Edit on GitHub

sqlglot.parser

   1from __future__ import annotations
   2
   3import logging
   4import typing as t
   5from collections import defaultdict
   6
   7from sqlglot import exp
   8from sqlglot.errors import ErrorLevel, ParseError, concat_messages, merge_errors
   9from sqlglot.helper import apply_index_offset, ensure_list, seq_get
  10from sqlglot.time import format_time
  11from sqlglot.tokens import Token, Tokenizer, TokenType
  12from sqlglot.trie import TrieResult, in_trie, new_trie
  13
  14if t.TYPE_CHECKING:
  15    from sqlglot._typing import E, Lit
  16    from sqlglot.dialects.dialect import Dialect, DialectType
  17
  18logger = logging.getLogger("sqlglot")
  19
  20
  21def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  22    if len(args) == 1 and args[0].is_star:
  23        return exp.StarMap(this=args[0])
  24
  25    keys = []
  26    values = []
  27    for i in range(0, len(args), 2):
  28        keys.append(args[i])
  29        values.append(args[i + 1])
  30
  31    return exp.VarMap(
  32        keys=exp.Array(expressions=keys),
  33        values=exp.Array(expressions=values),
  34    )
  35
  36
  37def parse_like(args: t.List) -> exp.Escape | exp.Like:
  38    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  39    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  40
  41
  42def binary_range_parser(
  43    expr_type: t.Type[exp.Expression],
  44) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  45    return lambda self, this: self._parse_escape(
  46        self.expression(expr_type, this=this, expression=self._parse_bitwise())
  47    )
  48
  49
  50def parse_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  51    # Default argument order is base, expression
  52    this = seq_get(args, 0)
  53    expression = seq_get(args, 1)
  54
  55    if expression:
  56        if not dialect.LOG_BASE_FIRST:
  57            this, expression = expression, this
  58        return exp.Log(this=this, expression=expression)
  59
  60    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  61
  62
  63def parse_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
  64    def _parser(args: t.List, dialect: Dialect) -> E:
  65        expression = expr_type(
  66            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
  67        )
  68        if len(args) > 2 and expr_type is exp.JSONExtract:
  69            expression.set("expressions", args[2:])
  70
  71        return expression
  72
  73    return _parser
  74
  75
  76class _Parser(type):
  77    def __new__(cls, clsname, bases, attrs):
  78        klass = super().__new__(cls, clsname, bases, attrs)
  79
  80        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
  81        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
  82
  83        return klass
  84
  85
  86class Parser(metaclass=_Parser):
  87    """
  88    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  89
  90    Args:
  91        error_level: The desired error level.
  92            Default: ErrorLevel.IMMEDIATE
  93        error_message_context: Determines the amount of context to capture from a
  94            query string when displaying the error message (in number of characters).
  95            Default: 100
  96        max_errors: Maximum number of error messages to include in a raised ParseError.
  97            This is only relevant if error_level is ErrorLevel.RAISE.
  98            Default: 3
  99    """
 100
 101    FUNCTIONS: t.Dict[str, t.Callable] = {
 102        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 103        "CONCAT": lambda args, dialect: exp.Concat(
 104            expressions=args,
 105            safe=not dialect.STRICT_STRING_CONCAT,
 106            coalesce=dialect.CONCAT_COALESCE,
 107        ),
 108        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 109            expressions=args,
 110            safe=not dialect.STRICT_STRING_CONCAT,
 111            coalesce=dialect.CONCAT_COALESCE,
 112        ),
 113        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 114            this=seq_get(args, 0),
 115            to=exp.DataType(this=exp.DataType.Type.TEXT),
 116        ),
 117        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 118        "JSON_EXTRACT": parse_extract_json_with_path(exp.JSONExtract),
 119        "JSON_EXTRACT_SCALAR": parse_extract_json_with_path(exp.JSONExtractScalar),
 120        "JSON_EXTRACT_PATH_TEXT": parse_extract_json_with_path(exp.JSONExtractScalar),
 121        "LIKE": parse_like,
 122        "LOG": parse_logarithm,
 123        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 124            this=seq_get(args, 0),
 125            to=exp.DataType(this=exp.DataType.Type.TEXT),
 126        ),
 127        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 128            this=exp.Cast(
 129                this=seq_get(args, 0),
 130                to=exp.DataType(this=exp.DataType.Type.TEXT),
 131            ),
 132            start=exp.Literal.number(1),
 133            length=exp.Literal.number(10),
 134        ),
 135        "VAR_MAP": parse_var_map,
 136    }
 137
 138    NO_PAREN_FUNCTIONS = {
 139        TokenType.CURRENT_DATE: exp.CurrentDate,
 140        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 141        TokenType.CURRENT_TIME: exp.CurrentTime,
 142        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 143        TokenType.CURRENT_USER: exp.CurrentUser,
 144    }
 145
 146    STRUCT_TYPE_TOKENS = {
 147        TokenType.NESTED,
 148        TokenType.STRUCT,
 149    }
 150
 151    NESTED_TYPE_TOKENS = {
 152        TokenType.ARRAY,
 153        TokenType.LOWCARDINALITY,
 154        TokenType.MAP,
 155        TokenType.NULLABLE,
 156        *STRUCT_TYPE_TOKENS,
 157    }
 158
 159    ENUM_TYPE_TOKENS = {
 160        TokenType.ENUM,
 161        TokenType.ENUM8,
 162        TokenType.ENUM16,
 163    }
 164
 165    AGGREGATE_TYPE_TOKENS = {
 166        TokenType.AGGREGATEFUNCTION,
 167        TokenType.SIMPLEAGGREGATEFUNCTION,
 168    }
 169
 170    TYPE_TOKENS = {
 171        TokenType.BIT,
 172        TokenType.BOOLEAN,
 173        TokenType.TINYINT,
 174        TokenType.UTINYINT,
 175        TokenType.SMALLINT,
 176        TokenType.USMALLINT,
 177        TokenType.INT,
 178        TokenType.UINT,
 179        TokenType.BIGINT,
 180        TokenType.UBIGINT,
 181        TokenType.INT128,
 182        TokenType.UINT128,
 183        TokenType.INT256,
 184        TokenType.UINT256,
 185        TokenType.MEDIUMINT,
 186        TokenType.UMEDIUMINT,
 187        TokenType.FIXEDSTRING,
 188        TokenType.FLOAT,
 189        TokenType.DOUBLE,
 190        TokenType.CHAR,
 191        TokenType.NCHAR,
 192        TokenType.VARCHAR,
 193        TokenType.NVARCHAR,
 194        TokenType.BPCHAR,
 195        TokenType.TEXT,
 196        TokenType.MEDIUMTEXT,
 197        TokenType.LONGTEXT,
 198        TokenType.MEDIUMBLOB,
 199        TokenType.LONGBLOB,
 200        TokenType.BINARY,
 201        TokenType.VARBINARY,
 202        TokenType.JSON,
 203        TokenType.JSONB,
 204        TokenType.INTERVAL,
 205        TokenType.TINYBLOB,
 206        TokenType.TINYTEXT,
 207        TokenType.TIME,
 208        TokenType.TIMETZ,
 209        TokenType.TIMESTAMP,
 210        TokenType.TIMESTAMP_S,
 211        TokenType.TIMESTAMP_MS,
 212        TokenType.TIMESTAMP_NS,
 213        TokenType.TIMESTAMPTZ,
 214        TokenType.TIMESTAMPLTZ,
 215        TokenType.DATETIME,
 216        TokenType.DATETIME64,
 217        TokenType.DATE,
 218        TokenType.DATE32,
 219        TokenType.INT4RANGE,
 220        TokenType.INT4MULTIRANGE,
 221        TokenType.INT8RANGE,
 222        TokenType.INT8MULTIRANGE,
 223        TokenType.NUMRANGE,
 224        TokenType.NUMMULTIRANGE,
 225        TokenType.TSRANGE,
 226        TokenType.TSMULTIRANGE,
 227        TokenType.TSTZRANGE,
 228        TokenType.TSTZMULTIRANGE,
 229        TokenType.DATERANGE,
 230        TokenType.DATEMULTIRANGE,
 231        TokenType.DECIMAL,
 232        TokenType.UDECIMAL,
 233        TokenType.BIGDECIMAL,
 234        TokenType.UUID,
 235        TokenType.GEOGRAPHY,
 236        TokenType.GEOMETRY,
 237        TokenType.HLLSKETCH,
 238        TokenType.HSTORE,
 239        TokenType.PSEUDO_TYPE,
 240        TokenType.SUPER,
 241        TokenType.SERIAL,
 242        TokenType.SMALLSERIAL,
 243        TokenType.BIGSERIAL,
 244        TokenType.XML,
 245        TokenType.YEAR,
 246        TokenType.UNIQUEIDENTIFIER,
 247        TokenType.USERDEFINED,
 248        TokenType.MONEY,
 249        TokenType.SMALLMONEY,
 250        TokenType.ROWVERSION,
 251        TokenType.IMAGE,
 252        TokenType.VARIANT,
 253        TokenType.OBJECT,
 254        TokenType.OBJECT_IDENTIFIER,
 255        TokenType.INET,
 256        TokenType.IPADDRESS,
 257        TokenType.IPPREFIX,
 258        TokenType.IPV4,
 259        TokenType.IPV6,
 260        TokenType.UNKNOWN,
 261        TokenType.NULL,
 262        *ENUM_TYPE_TOKENS,
 263        *NESTED_TYPE_TOKENS,
 264        *AGGREGATE_TYPE_TOKENS,
 265    }
 266
 267    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 268        TokenType.BIGINT: TokenType.UBIGINT,
 269        TokenType.INT: TokenType.UINT,
 270        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 271        TokenType.SMALLINT: TokenType.USMALLINT,
 272        TokenType.TINYINT: TokenType.UTINYINT,
 273        TokenType.DECIMAL: TokenType.UDECIMAL,
 274    }
 275
 276    SUBQUERY_PREDICATES = {
 277        TokenType.ANY: exp.Any,
 278        TokenType.ALL: exp.All,
 279        TokenType.EXISTS: exp.Exists,
 280        TokenType.SOME: exp.Any,
 281    }
 282
 283    RESERVED_TOKENS = {
 284        *Tokenizer.SINGLE_TOKENS.values(),
 285        TokenType.SELECT,
 286    }
 287
 288    DB_CREATABLES = {
 289        TokenType.DATABASE,
 290        TokenType.SCHEMA,
 291        TokenType.TABLE,
 292        TokenType.VIEW,
 293        TokenType.MODEL,
 294        TokenType.DICTIONARY,
 295    }
 296
 297    CREATABLES = {
 298        TokenType.COLUMN,
 299        TokenType.CONSTRAINT,
 300        TokenType.FUNCTION,
 301        TokenType.INDEX,
 302        TokenType.PROCEDURE,
 303        TokenType.FOREIGN_KEY,
 304        *DB_CREATABLES,
 305    }
 306
 307    # Tokens that can represent identifiers
 308    ID_VAR_TOKENS = {
 309        TokenType.VAR,
 310        TokenType.ANTI,
 311        TokenType.APPLY,
 312        TokenType.ASC,
 313        TokenType.AUTO_INCREMENT,
 314        TokenType.BEGIN,
 315        TokenType.BPCHAR,
 316        TokenType.CACHE,
 317        TokenType.CASE,
 318        TokenType.COLLATE,
 319        TokenType.COMMAND,
 320        TokenType.COMMENT,
 321        TokenType.COMMIT,
 322        TokenType.CONSTRAINT,
 323        TokenType.DEFAULT,
 324        TokenType.DELETE,
 325        TokenType.DESC,
 326        TokenType.DESCRIBE,
 327        TokenType.DICTIONARY,
 328        TokenType.DIV,
 329        TokenType.END,
 330        TokenType.EXECUTE,
 331        TokenType.ESCAPE,
 332        TokenType.FALSE,
 333        TokenType.FIRST,
 334        TokenType.FILTER,
 335        TokenType.FINAL,
 336        TokenType.FORMAT,
 337        TokenType.FULL,
 338        TokenType.IS,
 339        TokenType.ISNULL,
 340        TokenType.INTERVAL,
 341        TokenType.KEEP,
 342        TokenType.KILL,
 343        TokenType.LEFT,
 344        TokenType.LOAD,
 345        TokenType.MERGE,
 346        TokenType.NATURAL,
 347        TokenType.NEXT,
 348        TokenType.OFFSET,
 349        TokenType.OPERATOR,
 350        TokenType.ORDINALITY,
 351        TokenType.OVERLAPS,
 352        TokenType.OVERWRITE,
 353        TokenType.PARTITION,
 354        TokenType.PERCENT,
 355        TokenType.PIVOT,
 356        TokenType.PRAGMA,
 357        TokenType.RANGE,
 358        TokenType.RECURSIVE,
 359        TokenType.REFERENCES,
 360        TokenType.REFRESH,
 361        TokenType.REPLACE,
 362        TokenType.RIGHT,
 363        TokenType.ROW,
 364        TokenType.ROWS,
 365        TokenType.SEMI,
 366        TokenType.SET,
 367        TokenType.SETTINGS,
 368        TokenType.SHOW,
 369        TokenType.TEMPORARY,
 370        TokenType.TOP,
 371        TokenType.TRUE,
 372        TokenType.UNIQUE,
 373        TokenType.UNPIVOT,
 374        TokenType.UPDATE,
 375        TokenType.USE,
 376        TokenType.VOLATILE,
 377        TokenType.WINDOW,
 378        *CREATABLES,
 379        *SUBQUERY_PREDICATES,
 380        *TYPE_TOKENS,
 381        *NO_PAREN_FUNCTIONS,
 382    }
 383
 384    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 385
 386    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 387        TokenType.ANTI,
 388        TokenType.APPLY,
 389        TokenType.ASOF,
 390        TokenType.FULL,
 391        TokenType.LEFT,
 392        TokenType.LOCK,
 393        TokenType.NATURAL,
 394        TokenType.OFFSET,
 395        TokenType.RIGHT,
 396        TokenType.SEMI,
 397        TokenType.WINDOW,
 398    }
 399
 400    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 401
 402    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 403
 404    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 405
 406    FUNC_TOKENS = {
 407        TokenType.COLLATE,
 408        TokenType.COMMAND,
 409        TokenType.CURRENT_DATE,
 410        TokenType.CURRENT_DATETIME,
 411        TokenType.CURRENT_TIMESTAMP,
 412        TokenType.CURRENT_TIME,
 413        TokenType.CURRENT_USER,
 414        TokenType.FILTER,
 415        TokenType.FIRST,
 416        TokenType.FORMAT,
 417        TokenType.GLOB,
 418        TokenType.IDENTIFIER,
 419        TokenType.INDEX,
 420        TokenType.ISNULL,
 421        TokenType.ILIKE,
 422        TokenType.INSERT,
 423        TokenType.LIKE,
 424        TokenType.MERGE,
 425        TokenType.OFFSET,
 426        TokenType.PRIMARY_KEY,
 427        TokenType.RANGE,
 428        TokenType.REPLACE,
 429        TokenType.RLIKE,
 430        TokenType.ROW,
 431        TokenType.UNNEST,
 432        TokenType.VAR,
 433        TokenType.LEFT,
 434        TokenType.RIGHT,
 435        TokenType.DATE,
 436        TokenType.DATETIME,
 437        TokenType.TABLE,
 438        TokenType.TIMESTAMP,
 439        TokenType.TIMESTAMPTZ,
 440        TokenType.WINDOW,
 441        TokenType.XOR,
 442        *TYPE_TOKENS,
 443        *SUBQUERY_PREDICATES,
 444    }
 445
 446    CONJUNCTION = {
 447        TokenType.AND: exp.And,
 448        TokenType.OR: exp.Or,
 449    }
 450
 451    EQUALITY = {
 452        TokenType.COLON_EQ: exp.PropertyEQ,
 453        TokenType.EQ: exp.EQ,
 454        TokenType.NEQ: exp.NEQ,
 455        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 456    }
 457
 458    COMPARISON = {
 459        TokenType.GT: exp.GT,
 460        TokenType.GTE: exp.GTE,
 461        TokenType.LT: exp.LT,
 462        TokenType.LTE: exp.LTE,
 463    }
 464
 465    BITWISE = {
 466        TokenType.AMP: exp.BitwiseAnd,
 467        TokenType.CARET: exp.BitwiseXor,
 468        TokenType.PIPE: exp.BitwiseOr,
 469    }
 470
 471    TERM = {
 472        TokenType.DASH: exp.Sub,
 473        TokenType.PLUS: exp.Add,
 474        TokenType.MOD: exp.Mod,
 475        TokenType.COLLATE: exp.Collate,
 476    }
 477
 478    FACTOR = {
 479        TokenType.DIV: exp.IntDiv,
 480        TokenType.LR_ARROW: exp.Distance,
 481        TokenType.SLASH: exp.Div,
 482        TokenType.STAR: exp.Mul,
 483    }
 484
 485    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 486
 487    TIMES = {
 488        TokenType.TIME,
 489        TokenType.TIMETZ,
 490    }
 491
 492    TIMESTAMPS = {
 493        TokenType.TIMESTAMP,
 494        TokenType.TIMESTAMPTZ,
 495        TokenType.TIMESTAMPLTZ,
 496        *TIMES,
 497    }
 498
 499    SET_OPERATIONS = {
 500        TokenType.UNION,
 501        TokenType.INTERSECT,
 502        TokenType.EXCEPT,
 503    }
 504
 505    JOIN_METHODS = {
 506        TokenType.NATURAL,
 507        TokenType.ASOF,
 508    }
 509
 510    JOIN_SIDES = {
 511        TokenType.LEFT,
 512        TokenType.RIGHT,
 513        TokenType.FULL,
 514    }
 515
 516    JOIN_KINDS = {
 517        TokenType.INNER,
 518        TokenType.OUTER,
 519        TokenType.CROSS,
 520        TokenType.SEMI,
 521        TokenType.ANTI,
 522    }
 523
 524    JOIN_HINTS: t.Set[str] = set()
 525
 526    LAMBDAS = {
 527        TokenType.ARROW: lambda self, expressions: self.expression(
 528            exp.Lambda,
 529            this=self._replace_lambda(
 530                self._parse_conjunction(),
 531                {node.name for node in expressions},
 532            ),
 533            expressions=expressions,
 534        ),
 535        TokenType.FARROW: lambda self, expressions: self.expression(
 536            exp.Kwarg,
 537            this=exp.var(expressions[0].name),
 538            expression=self._parse_conjunction(),
 539        ),
 540    }
 541
 542    COLUMN_OPERATORS = {
 543        TokenType.DOT: None,
 544        TokenType.DCOLON: lambda self, this, to: self.expression(
 545            exp.Cast if self.STRICT_CAST else exp.TryCast,
 546            this=this,
 547            to=to,
 548        ),
 549        TokenType.ARROW: lambda self, this, path: self.expression(
 550            exp.JSONExtract,
 551            this=this,
 552            expression=self.dialect.to_json_path(path),
 553        ),
 554        TokenType.DARROW: lambda self, this, path: self.expression(
 555            exp.JSONExtractScalar,
 556            this=this,
 557            expression=self.dialect.to_json_path(path),
 558        ),
 559        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 560            exp.JSONBExtract,
 561            this=this,
 562            expression=path,
 563        ),
 564        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 565            exp.JSONBExtractScalar,
 566            this=this,
 567            expression=path,
 568        ),
 569        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 570            exp.JSONBContains,
 571            this=this,
 572            expression=key,
 573        ),
 574    }
 575
 576    EXPRESSION_PARSERS = {
 577        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 578        exp.Column: lambda self: self._parse_column(),
 579        exp.Condition: lambda self: self._parse_conjunction(),
 580        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 581        exp.Expression: lambda self: self._parse_statement(),
 582        exp.From: lambda self: self._parse_from(),
 583        exp.Group: lambda self: self._parse_group(),
 584        exp.Having: lambda self: self._parse_having(),
 585        exp.Identifier: lambda self: self._parse_id_var(),
 586        exp.Join: lambda self: self._parse_join(),
 587        exp.Lambda: lambda self: self._parse_lambda(),
 588        exp.Lateral: lambda self: self._parse_lateral(),
 589        exp.Limit: lambda self: self._parse_limit(),
 590        exp.Offset: lambda self: self._parse_offset(),
 591        exp.Order: lambda self: self._parse_order(),
 592        exp.Ordered: lambda self: self._parse_ordered(),
 593        exp.Properties: lambda self: self._parse_properties(),
 594        exp.Qualify: lambda self: self._parse_qualify(),
 595        exp.Returning: lambda self: self._parse_returning(),
 596        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 597        exp.Table: lambda self: self._parse_table_parts(),
 598        exp.TableAlias: lambda self: self._parse_table_alias(),
 599        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 600        exp.Where: lambda self: self._parse_where(),
 601        exp.Window: lambda self: self._parse_named_window(),
 602        exp.With: lambda self: self._parse_with(),
 603        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 604    }
 605
 606    STATEMENT_PARSERS = {
 607        TokenType.ALTER: lambda self: self._parse_alter(),
 608        TokenType.BEGIN: lambda self: self._parse_transaction(),
 609        TokenType.CACHE: lambda self: self._parse_cache(),
 610        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 611        TokenType.COMMENT: lambda self: self._parse_comment(),
 612        TokenType.CREATE: lambda self: self._parse_create(),
 613        TokenType.DELETE: lambda self: self._parse_delete(),
 614        TokenType.DESC: lambda self: self._parse_describe(),
 615        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 616        TokenType.DROP: lambda self: self._parse_drop(),
 617        TokenType.INSERT: lambda self: self._parse_insert(),
 618        TokenType.KILL: lambda self: self._parse_kill(),
 619        TokenType.LOAD: lambda self: self._parse_load(),
 620        TokenType.MERGE: lambda self: self._parse_merge(),
 621        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 622        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 623        TokenType.REFRESH: lambda self: self._parse_refresh(),
 624        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 625        TokenType.SET: lambda self: self._parse_set(),
 626        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 627        TokenType.UPDATE: lambda self: self._parse_update(),
 628        TokenType.USE: lambda self: self.expression(
 629            exp.Use,
 630            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
 631            and exp.var(self._prev.text),
 632            this=self._parse_table(schema=False),
 633        ),
 634    }
 635
 636    UNARY_PARSERS = {
 637        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 638        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 639        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 640        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 641    }
 642
 643    PRIMARY_PARSERS = {
 644        TokenType.STRING: lambda self, token: self.expression(
 645            exp.Literal, this=token.text, is_string=True
 646        ),
 647        TokenType.NUMBER: lambda self, token: self.expression(
 648            exp.Literal, this=token.text, is_string=False
 649        ),
 650        TokenType.STAR: lambda self, _: self.expression(
 651            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 652        ),
 653        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 654        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 655        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 656        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 657        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 658        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 659        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 660        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 661            exp.National, this=token.text
 662        ),
 663        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 664        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 665            exp.RawString, this=token.text
 666        ),
 667        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 668            exp.UnicodeString,
 669            this=token.text,
 670            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 671        ),
 672        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 673    }
 674
 675    PLACEHOLDER_PARSERS = {
 676        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 677        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 678        TokenType.COLON: lambda self: (
 679            self.expression(exp.Placeholder, this=self._prev.text)
 680            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 681            else None
 682        ),
 683    }
 684
 685    RANGE_PARSERS = {
 686        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 687        TokenType.GLOB: binary_range_parser(exp.Glob),
 688        TokenType.ILIKE: binary_range_parser(exp.ILike),
 689        TokenType.IN: lambda self, this: self._parse_in(this),
 690        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 691        TokenType.IS: lambda self, this: self._parse_is(this),
 692        TokenType.LIKE: binary_range_parser(exp.Like),
 693        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 694        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 695        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 696        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 697    }
 698
 699    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 700        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 701        "AUTO": lambda self: self._parse_auto_property(),
 702        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 703        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 704        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 705        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 706        "CHECKSUM": lambda self: self._parse_checksum(),
 707        "CLUSTER BY": lambda self: self._parse_cluster(),
 708        "CLUSTERED": lambda self: self._parse_clustered_by(),
 709        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 710            exp.CollateProperty, **kwargs
 711        ),
 712        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 713        "CONTAINS": lambda self: self._parse_contains_property(),
 714        "COPY": lambda self: self._parse_copy_property(),
 715        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 716        "DEFINER": lambda self: self._parse_definer(),
 717        "DETERMINISTIC": lambda self: self.expression(
 718            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 719        ),
 720        "DISTKEY": lambda self: self._parse_distkey(),
 721        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 722        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 723        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 724        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 725        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 726        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 727        "FREESPACE": lambda self: self._parse_freespace(),
 728        "HEAP": lambda self: self.expression(exp.HeapProperty),
 729        "IMMUTABLE": lambda self: self.expression(
 730            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 731        ),
 732        "INHERITS": lambda self: self.expression(
 733            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 734        ),
 735        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 736        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 737        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 738        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 739        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 740        "LIKE": lambda self: self._parse_create_like(),
 741        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 742        "LOCK": lambda self: self._parse_locking(),
 743        "LOCKING": lambda self: self._parse_locking(),
 744        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 745        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 746        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 747        "MODIFIES": lambda self: self._parse_modifies_property(),
 748        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 749        "NO": lambda self: self._parse_no_property(),
 750        "ON": lambda self: self._parse_on_property(),
 751        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 752        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 753        "PARTITION": lambda self: self._parse_partitioned_of(),
 754        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 755        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 756        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 757        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 758        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 759        "READS": lambda self: self._parse_reads_property(),
 760        "REMOTE": lambda self: self._parse_remote_with_connection(),
 761        "RETURNS": lambda self: self._parse_returns(),
 762        "ROW": lambda self: self._parse_row(),
 763        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 764        "SAMPLE": lambda self: self.expression(
 765            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 766        ),
 767        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 768        "SETTINGS": lambda self: self.expression(
 769            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 770        ),
 771        "SORTKEY": lambda self: self._parse_sortkey(),
 772        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 773        "STABLE": lambda self: self.expression(
 774            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 775        ),
 776        "STORED": lambda self: self._parse_stored(),
 777        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 778        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
 779        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 780        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 781        "TO": lambda self: self._parse_to_table(),
 782        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 783        "TRANSFORM": lambda self: self.expression(
 784            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 785        ),
 786        "TTL": lambda self: self._parse_ttl(),
 787        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 788        "VOLATILE": lambda self: self._parse_volatile_property(),
 789        "WITH": lambda self: self._parse_with_property(),
 790    }
 791
 792    CONSTRAINT_PARSERS = {
 793        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 794        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 795        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 796        "CHARACTER SET": lambda self: self.expression(
 797            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 798        ),
 799        "CHECK": lambda self: self.expression(
 800            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
 801        ),
 802        "COLLATE": lambda self: self.expression(
 803            exp.CollateColumnConstraint, this=self._parse_var()
 804        ),
 805        "COMMENT": lambda self: self.expression(
 806            exp.CommentColumnConstraint, this=self._parse_string()
 807        ),
 808        "COMPRESS": lambda self: self._parse_compress(),
 809        "CLUSTERED": lambda self: self.expression(
 810            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 811        ),
 812        "NONCLUSTERED": lambda self: self.expression(
 813            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 814        ),
 815        "DEFAULT": lambda self: self.expression(
 816            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 817        ),
 818        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 819        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 820        "FORMAT": lambda self: self.expression(
 821            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 822        ),
 823        "GENERATED": lambda self: self._parse_generated_as_identity(),
 824        "IDENTITY": lambda self: self._parse_auto_increment(),
 825        "INLINE": lambda self: self._parse_inline(),
 826        "LIKE": lambda self: self._parse_create_like(),
 827        "NOT": lambda self: self._parse_not_constraint(),
 828        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 829        "ON": lambda self: (
 830            self._match(TokenType.UPDATE)
 831            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 832        )
 833        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 834        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 835        "PERIOD": lambda self: self._parse_period_for_system_time(),
 836        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 837        "REFERENCES": lambda self: self._parse_references(match=False),
 838        "TITLE": lambda self: self.expression(
 839            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 840        ),
 841        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 842        "UNIQUE": lambda self: self._parse_unique(),
 843        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 844        "WITH": lambda self: self.expression(
 845            exp.Properties, expressions=self._parse_wrapped_csv(self._parse_property)
 846        ),
 847    }
 848
 849    ALTER_PARSERS = {
 850        "ADD": lambda self: self._parse_alter_table_add(),
 851        "ALTER": lambda self: self._parse_alter_table_alter(),
 852        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 853        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 854        "DROP": lambda self: self._parse_alter_table_drop(),
 855        "RENAME": lambda self: self._parse_alter_table_rename(),
 856    }
 857
 858    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE", "PERIOD"}
 859
 860    NO_PAREN_FUNCTION_PARSERS = {
 861        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 862        "CASE": lambda self: self._parse_case(),
 863        "IF": lambda self: self._parse_if(),
 864        "NEXT": lambda self: self._parse_next_value_for(),
 865    }
 866
 867    INVALID_FUNC_NAME_TOKENS = {
 868        TokenType.IDENTIFIER,
 869        TokenType.STRING,
 870    }
 871
 872    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 873
 874    FUNCTION_PARSERS = {
 875        "ANY_VALUE": lambda self: self._parse_any_value(),
 876        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 877        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 878        "DECODE": lambda self: self._parse_decode(),
 879        "EXTRACT": lambda self: self._parse_extract(),
 880        "JSON_OBJECT": lambda self: self._parse_json_object(),
 881        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 882        "JSON_TABLE": lambda self: self._parse_json_table(),
 883        "MATCH": lambda self: self._parse_match_against(),
 884        "OPENJSON": lambda self: self._parse_open_json(),
 885        "POSITION": lambda self: self._parse_position(),
 886        "PREDICT": lambda self: self._parse_predict(),
 887        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 888        "STRING_AGG": lambda self: self._parse_string_agg(),
 889        "SUBSTRING": lambda self: self._parse_substring(),
 890        "TRIM": lambda self: self._parse_trim(),
 891        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 892        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 893    }
 894
 895    QUERY_MODIFIER_PARSERS = {
 896        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 897        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 898        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 899        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 900        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 901        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 902        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 903        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 904        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 905        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 906        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 907        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 908        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 909        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 910        TokenType.CLUSTER_BY: lambda self: (
 911            "cluster",
 912            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 913        ),
 914        TokenType.DISTRIBUTE_BY: lambda self: (
 915            "distribute",
 916            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 917        ),
 918        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 919        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 920        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 921    }
 922
 923    SET_PARSERS = {
 924        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 925        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 926        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 927        "TRANSACTION": lambda self: self._parse_set_transaction(),
 928    }
 929
 930    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 931
 932    TYPE_LITERAL_PARSERS = {
 933        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 934    }
 935
 936    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
 937
 938    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 939
 940    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 941
 942    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 943    TRANSACTION_CHARACTERISTICS = {
 944        "ISOLATION LEVEL REPEATABLE READ",
 945        "ISOLATION LEVEL READ COMMITTED",
 946        "ISOLATION LEVEL READ UNCOMMITTED",
 947        "ISOLATION LEVEL SERIALIZABLE",
 948        "READ WRITE",
 949        "READ ONLY",
 950    }
 951
 952    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
 953
 954    CLONE_KEYWORDS = {"CLONE", "COPY"}
 955    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
 956
 957    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS"}
 958    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
 959
 960    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
 961
 962    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
 963    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
 964    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
 965
 966    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
 967
 968    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
 969
 970    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
 971
 972    DISTINCT_TOKENS = {TokenType.DISTINCT}
 973
 974    NULL_TOKENS = {TokenType.NULL}
 975
 976    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
 977
 978    STRICT_CAST = True
 979
 980    PREFIXED_PIVOT_COLUMNS = False
 981    IDENTIFY_PIVOT_STRINGS = False
 982
 983    LOG_DEFAULTS_TO_LN = False
 984
 985    # Whether or not ADD is present for each column added by ALTER TABLE
 986    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
 987
 988    # Whether or not the table sample clause expects CSV syntax
 989    TABLESAMPLE_CSV = False
 990
 991    # Whether or not the SET command needs a delimiter (e.g. "=") for assignments
 992    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
 993
 994    # Whether the TRIM function expects the characters to trim as its first argument
 995    TRIM_PATTERN_FIRST = False
 996
 997    # Whether or not string aliases are supported `SELECT COUNT(*) 'count'`
 998    STRING_ALIASES = False
 999
1000    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1001    MODIFIERS_ATTACHED_TO_UNION = True
1002    UNION_MODIFIERS = {"order", "limit", "offset"}
1003
1004    # parses no parenthesis if statements as commands
1005    NO_PAREN_IF_COMMANDS = True
1006
1007    __slots__ = (
1008        "error_level",
1009        "error_message_context",
1010        "max_errors",
1011        "dialect",
1012        "sql",
1013        "errors",
1014        "_tokens",
1015        "_index",
1016        "_curr",
1017        "_next",
1018        "_prev",
1019        "_prev_comments",
1020    )
1021
1022    # Autofilled
1023    SHOW_TRIE: t.Dict = {}
1024    SET_TRIE: t.Dict = {}
1025
1026    def __init__(
1027        self,
1028        error_level: t.Optional[ErrorLevel] = None,
1029        error_message_context: int = 100,
1030        max_errors: int = 3,
1031        dialect: DialectType = None,
1032    ):
1033        from sqlglot.dialects import Dialect
1034
1035        self.error_level = error_level or ErrorLevel.IMMEDIATE
1036        self.error_message_context = error_message_context
1037        self.max_errors = max_errors
1038        self.dialect = Dialect.get_or_raise(dialect)
1039        self.reset()
1040
1041    def reset(self):
1042        self.sql = ""
1043        self.errors = []
1044        self._tokens = []
1045        self._index = 0
1046        self._curr = None
1047        self._next = None
1048        self._prev = None
1049        self._prev_comments = None
1050
1051    def parse(
1052        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1053    ) -> t.List[t.Optional[exp.Expression]]:
1054        """
1055        Parses a list of tokens and returns a list of syntax trees, one tree
1056        per parsed SQL statement.
1057
1058        Args:
1059            raw_tokens: The list of tokens.
1060            sql: The original SQL string, used to produce helpful debug messages.
1061
1062        Returns:
1063            The list of the produced syntax trees.
1064        """
1065        return self._parse(
1066            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1067        )
1068
1069    def parse_into(
1070        self,
1071        expression_types: exp.IntoType,
1072        raw_tokens: t.List[Token],
1073        sql: t.Optional[str] = None,
1074    ) -> t.List[t.Optional[exp.Expression]]:
1075        """
1076        Parses a list of tokens into a given Expression type. If a collection of Expression
1077        types is given instead, this method will try to parse the token list into each one
1078        of them, stopping at the first for which the parsing succeeds.
1079
1080        Args:
1081            expression_types: The expression type(s) to try and parse the token list into.
1082            raw_tokens: The list of tokens.
1083            sql: The original SQL string, used to produce helpful debug messages.
1084
1085        Returns:
1086            The target Expression.
1087        """
1088        errors = []
1089        for expression_type in ensure_list(expression_types):
1090            parser = self.EXPRESSION_PARSERS.get(expression_type)
1091            if not parser:
1092                raise TypeError(f"No parser registered for {expression_type}")
1093
1094            try:
1095                return self._parse(parser, raw_tokens, sql)
1096            except ParseError as e:
1097                e.errors[0]["into_expression"] = expression_type
1098                errors.append(e)
1099
1100        raise ParseError(
1101            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1102            errors=merge_errors(errors),
1103        ) from errors[-1]
1104
1105    def _parse(
1106        self,
1107        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1108        raw_tokens: t.List[Token],
1109        sql: t.Optional[str] = None,
1110    ) -> t.List[t.Optional[exp.Expression]]:
1111        self.reset()
1112        self.sql = sql or ""
1113
1114        total = len(raw_tokens)
1115        chunks: t.List[t.List[Token]] = [[]]
1116
1117        for i, token in enumerate(raw_tokens):
1118            if token.token_type == TokenType.SEMICOLON:
1119                if i < total - 1:
1120                    chunks.append([])
1121            else:
1122                chunks[-1].append(token)
1123
1124        expressions = []
1125
1126        for tokens in chunks:
1127            self._index = -1
1128            self._tokens = tokens
1129            self._advance()
1130
1131            expressions.append(parse_method(self))
1132
1133            if self._index < len(self._tokens):
1134                self.raise_error("Invalid expression / Unexpected token")
1135
1136            self.check_errors()
1137
1138        return expressions
1139
1140    def check_errors(self) -> None:
1141        """Logs or raises any found errors, depending on the chosen error level setting."""
1142        if self.error_level == ErrorLevel.WARN:
1143            for error in self.errors:
1144                logger.error(str(error))
1145        elif self.error_level == ErrorLevel.RAISE and self.errors:
1146            raise ParseError(
1147                concat_messages(self.errors, self.max_errors),
1148                errors=merge_errors(self.errors),
1149            )
1150
1151    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1152        """
1153        Appends an error in the list of recorded errors or raises it, depending on the chosen
1154        error level setting.
1155        """
1156        token = token or self._curr or self._prev or Token.string("")
1157        start = token.start
1158        end = token.end + 1
1159        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1160        highlight = self.sql[start:end]
1161        end_context = self.sql[end : end + self.error_message_context]
1162
1163        error = ParseError.new(
1164            f"{message}. Line {token.line}, Col: {token.col}.\n"
1165            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1166            description=message,
1167            line=token.line,
1168            col=token.col,
1169            start_context=start_context,
1170            highlight=highlight,
1171            end_context=end_context,
1172        )
1173
1174        if self.error_level == ErrorLevel.IMMEDIATE:
1175            raise error
1176
1177        self.errors.append(error)
1178
1179    def expression(
1180        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1181    ) -> E:
1182        """
1183        Creates a new, validated Expression.
1184
1185        Args:
1186            exp_class: The expression class to instantiate.
1187            comments: An optional list of comments to attach to the expression.
1188            kwargs: The arguments to set for the expression along with their respective values.
1189
1190        Returns:
1191            The target expression.
1192        """
1193        instance = exp_class(**kwargs)
1194        instance.add_comments(comments) if comments else self._add_comments(instance)
1195        return self.validate_expression(instance)
1196
1197    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1198        if expression and self._prev_comments:
1199            expression.add_comments(self._prev_comments)
1200            self._prev_comments = None
1201
1202    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1203        """
1204        Validates an Expression, making sure that all its mandatory arguments are set.
1205
1206        Args:
1207            expression: The expression to validate.
1208            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1209
1210        Returns:
1211            The validated expression.
1212        """
1213        if self.error_level != ErrorLevel.IGNORE:
1214            for error_message in expression.error_messages(args):
1215                self.raise_error(error_message)
1216
1217        return expression
1218
1219    def _find_sql(self, start: Token, end: Token) -> str:
1220        return self.sql[start.start : end.end + 1]
1221
1222    def _is_connected(self) -> bool:
1223        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1224
1225    def _advance(self, times: int = 1) -> None:
1226        self._index += times
1227        self._curr = seq_get(self._tokens, self._index)
1228        self._next = seq_get(self._tokens, self._index + 1)
1229
1230        if self._index > 0:
1231            self._prev = self._tokens[self._index - 1]
1232            self._prev_comments = self._prev.comments
1233        else:
1234            self._prev = None
1235            self._prev_comments = None
1236
1237    def _retreat(self, index: int) -> None:
1238        if index != self._index:
1239            self._advance(index - self._index)
1240
1241    def _warn_unsupported(self) -> None:
1242        if len(self._tokens) <= 1:
1243            return
1244
1245        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1246        # interested in emitting a warning for the one being currently processed.
1247        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1248
1249        logger.warning(
1250            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1251        )
1252
1253    def _parse_command(self) -> exp.Command:
1254        self._warn_unsupported()
1255        return self.expression(
1256            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1257        )
1258
1259    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1260        start = self._prev
1261        exists = self._parse_exists() if allow_exists else None
1262
1263        self._match(TokenType.ON)
1264
1265        kind = self._match_set(self.CREATABLES) and self._prev
1266        if not kind:
1267            return self._parse_as_command(start)
1268
1269        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1270            this = self._parse_user_defined_function(kind=kind.token_type)
1271        elif kind.token_type == TokenType.TABLE:
1272            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1273        elif kind.token_type == TokenType.COLUMN:
1274            this = self._parse_column()
1275        else:
1276            this = self._parse_id_var()
1277
1278        self._match(TokenType.IS)
1279
1280        return self.expression(
1281            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
1282        )
1283
1284    def _parse_to_table(
1285        self,
1286    ) -> exp.ToTableProperty:
1287        table = self._parse_table_parts(schema=True)
1288        return self.expression(exp.ToTableProperty, this=table)
1289
1290    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1291    def _parse_ttl(self) -> exp.Expression:
1292        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1293            this = self._parse_bitwise()
1294
1295            if self._match_text_seq("DELETE"):
1296                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1297            if self._match_text_seq("RECOMPRESS"):
1298                return self.expression(
1299                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1300                )
1301            if self._match_text_seq("TO", "DISK"):
1302                return self.expression(
1303                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1304                )
1305            if self._match_text_seq("TO", "VOLUME"):
1306                return self.expression(
1307                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1308                )
1309
1310            return this
1311
1312        expressions = self._parse_csv(_parse_ttl_action)
1313        where = self._parse_where()
1314        group = self._parse_group()
1315
1316        aggregates = None
1317        if group and self._match(TokenType.SET):
1318            aggregates = self._parse_csv(self._parse_set_item)
1319
1320        return self.expression(
1321            exp.MergeTreeTTL,
1322            expressions=expressions,
1323            where=where,
1324            group=group,
1325            aggregates=aggregates,
1326        )
1327
1328    def _parse_statement(self) -> t.Optional[exp.Expression]:
1329        if self._curr is None:
1330            return None
1331
1332        if self._match_set(self.STATEMENT_PARSERS):
1333            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1334
1335        if self._match_set(Tokenizer.COMMANDS):
1336            return self._parse_command()
1337
1338        expression = self._parse_expression()
1339        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1340        return self._parse_query_modifiers(expression)
1341
1342    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1343        start = self._prev
1344        temporary = self._match(TokenType.TEMPORARY)
1345        materialized = self._match_text_seq("MATERIALIZED")
1346
1347        kind = self._match_set(self.CREATABLES) and self._prev.text
1348        if not kind:
1349            return self._parse_as_command(start)
1350
1351        return self.expression(
1352            exp.Drop,
1353            comments=start.comments,
1354            exists=exists or self._parse_exists(),
1355            this=self._parse_table(
1356                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1357            ),
1358            kind=kind,
1359            temporary=temporary,
1360            materialized=materialized,
1361            cascade=self._match_text_seq("CASCADE"),
1362            constraints=self._match_text_seq("CONSTRAINTS"),
1363            purge=self._match_text_seq("PURGE"),
1364        )
1365
1366    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1367        return (
1368            self._match_text_seq("IF")
1369            and (not not_ or self._match(TokenType.NOT))
1370            and self._match(TokenType.EXISTS)
1371        )
1372
1373    def _parse_create(self) -> exp.Create | exp.Command:
1374        # Note: this can't be None because we've matched a statement parser
1375        start = self._prev
1376        comments = self._prev_comments
1377
1378        replace = (
1379            start.token_type == TokenType.REPLACE
1380            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1381            or self._match_pair(TokenType.OR, TokenType.ALTER)
1382        )
1383        unique = self._match(TokenType.UNIQUE)
1384
1385        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1386            self._advance()
1387
1388        properties = None
1389        create_token = self._match_set(self.CREATABLES) and self._prev
1390
1391        if not create_token:
1392            # exp.Properties.Location.POST_CREATE
1393            properties = self._parse_properties()
1394            create_token = self._match_set(self.CREATABLES) and self._prev
1395
1396            if not properties or not create_token:
1397                return self._parse_as_command(start)
1398
1399        exists = self._parse_exists(not_=True)
1400        this = None
1401        expression: t.Optional[exp.Expression] = None
1402        indexes = None
1403        no_schema_binding = None
1404        begin = None
1405        end = None
1406        clone = None
1407
1408        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1409            nonlocal properties
1410            if properties and temp_props:
1411                properties.expressions.extend(temp_props.expressions)
1412            elif temp_props:
1413                properties = temp_props
1414
1415        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1416            this = self._parse_user_defined_function(kind=create_token.token_type)
1417
1418            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1419            extend_props(self._parse_properties())
1420
1421            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1422
1423            if not expression:
1424                if self._match(TokenType.COMMAND):
1425                    expression = self._parse_as_command(self._prev)
1426                else:
1427                    begin = self._match(TokenType.BEGIN)
1428                    return_ = self._match_text_seq("RETURN")
1429
1430                    if self._match(TokenType.STRING, advance=False):
1431                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1432                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1433                        expression = self._parse_string()
1434                        extend_props(self._parse_properties())
1435                    else:
1436                        expression = self._parse_statement()
1437
1438                    end = self._match_text_seq("END")
1439
1440                    if return_:
1441                        expression = self.expression(exp.Return, this=expression)
1442        elif create_token.token_type == TokenType.INDEX:
1443            this = self._parse_index(index=self._parse_id_var())
1444        elif create_token.token_type in self.DB_CREATABLES:
1445            table_parts = self._parse_table_parts(
1446                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1447            )
1448
1449            # exp.Properties.Location.POST_NAME
1450            self._match(TokenType.COMMA)
1451            extend_props(self._parse_properties(before=True))
1452
1453            this = self._parse_schema(this=table_parts)
1454
1455            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1456            extend_props(self._parse_properties())
1457
1458            self._match(TokenType.ALIAS)
1459            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1460                # exp.Properties.Location.POST_ALIAS
1461                extend_props(self._parse_properties())
1462
1463            expression = self._parse_ddl_select()
1464
1465            if create_token.token_type == TokenType.TABLE:
1466                # exp.Properties.Location.POST_EXPRESSION
1467                extend_props(self._parse_properties())
1468
1469                indexes = []
1470                while True:
1471                    index = self._parse_index()
1472
1473                    # exp.Properties.Location.POST_INDEX
1474                    extend_props(self._parse_properties())
1475
1476                    if not index:
1477                        break
1478                    else:
1479                        self._match(TokenType.COMMA)
1480                        indexes.append(index)
1481            elif create_token.token_type == TokenType.VIEW:
1482                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1483                    no_schema_binding = True
1484
1485            shallow = self._match_text_seq("SHALLOW")
1486
1487            if self._match_texts(self.CLONE_KEYWORDS):
1488                copy = self._prev.text.lower() == "copy"
1489                clone = self.expression(
1490                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1491                )
1492
1493        if self._curr:
1494            return self._parse_as_command(start)
1495
1496        return self.expression(
1497            exp.Create,
1498            comments=comments,
1499            this=this,
1500            kind=create_token.text.upper(),
1501            replace=replace,
1502            unique=unique,
1503            expression=expression,
1504            exists=exists,
1505            properties=properties,
1506            indexes=indexes,
1507            no_schema_binding=no_schema_binding,
1508            begin=begin,
1509            end=end,
1510            clone=clone,
1511        )
1512
1513    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1514        # only used for teradata currently
1515        self._match(TokenType.COMMA)
1516
1517        kwargs = {
1518            "no": self._match_text_seq("NO"),
1519            "dual": self._match_text_seq("DUAL"),
1520            "before": self._match_text_seq("BEFORE"),
1521            "default": self._match_text_seq("DEFAULT"),
1522            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1523            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1524            "after": self._match_text_seq("AFTER"),
1525            "minimum": self._match_texts(("MIN", "MINIMUM")),
1526            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1527        }
1528
1529        if self._match_texts(self.PROPERTY_PARSERS):
1530            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1531            try:
1532                return parser(self, **{k: v for k, v in kwargs.items() if v})
1533            except TypeError:
1534                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1535
1536        return None
1537
1538    def _parse_property(self) -> t.Optional[exp.Expression]:
1539        if self._match_texts(self.PROPERTY_PARSERS):
1540            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1541
1542        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1543            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1544
1545        if self._match_text_seq("COMPOUND", "SORTKEY"):
1546            return self._parse_sortkey(compound=True)
1547
1548        if self._match_text_seq("SQL", "SECURITY"):
1549            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1550
1551        index = self._index
1552        key = self._parse_column()
1553
1554        if not self._match(TokenType.EQ):
1555            self._retreat(index)
1556            return None
1557
1558        return self.expression(
1559            exp.Property,
1560            this=key.to_dot() if isinstance(key, exp.Column) else key,
1561            value=self._parse_column() or self._parse_var(any_token=True),
1562        )
1563
1564    def _parse_stored(self) -> exp.FileFormatProperty:
1565        self._match(TokenType.ALIAS)
1566
1567        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1568        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1569
1570        return self.expression(
1571            exp.FileFormatProperty,
1572            this=(
1573                self.expression(
1574                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1575                )
1576                if input_format or output_format
1577                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1578            ),
1579        )
1580
1581    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1582        self._match(TokenType.EQ)
1583        self._match(TokenType.ALIAS)
1584        return self.expression(exp_class, this=self._parse_field(), **kwargs)
1585
1586    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1587        properties = []
1588        while True:
1589            if before:
1590                prop = self._parse_property_before()
1591            else:
1592                prop = self._parse_property()
1593
1594            if not prop:
1595                break
1596            for p in ensure_list(prop):
1597                properties.append(p)
1598
1599        if properties:
1600            return self.expression(exp.Properties, expressions=properties)
1601
1602        return None
1603
1604    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1605        return self.expression(
1606            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1607        )
1608
1609    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1610        if self._index >= 2:
1611            pre_volatile_token = self._tokens[self._index - 2]
1612        else:
1613            pre_volatile_token = None
1614
1615        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1616            return exp.VolatileProperty()
1617
1618        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1619
1620    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1621        self._match_pair(TokenType.EQ, TokenType.ON)
1622
1623        prop = self.expression(exp.WithSystemVersioningProperty)
1624        if self._match(TokenType.L_PAREN):
1625            self._match_text_seq("HISTORY_TABLE", "=")
1626            prop.set("this", self._parse_table_parts())
1627
1628            if self._match(TokenType.COMMA):
1629                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1630                prop.set("expression", self._advance_any() and self._prev.text.upper())
1631
1632            self._match_r_paren()
1633
1634        return prop
1635
1636    def _parse_with_property(
1637        self,
1638    ) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1639        if self._match(TokenType.L_PAREN, advance=False):
1640            return self._parse_wrapped_csv(self._parse_property)
1641
1642        if self._match_text_seq("JOURNAL"):
1643            return self._parse_withjournaltable()
1644
1645        if self._match_text_seq("DATA"):
1646            return self._parse_withdata(no=False)
1647        elif self._match_text_seq("NO", "DATA"):
1648            return self._parse_withdata(no=True)
1649
1650        if not self._next:
1651            return None
1652
1653        return self._parse_withisolatedloading()
1654
1655    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1656    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1657        self._match(TokenType.EQ)
1658
1659        user = self._parse_id_var()
1660        self._match(TokenType.PARAMETER)
1661        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1662
1663        if not user or not host:
1664            return None
1665
1666        return exp.DefinerProperty(this=f"{user}@{host}")
1667
1668    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1669        self._match(TokenType.TABLE)
1670        self._match(TokenType.EQ)
1671        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1672
1673    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1674        return self.expression(exp.LogProperty, no=no)
1675
1676    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1677        return self.expression(exp.JournalProperty, **kwargs)
1678
1679    def _parse_checksum(self) -> exp.ChecksumProperty:
1680        self._match(TokenType.EQ)
1681
1682        on = None
1683        if self._match(TokenType.ON):
1684            on = True
1685        elif self._match_text_seq("OFF"):
1686            on = False
1687
1688        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1689
1690    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
1691        return self.expression(
1692            exp.Cluster,
1693            expressions=(
1694                self._parse_wrapped_csv(self._parse_ordered)
1695                if wrapped
1696                else self._parse_csv(self._parse_ordered)
1697            ),
1698        )
1699
1700    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1701        self._match_text_seq("BY")
1702
1703        self._match_l_paren()
1704        expressions = self._parse_csv(self._parse_column)
1705        self._match_r_paren()
1706
1707        if self._match_text_seq("SORTED", "BY"):
1708            self._match_l_paren()
1709            sorted_by = self._parse_csv(self._parse_ordered)
1710            self._match_r_paren()
1711        else:
1712            sorted_by = None
1713
1714        self._match(TokenType.INTO)
1715        buckets = self._parse_number()
1716        self._match_text_seq("BUCKETS")
1717
1718        return self.expression(
1719            exp.ClusteredByProperty,
1720            expressions=expressions,
1721            sorted_by=sorted_by,
1722            buckets=buckets,
1723        )
1724
1725    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1726        if not self._match_text_seq("GRANTS"):
1727            self._retreat(self._index - 1)
1728            return None
1729
1730        return self.expression(exp.CopyGrantsProperty)
1731
1732    def _parse_freespace(self) -> exp.FreespaceProperty:
1733        self._match(TokenType.EQ)
1734        return self.expression(
1735            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1736        )
1737
1738    def _parse_mergeblockratio(
1739        self, no: bool = False, default: bool = False
1740    ) -> exp.MergeBlockRatioProperty:
1741        if self._match(TokenType.EQ):
1742            return self.expression(
1743                exp.MergeBlockRatioProperty,
1744                this=self._parse_number(),
1745                percent=self._match(TokenType.PERCENT),
1746            )
1747
1748        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1749
1750    def _parse_datablocksize(
1751        self,
1752        default: t.Optional[bool] = None,
1753        minimum: t.Optional[bool] = None,
1754        maximum: t.Optional[bool] = None,
1755    ) -> exp.DataBlocksizeProperty:
1756        self._match(TokenType.EQ)
1757        size = self._parse_number()
1758
1759        units = None
1760        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1761            units = self._prev.text
1762
1763        return self.expression(
1764            exp.DataBlocksizeProperty,
1765            size=size,
1766            units=units,
1767            default=default,
1768            minimum=minimum,
1769            maximum=maximum,
1770        )
1771
1772    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1773        self._match(TokenType.EQ)
1774        always = self._match_text_seq("ALWAYS")
1775        manual = self._match_text_seq("MANUAL")
1776        never = self._match_text_seq("NEVER")
1777        default = self._match_text_seq("DEFAULT")
1778
1779        autotemp = None
1780        if self._match_text_seq("AUTOTEMP"):
1781            autotemp = self._parse_schema()
1782
1783        return self.expression(
1784            exp.BlockCompressionProperty,
1785            always=always,
1786            manual=manual,
1787            never=never,
1788            default=default,
1789            autotemp=autotemp,
1790        )
1791
1792    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
1793        no = self._match_text_seq("NO")
1794        concurrent = self._match_text_seq("CONCURRENT")
1795        self._match_text_seq("ISOLATED", "LOADING")
1796        for_all = self._match_text_seq("FOR", "ALL")
1797        for_insert = self._match_text_seq("FOR", "INSERT")
1798        for_none = self._match_text_seq("FOR", "NONE")
1799        return self.expression(
1800            exp.IsolatedLoadingProperty,
1801            no=no,
1802            concurrent=concurrent,
1803            for_all=for_all,
1804            for_insert=for_insert,
1805            for_none=for_none,
1806        )
1807
1808    def _parse_locking(self) -> exp.LockingProperty:
1809        if self._match(TokenType.TABLE):
1810            kind = "TABLE"
1811        elif self._match(TokenType.VIEW):
1812            kind = "VIEW"
1813        elif self._match(TokenType.ROW):
1814            kind = "ROW"
1815        elif self._match_text_seq("DATABASE"):
1816            kind = "DATABASE"
1817        else:
1818            kind = None
1819
1820        if kind in ("DATABASE", "TABLE", "VIEW"):
1821            this = self._parse_table_parts()
1822        else:
1823            this = None
1824
1825        if self._match(TokenType.FOR):
1826            for_or_in = "FOR"
1827        elif self._match(TokenType.IN):
1828            for_or_in = "IN"
1829        else:
1830            for_or_in = None
1831
1832        if self._match_text_seq("ACCESS"):
1833            lock_type = "ACCESS"
1834        elif self._match_texts(("EXCL", "EXCLUSIVE")):
1835            lock_type = "EXCLUSIVE"
1836        elif self._match_text_seq("SHARE"):
1837            lock_type = "SHARE"
1838        elif self._match_text_seq("READ"):
1839            lock_type = "READ"
1840        elif self._match_text_seq("WRITE"):
1841            lock_type = "WRITE"
1842        elif self._match_text_seq("CHECKSUM"):
1843            lock_type = "CHECKSUM"
1844        else:
1845            lock_type = None
1846
1847        override = self._match_text_seq("OVERRIDE")
1848
1849        return self.expression(
1850            exp.LockingProperty,
1851            this=this,
1852            kind=kind,
1853            for_or_in=for_or_in,
1854            lock_type=lock_type,
1855            override=override,
1856        )
1857
1858    def _parse_partition_by(self) -> t.List[exp.Expression]:
1859        if self._match(TokenType.PARTITION_BY):
1860            return self._parse_csv(self._parse_conjunction)
1861        return []
1862
1863    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
1864        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
1865            if self._match_text_seq("MINVALUE"):
1866                return exp.var("MINVALUE")
1867            if self._match_text_seq("MAXVALUE"):
1868                return exp.var("MAXVALUE")
1869            return self._parse_bitwise()
1870
1871        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
1872        expression = None
1873        from_expressions = None
1874        to_expressions = None
1875
1876        if self._match(TokenType.IN):
1877            this = self._parse_wrapped_csv(self._parse_bitwise)
1878        elif self._match(TokenType.FROM):
1879            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1880            self._match_text_seq("TO")
1881            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1882        elif self._match_text_seq("WITH", "(", "MODULUS"):
1883            this = self._parse_number()
1884            self._match_text_seq(",", "REMAINDER")
1885            expression = self._parse_number()
1886            self._match_r_paren()
1887        else:
1888            self.raise_error("Failed to parse partition bound spec.")
1889
1890        return self.expression(
1891            exp.PartitionBoundSpec,
1892            this=this,
1893            expression=expression,
1894            from_expressions=from_expressions,
1895            to_expressions=to_expressions,
1896        )
1897
1898    # https://www.postgresql.org/docs/current/sql-createtable.html
1899    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
1900        if not self._match_text_seq("OF"):
1901            self._retreat(self._index - 1)
1902            return None
1903
1904        this = self._parse_table(schema=True)
1905
1906        if self._match(TokenType.DEFAULT):
1907            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
1908        elif self._match_text_seq("FOR", "VALUES"):
1909            expression = self._parse_partition_bound_spec()
1910        else:
1911            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
1912
1913        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
1914
1915    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
1916        self._match(TokenType.EQ)
1917        return self.expression(
1918            exp.PartitionedByProperty,
1919            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
1920        )
1921
1922    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
1923        if self._match_text_seq("AND", "STATISTICS"):
1924            statistics = True
1925        elif self._match_text_seq("AND", "NO", "STATISTICS"):
1926            statistics = False
1927        else:
1928            statistics = None
1929
1930        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
1931
1932    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1933        if self._match_text_seq("SQL"):
1934            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
1935        return None
1936
1937    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1938        if self._match_text_seq("SQL", "DATA"):
1939            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
1940        return None
1941
1942    def _parse_no_property(self) -> t.Optional[exp.Expression]:
1943        if self._match_text_seq("PRIMARY", "INDEX"):
1944            return exp.NoPrimaryIndexProperty()
1945        if self._match_text_seq("SQL"):
1946            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
1947        return None
1948
1949    def _parse_on_property(self) -> t.Optional[exp.Expression]:
1950        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
1951            return exp.OnCommitProperty()
1952        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
1953            return exp.OnCommitProperty(delete=True)
1954        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
1955
1956    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1957        if self._match_text_seq("SQL", "DATA"):
1958            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
1959        return None
1960
1961    def _parse_distkey(self) -> exp.DistKeyProperty:
1962        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
1963
1964    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
1965        table = self._parse_table(schema=True)
1966
1967        options = []
1968        while self._match_texts(("INCLUDING", "EXCLUDING")):
1969            this = self._prev.text.upper()
1970
1971            id_var = self._parse_id_var()
1972            if not id_var:
1973                return None
1974
1975            options.append(
1976                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
1977            )
1978
1979        return self.expression(exp.LikeProperty, this=table, expressions=options)
1980
1981    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
1982        return self.expression(
1983            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
1984        )
1985
1986    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
1987        self._match(TokenType.EQ)
1988        return self.expression(
1989            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
1990        )
1991
1992    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
1993        self._match_text_seq("WITH", "CONNECTION")
1994        return self.expression(
1995            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
1996        )
1997
1998    def _parse_returns(self) -> exp.ReturnsProperty:
1999        value: t.Optional[exp.Expression]
2000        is_table = self._match(TokenType.TABLE)
2001
2002        if is_table:
2003            if self._match(TokenType.LT):
2004                value = self.expression(
2005                    exp.Schema,
2006                    this="TABLE",
2007                    expressions=self._parse_csv(self._parse_struct_types),
2008                )
2009                if not self._match(TokenType.GT):
2010                    self.raise_error("Expecting >")
2011            else:
2012                value = self._parse_schema(exp.var("TABLE"))
2013        else:
2014            value = self._parse_types()
2015
2016        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
2017
2018    def _parse_describe(self) -> exp.Describe:
2019        kind = self._match_set(self.CREATABLES) and self._prev.text
2020        extended = self._match_text_seq("EXTENDED")
2021        this = self._parse_table(schema=True)
2022        properties = self._parse_properties()
2023        expressions = properties.expressions if properties else None
2024        return self.expression(
2025            exp.Describe, this=this, extended=extended, kind=kind, expressions=expressions
2026        )
2027
2028    def _parse_insert(self) -> exp.Insert:
2029        comments = ensure_list(self._prev_comments)
2030        overwrite = self._match(TokenType.OVERWRITE)
2031        ignore = self._match(TokenType.IGNORE)
2032        local = self._match_text_seq("LOCAL")
2033        alternative = None
2034
2035        if self._match_text_seq("DIRECTORY"):
2036            this: t.Optional[exp.Expression] = self.expression(
2037                exp.Directory,
2038                this=self._parse_var_or_string(),
2039                local=local,
2040                row_format=self._parse_row_format(match_row=True),
2041            )
2042        else:
2043            if self._match(TokenType.OR):
2044                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2045
2046            self._match(TokenType.INTO)
2047            comments += ensure_list(self._prev_comments)
2048            self._match(TokenType.TABLE)
2049            this = self._parse_table(schema=True)
2050
2051        returning = self._parse_returning()
2052
2053        return self.expression(
2054            exp.Insert,
2055            comments=comments,
2056            this=this,
2057            by_name=self._match_text_seq("BY", "NAME"),
2058            exists=self._parse_exists(),
2059            partition=self._parse_partition(),
2060            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
2061            and self._parse_conjunction(),
2062            expression=self._parse_ddl_select(),
2063            conflict=self._parse_on_conflict(),
2064            returning=returning or self._parse_returning(),
2065            overwrite=overwrite,
2066            alternative=alternative,
2067            ignore=ignore,
2068        )
2069
2070    def _parse_kill(self) -> exp.Kill:
2071        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2072
2073        return self.expression(
2074            exp.Kill,
2075            this=self._parse_primary(),
2076            kind=kind,
2077        )
2078
2079    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2080        conflict = self._match_text_seq("ON", "CONFLICT")
2081        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2082
2083        if not conflict and not duplicate:
2084            return None
2085
2086        nothing = None
2087        expressions = None
2088        key = None
2089        constraint = None
2090
2091        if conflict:
2092            if self._match_text_seq("ON", "CONSTRAINT"):
2093                constraint = self._parse_id_var()
2094            else:
2095                key = self._parse_csv(self._parse_value)
2096
2097        self._match_text_seq("DO")
2098        if self._match_text_seq("NOTHING"):
2099            nothing = True
2100        else:
2101            self._match(TokenType.UPDATE)
2102            self._match(TokenType.SET)
2103            expressions = self._parse_csv(self._parse_equality)
2104
2105        return self.expression(
2106            exp.OnConflict,
2107            duplicate=duplicate,
2108            expressions=expressions,
2109            nothing=nothing,
2110            key=key,
2111            constraint=constraint,
2112        )
2113
2114    def _parse_returning(self) -> t.Optional[exp.Returning]:
2115        if not self._match(TokenType.RETURNING):
2116            return None
2117        return self.expression(
2118            exp.Returning,
2119            expressions=self._parse_csv(self._parse_expression),
2120            into=self._match(TokenType.INTO) and self._parse_table_part(),
2121        )
2122
2123    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2124        if not self._match(TokenType.FORMAT):
2125            return None
2126        return self._parse_row_format()
2127
2128    def _parse_row_format(
2129        self, match_row: bool = False
2130    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2131        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2132            return None
2133
2134        if self._match_text_seq("SERDE"):
2135            this = self._parse_string()
2136
2137            serde_properties = None
2138            if self._match(TokenType.SERDE_PROPERTIES):
2139                serde_properties = self.expression(
2140                    exp.SerdeProperties, expressions=self._parse_wrapped_csv(self._parse_property)
2141                )
2142
2143            return self.expression(
2144                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2145            )
2146
2147        self._match_text_seq("DELIMITED")
2148
2149        kwargs = {}
2150
2151        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2152            kwargs["fields"] = self._parse_string()
2153            if self._match_text_seq("ESCAPED", "BY"):
2154                kwargs["escaped"] = self._parse_string()
2155        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2156            kwargs["collection_items"] = self._parse_string()
2157        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2158            kwargs["map_keys"] = self._parse_string()
2159        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2160            kwargs["lines"] = self._parse_string()
2161        if self._match_text_seq("NULL", "DEFINED", "AS"):
2162            kwargs["null"] = self._parse_string()
2163
2164        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2165
2166    def _parse_load(self) -> exp.LoadData | exp.Command:
2167        if self._match_text_seq("DATA"):
2168            local = self._match_text_seq("LOCAL")
2169            self._match_text_seq("INPATH")
2170            inpath = self._parse_string()
2171            overwrite = self._match(TokenType.OVERWRITE)
2172            self._match_pair(TokenType.INTO, TokenType.TABLE)
2173
2174            return self.expression(
2175                exp.LoadData,
2176                this=self._parse_table(schema=True),
2177                local=local,
2178                overwrite=overwrite,
2179                inpath=inpath,
2180                partition=self._parse_partition(),
2181                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2182                serde=self._match_text_seq("SERDE") and self._parse_string(),
2183            )
2184        return self._parse_as_command(self._prev)
2185
2186    def _parse_delete(self) -> exp.Delete:
2187        # This handles MySQL's "Multiple-Table Syntax"
2188        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2189        tables = None
2190        comments = self._prev_comments
2191        if not self._match(TokenType.FROM, advance=False):
2192            tables = self._parse_csv(self._parse_table) or None
2193
2194        returning = self._parse_returning()
2195
2196        return self.expression(
2197            exp.Delete,
2198            comments=comments,
2199            tables=tables,
2200            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2201            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2202            where=self._parse_where(),
2203            returning=returning or self._parse_returning(),
2204            limit=self._parse_limit(),
2205        )
2206
2207    def _parse_update(self) -> exp.Update:
2208        comments = self._prev_comments
2209        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2210        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2211        returning = self._parse_returning()
2212        return self.expression(
2213            exp.Update,
2214            comments=comments,
2215            **{  # type: ignore
2216                "this": this,
2217                "expressions": expressions,
2218                "from": self._parse_from(joins=True),
2219                "where": self._parse_where(),
2220                "returning": returning or self._parse_returning(),
2221                "order": self._parse_order(),
2222                "limit": self._parse_limit(),
2223            },
2224        )
2225
2226    def _parse_uncache(self) -> exp.Uncache:
2227        if not self._match(TokenType.TABLE):
2228            self.raise_error("Expecting TABLE after UNCACHE")
2229
2230        return self.expression(
2231            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2232        )
2233
2234    def _parse_cache(self) -> exp.Cache:
2235        lazy = self._match_text_seq("LAZY")
2236        self._match(TokenType.TABLE)
2237        table = self._parse_table(schema=True)
2238
2239        options = []
2240        if self._match_text_seq("OPTIONS"):
2241            self._match_l_paren()
2242            k = self._parse_string()
2243            self._match(TokenType.EQ)
2244            v = self._parse_string()
2245            options = [k, v]
2246            self._match_r_paren()
2247
2248        self._match(TokenType.ALIAS)
2249        return self.expression(
2250            exp.Cache,
2251            this=table,
2252            lazy=lazy,
2253            options=options,
2254            expression=self._parse_select(nested=True),
2255        )
2256
2257    def _parse_partition(self) -> t.Optional[exp.Partition]:
2258        if not self._match(TokenType.PARTITION):
2259            return None
2260
2261        return self.expression(
2262            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2263        )
2264
2265    def _parse_value(self) -> exp.Tuple:
2266        if self._match(TokenType.L_PAREN):
2267            expressions = self._parse_csv(self._parse_expression)
2268            self._match_r_paren()
2269            return self.expression(exp.Tuple, expressions=expressions)
2270
2271        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
2272        # https://prestodb.io/docs/current/sql/values.html
2273        return self.expression(exp.Tuple, expressions=[self._parse_expression()])
2274
2275    def _parse_projections(self) -> t.List[exp.Expression]:
2276        return self._parse_expressions()
2277
2278    def _parse_select(
2279        self,
2280        nested: bool = False,
2281        table: bool = False,
2282        parse_subquery_alias: bool = True,
2283        parse_set_operation: bool = True,
2284    ) -> t.Optional[exp.Expression]:
2285        cte = self._parse_with()
2286
2287        if cte:
2288            this = self._parse_statement()
2289
2290            if not this:
2291                self.raise_error("Failed to parse any statement following CTE")
2292                return cte
2293
2294            if "with" in this.arg_types:
2295                this.set("with", cte)
2296            else:
2297                self.raise_error(f"{this.key} does not support CTE")
2298                this = cte
2299
2300            return this
2301
2302        # duckdb supports leading with FROM x
2303        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2304
2305        if self._match(TokenType.SELECT):
2306            comments = self._prev_comments
2307
2308            hint = self._parse_hint()
2309            all_ = self._match(TokenType.ALL)
2310            distinct = self._match_set(self.DISTINCT_TOKENS)
2311
2312            kind = (
2313                self._match(TokenType.ALIAS)
2314                and self._match_texts(("STRUCT", "VALUE"))
2315                and self._prev.text.upper()
2316            )
2317
2318            if distinct:
2319                distinct = self.expression(
2320                    exp.Distinct,
2321                    on=self._parse_value() if self._match(TokenType.ON) else None,
2322                )
2323
2324            if all_ and distinct:
2325                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2326
2327            limit = self._parse_limit(top=True)
2328            projections = self._parse_projections()
2329
2330            this = self.expression(
2331                exp.Select,
2332                kind=kind,
2333                hint=hint,
2334                distinct=distinct,
2335                expressions=projections,
2336                limit=limit,
2337            )
2338            this.comments = comments
2339
2340            into = self._parse_into()
2341            if into:
2342                this.set("into", into)
2343
2344            if not from_:
2345                from_ = self._parse_from()
2346
2347            if from_:
2348                this.set("from", from_)
2349
2350            this = self._parse_query_modifiers(this)
2351        elif (table or nested) and self._match(TokenType.L_PAREN):
2352            if self._match(TokenType.PIVOT):
2353                this = self._parse_simplified_pivot()
2354            elif self._match(TokenType.FROM):
2355                this = exp.select("*").from_(
2356                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2357                )
2358            else:
2359                this = (
2360                    self._parse_table()
2361                    if table
2362                    else self._parse_select(nested=True, parse_set_operation=False)
2363                )
2364                this = self._parse_query_modifiers(self._parse_set_operations(this))
2365
2366            self._match_r_paren()
2367
2368            # We return early here so that the UNION isn't attached to the subquery by the
2369            # following call to _parse_set_operations, but instead becomes the parent node
2370            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2371        elif self._match(TokenType.VALUES):
2372            this = self.expression(
2373                exp.Values,
2374                expressions=self._parse_csv(self._parse_value),
2375                alias=self._parse_table_alias(),
2376            )
2377        elif from_:
2378            this = exp.select("*").from_(from_.this, copy=False)
2379        else:
2380            this = None
2381
2382        if parse_set_operation:
2383            return self._parse_set_operations(this)
2384        return this
2385
2386    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2387        if not skip_with_token and not self._match(TokenType.WITH):
2388            return None
2389
2390        comments = self._prev_comments
2391        recursive = self._match(TokenType.RECURSIVE)
2392
2393        expressions = []
2394        while True:
2395            expressions.append(self._parse_cte())
2396
2397            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2398                break
2399            else:
2400                self._match(TokenType.WITH)
2401
2402        return self.expression(
2403            exp.With, comments=comments, expressions=expressions, recursive=recursive
2404        )
2405
2406    def _parse_cte(self) -> exp.CTE:
2407        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2408        if not alias or not alias.this:
2409            self.raise_error("Expected CTE to have alias")
2410
2411        self._match(TokenType.ALIAS)
2412        return self.expression(
2413            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
2414        )
2415
2416    def _parse_table_alias(
2417        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2418    ) -> t.Optional[exp.TableAlias]:
2419        any_token = self._match(TokenType.ALIAS)
2420        alias = (
2421            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2422            or self._parse_string_as_identifier()
2423        )
2424
2425        index = self._index
2426        if self._match(TokenType.L_PAREN):
2427            columns = self._parse_csv(self._parse_function_parameter)
2428            self._match_r_paren() if columns else self._retreat(index)
2429        else:
2430            columns = None
2431
2432        if not alias and not columns:
2433            return None
2434
2435        return self.expression(exp.TableAlias, this=alias, columns=columns)
2436
2437    def _parse_subquery(
2438        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2439    ) -> t.Optional[exp.Subquery]:
2440        if not this:
2441            return None
2442
2443        return self.expression(
2444            exp.Subquery,
2445            this=this,
2446            pivots=self._parse_pivots(),
2447            alias=self._parse_table_alias() if parse_alias else None,
2448        )
2449
2450    def _parse_query_modifiers(
2451        self, this: t.Optional[exp.Expression]
2452    ) -> t.Optional[exp.Expression]:
2453        if isinstance(this, self.MODIFIABLES):
2454            for join in iter(self._parse_join, None):
2455                this.append("joins", join)
2456            for lateral in iter(self._parse_lateral, None):
2457                this.append("laterals", lateral)
2458
2459            while True:
2460                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2461                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2462                    key, expression = parser(self)
2463
2464                    if expression:
2465                        this.set(key, expression)
2466                        if key == "limit":
2467                            offset = expression.args.pop("offset", None)
2468                            if offset:
2469                                this.set("offset", exp.Offset(expression=offset))
2470                        continue
2471                break
2472        return this
2473
2474    def _parse_hint(self) -> t.Optional[exp.Hint]:
2475        if self._match(TokenType.HINT):
2476            hints = []
2477            for hint in iter(lambda: self._parse_csv(self._parse_function), []):
2478                hints.extend(hint)
2479
2480            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2481                self.raise_error("Expected */ after HINT")
2482
2483            return self.expression(exp.Hint, expressions=hints)
2484
2485        return None
2486
2487    def _parse_into(self) -> t.Optional[exp.Into]:
2488        if not self._match(TokenType.INTO):
2489            return None
2490
2491        temp = self._match(TokenType.TEMPORARY)
2492        unlogged = self._match_text_seq("UNLOGGED")
2493        self._match(TokenType.TABLE)
2494
2495        return self.expression(
2496            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2497        )
2498
2499    def _parse_from(
2500        self, joins: bool = False, skip_from_token: bool = False
2501    ) -> t.Optional[exp.From]:
2502        if not skip_from_token and not self._match(TokenType.FROM):
2503            return None
2504
2505        return self.expression(
2506            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2507        )
2508
2509    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2510        if not self._match(TokenType.MATCH_RECOGNIZE):
2511            return None
2512
2513        self._match_l_paren()
2514
2515        partition = self._parse_partition_by()
2516        order = self._parse_order()
2517        measures = self._parse_expressions() if self._match_text_seq("MEASURES") else None
2518
2519        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2520            rows = exp.var("ONE ROW PER MATCH")
2521        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2522            text = "ALL ROWS PER MATCH"
2523            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2524                text += " SHOW EMPTY MATCHES"
2525            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2526                text += " OMIT EMPTY MATCHES"
2527            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2528                text += " WITH UNMATCHED ROWS"
2529            rows = exp.var(text)
2530        else:
2531            rows = None
2532
2533        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2534            text = "AFTER MATCH SKIP"
2535            if self._match_text_seq("PAST", "LAST", "ROW"):
2536                text += " PAST LAST ROW"
2537            elif self._match_text_seq("TO", "NEXT", "ROW"):
2538                text += " TO NEXT ROW"
2539            elif self._match_text_seq("TO", "FIRST"):
2540                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2541            elif self._match_text_seq("TO", "LAST"):
2542                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2543            after = exp.var(text)
2544        else:
2545            after = None
2546
2547        if self._match_text_seq("PATTERN"):
2548            self._match_l_paren()
2549
2550            if not self._curr:
2551                self.raise_error("Expecting )", self._curr)
2552
2553            paren = 1
2554            start = self._curr
2555
2556            while self._curr and paren > 0:
2557                if self._curr.token_type == TokenType.L_PAREN:
2558                    paren += 1
2559                if self._curr.token_type == TokenType.R_PAREN:
2560                    paren -= 1
2561
2562                end = self._prev
2563                self._advance()
2564
2565            if paren > 0:
2566                self.raise_error("Expecting )", self._curr)
2567
2568            pattern = exp.var(self._find_sql(start, end))
2569        else:
2570            pattern = None
2571
2572        define = (
2573            self._parse_csv(self._parse_name_as_expression)
2574            if self._match_text_seq("DEFINE")
2575            else None
2576        )
2577
2578        self._match_r_paren()
2579
2580        return self.expression(
2581            exp.MatchRecognize,
2582            partition_by=partition,
2583            order=order,
2584            measures=measures,
2585            rows=rows,
2586            after=after,
2587            pattern=pattern,
2588            define=define,
2589            alias=self._parse_table_alias(),
2590        )
2591
2592    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2593        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2594        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2595            cross_apply = False
2596
2597        if cross_apply is not None:
2598            this = self._parse_select(table=True)
2599            view = None
2600            outer = None
2601        elif self._match(TokenType.LATERAL):
2602            this = self._parse_select(table=True)
2603            view = self._match(TokenType.VIEW)
2604            outer = self._match(TokenType.OUTER)
2605        else:
2606            return None
2607
2608        if not this:
2609            this = (
2610                self._parse_unnest()
2611                or self._parse_function()
2612                or self._parse_id_var(any_token=False)
2613            )
2614
2615            while self._match(TokenType.DOT):
2616                this = exp.Dot(
2617                    this=this,
2618                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2619                )
2620
2621        if view:
2622            table = self._parse_id_var(any_token=False)
2623            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2624            table_alias: t.Optional[exp.TableAlias] = self.expression(
2625                exp.TableAlias, this=table, columns=columns
2626            )
2627        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2628            # We move the alias from the lateral's child node to the lateral itself
2629            table_alias = this.args["alias"].pop()
2630        else:
2631            table_alias = self._parse_table_alias()
2632
2633        return self.expression(
2634            exp.Lateral,
2635            this=this,
2636            view=view,
2637            outer=outer,
2638            alias=table_alias,
2639            cross_apply=cross_apply,
2640        )
2641
2642    def _parse_join_parts(
2643        self,
2644    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2645        return (
2646            self._match_set(self.JOIN_METHODS) and self._prev,
2647            self._match_set(self.JOIN_SIDES) and self._prev,
2648            self._match_set(self.JOIN_KINDS) and self._prev,
2649        )
2650
2651    def _parse_join(
2652        self, skip_join_token: bool = False, parse_bracket: bool = False
2653    ) -> t.Optional[exp.Join]:
2654        if self._match(TokenType.COMMA):
2655            return self.expression(exp.Join, this=self._parse_table())
2656
2657        index = self._index
2658        method, side, kind = self._parse_join_parts()
2659        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2660        join = self._match(TokenType.JOIN)
2661
2662        if not skip_join_token and not join:
2663            self._retreat(index)
2664            kind = None
2665            method = None
2666            side = None
2667
2668        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2669        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2670
2671        if not skip_join_token and not join and not outer_apply and not cross_apply:
2672            return None
2673
2674        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2675
2676        if method:
2677            kwargs["method"] = method.text
2678        if side:
2679            kwargs["side"] = side.text
2680        if kind:
2681            kwargs["kind"] = kind.text
2682        if hint:
2683            kwargs["hint"] = hint
2684
2685        if self._match(TokenType.ON):
2686            kwargs["on"] = self._parse_conjunction()
2687        elif self._match(TokenType.USING):
2688            kwargs["using"] = self._parse_wrapped_id_vars()
2689        elif not (kind and kind.token_type == TokenType.CROSS):
2690            index = self._index
2691            join = self._parse_join()
2692
2693            if join and self._match(TokenType.ON):
2694                kwargs["on"] = self._parse_conjunction()
2695            elif join and self._match(TokenType.USING):
2696                kwargs["using"] = self._parse_wrapped_id_vars()
2697            else:
2698                join = None
2699                self._retreat(index)
2700
2701            kwargs["this"].set("joins", [join] if join else None)
2702
2703        comments = [c for token in (method, side, kind) if token for c in token.comments]
2704        return self.expression(exp.Join, comments=comments, **kwargs)
2705
2706    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2707        this = self._parse_conjunction()
2708        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2709            return this
2710
2711        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2712            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
2713
2714        return this
2715
2716    def _parse_index(
2717        self,
2718        index: t.Optional[exp.Expression] = None,
2719    ) -> t.Optional[exp.Index]:
2720        if index:
2721            unique = None
2722            primary = None
2723            amp = None
2724
2725            self._match(TokenType.ON)
2726            self._match(TokenType.TABLE)  # hive
2727            table = self._parse_table_parts(schema=True)
2728        else:
2729            unique = self._match(TokenType.UNIQUE)
2730            primary = self._match_text_seq("PRIMARY")
2731            amp = self._match_text_seq("AMP")
2732
2733            if not self._match(TokenType.INDEX):
2734                return None
2735
2736            index = self._parse_id_var()
2737            table = None
2738
2739        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
2740
2741        if self._match(TokenType.L_PAREN, advance=False):
2742            columns = self._parse_wrapped_csv(lambda: self._parse_ordered(self._parse_opclass))
2743        else:
2744            columns = None
2745
2746        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
2747
2748        return self.expression(
2749            exp.Index,
2750            this=index,
2751            table=table,
2752            using=using,
2753            columns=columns,
2754            unique=unique,
2755            primary=primary,
2756            amp=amp,
2757            include=include,
2758            partition_by=self._parse_partition_by(),
2759            where=self._parse_where(),
2760        )
2761
2762    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
2763        hints: t.List[exp.Expression] = []
2764        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
2765            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
2766            hints.append(
2767                self.expression(
2768                    exp.WithTableHint,
2769                    expressions=self._parse_csv(
2770                        lambda: self._parse_function() or self._parse_var(any_token=True)
2771                    ),
2772                )
2773            )
2774            self._match_r_paren()
2775        else:
2776            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
2777            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
2778                hint = exp.IndexTableHint(this=self._prev.text.upper())
2779
2780                self._match_texts(("INDEX", "KEY"))
2781                if self._match(TokenType.FOR):
2782                    hint.set("target", self._advance_any() and self._prev.text.upper())
2783
2784                hint.set("expressions", self._parse_wrapped_id_vars())
2785                hints.append(hint)
2786
2787        return hints or None
2788
2789    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
2790        return (
2791            (not schema and self._parse_function(optional_parens=False))
2792            or self._parse_id_var(any_token=False)
2793            or self._parse_string_as_identifier()
2794            or self._parse_placeholder()
2795        )
2796
2797    def _parse_table_parts(self, schema: bool = False, is_db_reference: bool = False) -> exp.Table:
2798        catalog = None
2799        db = None
2800        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
2801
2802        while self._match(TokenType.DOT):
2803            if catalog:
2804                # This allows nesting the table in arbitrarily many dot expressions if needed
2805                table = self.expression(
2806                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
2807                )
2808            else:
2809                catalog = db
2810                db = table
2811                table = self._parse_table_part(schema=schema) or ""
2812
2813        if is_db_reference:
2814            catalog = db
2815            db = table
2816            table = None
2817
2818        if not table and not is_db_reference:
2819            self.raise_error(f"Expected table name but got {self._curr}")
2820        if not db and is_db_reference:
2821            self.raise_error(f"Expected database name but got {self._curr}")
2822
2823        return self.expression(
2824            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
2825        )
2826
2827    def _parse_table(
2828        self,
2829        schema: bool = False,
2830        joins: bool = False,
2831        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
2832        parse_bracket: bool = False,
2833        is_db_reference: bool = False,
2834    ) -> t.Optional[exp.Expression]:
2835        lateral = self._parse_lateral()
2836        if lateral:
2837            return lateral
2838
2839        unnest = self._parse_unnest()
2840        if unnest:
2841            return unnest
2842
2843        values = self._parse_derived_table_values()
2844        if values:
2845            return values
2846
2847        subquery = self._parse_select(table=True)
2848        if subquery:
2849            if not subquery.args.get("pivots"):
2850                subquery.set("pivots", self._parse_pivots())
2851            return subquery
2852
2853        bracket = parse_bracket and self._parse_bracket(None)
2854        bracket = self.expression(exp.Table, this=bracket) if bracket else None
2855        this = t.cast(
2856            exp.Expression,
2857            bracket
2858            or self._parse_bracket(
2859                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
2860            ),
2861        )
2862
2863        if schema:
2864            return self._parse_schema(this=this)
2865
2866        version = self._parse_version()
2867
2868        if version:
2869            this.set("version", version)
2870
2871        if self.dialect.ALIAS_POST_TABLESAMPLE:
2872            table_sample = self._parse_table_sample()
2873
2874        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2875        if alias:
2876            this.set("alias", alias)
2877
2878        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
2879            return self.expression(
2880                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
2881            )
2882
2883        this.set("hints", self._parse_table_hints())
2884
2885        if not this.args.get("pivots"):
2886            this.set("pivots", self._parse_pivots())
2887
2888        if not self.dialect.ALIAS_POST_TABLESAMPLE:
2889            table_sample = self._parse_table_sample()
2890
2891        if table_sample:
2892            table_sample.set("this", this)
2893            this = table_sample
2894
2895        if joins:
2896            for join in iter(self._parse_join, None):
2897                this.append("joins", join)
2898
2899        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
2900            this.set("ordinality", True)
2901            this.set("alias", self._parse_table_alias())
2902
2903        return this
2904
2905    def _parse_version(self) -> t.Optional[exp.Version]:
2906        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
2907            this = "TIMESTAMP"
2908        elif self._match(TokenType.VERSION_SNAPSHOT):
2909            this = "VERSION"
2910        else:
2911            return None
2912
2913        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
2914            kind = self._prev.text.upper()
2915            start = self._parse_bitwise()
2916            self._match_texts(("TO", "AND"))
2917            end = self._parse_bitwise()
2918            expression: t.Optional[exp.Expression] = self.expression(
2919                exp.Tuple, expressions=[start, end]
2920            )
2921        elif self._match_text_seq("CONTAINED", "IN"):
2922            kind = "CONTAINED IN"
2923            expression = self.expression(
2924                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
2925            )
2926        elif self._match(TokenType.ALL):
2927            kind = "ALL"
2928            expression = None
2929        else:
2930            self._match_text_seq("AS", "OF")
2931            kind = "AS OF"
2932            expression = self._parse_type()
2933
2934        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
2935
2936    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
2937        if not self._match(TokenType.UNNEST):
2938            return None
2939
2940        expressions = self._parse_wrapped_csv(self._parse_equality)
2941        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
2942
2943        alias = self._parse_table_alias() if with_alias else None
2944
2945        if alias:
2946            if self.dialect.UNNEST_COLUMN_ONLY:
2947                if alias.args.get("columns"):
2948                    self.raise_error("Unexpected extra column alias in unnest.")
2949
2950                alias.set("columns", [alias.this])
2951                alias.set("this", None)
2952
2953            columns = alias.args.get("columns") or []
2954            if offset and len(expressions) < len(columns):
2955                offset = columns.pop()
2956
2957        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
2958            self._match(TokenType.ALIAS)
2959            offset = self._parse_id_var(
2960                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
2961            ) or exp.to_identifier("offset")
2962
2963        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
2964
2965    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
2966        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
2967        if not is_derived and not self._match(TokenType.VALUES):
2968            return None
2969
2970        expressions = self._parse_csv(self._parse_value)
2971        alias = self._parse_table_alias()
2972
2973        if is_derived:
2974            self._match_r_paren()
2975
2976        return self.expression(
2977            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
2978        )
2979
2980    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
2981        if not self._match(TokenType.TABLE_SAMPLE) and not (
2982            as_modifier and self._match_text_seq("USING", "SAMPLE")
2983        ):
2984            return None
2985
2986        bucket_numerator = None
2987        bucket_denominator = None
2988        bucket_field = None
2989        percent = None
2990        size = None
2991        seed = None
2992
2993        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
2994        matched_l_paren = self._match(TokenType.L_PAREN)
2995
2996        if self.TABLESAMPLE_CSV:
2997            num = None
2998            expressions = self._parse_csv(self._parse_primary)
2999        else:
3000            expressions = None
3001            num = (
3002                self._parse_factor()
3003                if self._match(TokenType.NUMBER, advance=False)
3004                else self._parse_primary() or self._parse_placeholder()
3005            )
3006
3007        if self._match_text_seq("BUCKET"):
3008            bucket_numerator = self._parse_number()
3009            self._match_text_seq("OUT", "OF")
3010            bucket_denominator = bucket_denominator = self._parse_number()
3011            self._match(TokenType.ON)
3012            bucket_field = self._parse_field()
3013        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3014            percent = num
3015        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3016            size = num
3017        else:
3018            percent = num
3019
3020        if matched_l_paren:
3021            self._match_r_paren()
3022
3023        if self._match(TokenType.L_PAREN):
3024            method = self._parse_var(upper=True)
3025            seed = self._match(TokenType.COMMA) and self._parse_number()
3026            self._match_r_paren()
3027        elif self._match_texts(("SEED", "REPEATABLE")):
3028            seed = self._parse_wrapped(self._parse_number)
3029
3030        return self.expression(
3031            exp.TableSample,
3032            expressions=expressions,
3033            method=method,
3034            bucket_numerator=bucket_numerator,
3035            bucket_denominator=bucket_denominator,
3036            bucket_field=bucket_field,
3037            percent=percent,
3038            size=size,
3039            seed=seed,
3040        )
3041
3042    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3043        return list(iter(self._parse_pivot, None)) or None
3044
3045    def _parse_joins(self) -> t.Optional[t.List[exp.Join]]:
3046        return list(iter(self._parse_join, None)) or None
3047
3048    # https://duckdb.org/docs/sql/statements/pivot
3049    def _parse_simplified_pivot(self) -> exp.Pivot:
3050        def _parse_on() -> t.Optional[exp.Expression]:
3051            this = self._parse_bitwise()
3052            return self._parse_in(this) if self._match(TokenType.IN) else this
3053
3054        this = self._parse_table()
3055        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3056        using = self._match(TokenType.USING) and self._parse_csv(
3057            lambda: self._parse_alias(self._parse_function())
3058        )
3059        group = self._parse_group()
3060        return self.expression(
3061            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3062        )
3063
3064    def _parse_pivot_in(self) -> exp.In:
3065        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3066            this = self._parse_conjunction()
3067
3068            self._match(TokenType.ALIAS)
3069            alias = self._parse_field()
3070            if alias:
3071                return self.expression(exp.PivotAlias, this=this, alias=alias)
3072
3073            return this
3074
3075        value = self._parse_column()
3076
3077        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3078            self.raise_error("Expecting IN (")
3079
3080        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3081
3082        self._match_r_paren()
3083        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3084
3085    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3086        index = self._index
3087        include_nulls = None
3088
3089        if self._match(TokenType.PIVOT):
3090            unpivot = False
3091        elif self._match(TokenType.UNPIVOT):
3092            unpivot = True
3093
3094            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3095            if self._match_text_seq("INCLUDE", "NULLS"):
3096                include_nulls = True
3097            elif self._match_text_seq("EXCLUDE", "NULLS"):
3098                include_nulls = False
3099        else:
3100            return None
3101
3102        expressions = []
3103
3104        if not self._match(TokenType.L_PAREN):
3105            self._retreat(index)
3106            return None
3107
3108        if unpivot:
3109            expressions = self._parse_csv(self._parse_column)
3110        else:
3111            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3112
3113        if not expressions:
3114            self.raise_error("Failed to parse PIVOT's aggregation list")
3115
3116        if not self._match(TokenType.FOR):
3117            self.raise_error("Expecting FOR")
3118
3119        field = self._parse_pivot_in()
3120
3121        self._match_r_paren()
3122
3123        pivot = self.expression(
3124            exp.Pivot,
3125            expressions=expressions,
3126            field=field,
3127            unpivot=unpivot,
3128            include_nulls=include_nulls,
3129        )
3130
3131        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3132            pivot.set("alias", self._parse_table_alias())
3133
3134        if not unpivot:
3135            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3136
3137            columns: t.List[exp.Expression] = []
3138            for fld in pivot.args["field"].expressions:
3139                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3140                for name in names:
3141                    if self.PREFIXED_PIVOT_COLUMNS:
3142                        name = f"{name}_{field_name}" if name else field_name
3143                    else:
3144                        name = f"{field_name}_{name}" if name else field_name
3145
3146                    columns.append(exp.to_identifier(name))
3147
3148            pivot.set("columns", columns)
3149
3150        return pivot
3151
3152    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3153        return [agg.alias for agg in aggregations]
3154
3155    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3156        if not skip_where_token and not self._match(TokenType.WHERE):
3157            return None
3158
3159        return self.expression(
3160            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3161        )
3162
3163    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3164        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3165            return None
3166
3167        elements = defaultdict(list)
3168
3169        if self._match(TokenType.ALL):
3170            return self.expression(exp.Group, all=True)
3171
3172        while True:
3173            expressions = self._parse_csv(self._parse_conjunction)
3174            if expressions:
3175                elements["expressions"].extend(expressions)
3176
3177            grouping_sets = self._parse_grouping_sets()
3178            if grouping_sets:
3179                elements["grouping_sets"].extend(grouping_sets)
3180
3181            rollup = None
3182            cube = None
3183            totals = None
3184
3185            index = self._index
3186            with_ = self._match(TokenType.WITH)
3187            if self._match(TokenType.ROLLUP):
3188                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3189                elements["rollup"].extend(ensure_list(rollup))
3190
3191            if self._match(TokenType.CUBE):
3192                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3193                elements["cube"].extend(ensure_list(cube))
3194
3195            if self._match_text_seq("TOTALS"):
3196                totals = True
3197                elements["totals"] = True  # type: ignore
3198
3199            if not (grouping_sets or rollup or cube or totals):
3200                if with_:
3201                    self._retreat(index)
3202                break
3203
3204        return self.expression(exp.Group, **elements)  # type: ignore
3205
3206    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3207        if not self._match(TokenType.GROUPING_SETS):
3208            return None
3209
3210        return self._parse_wrapped_csv(self._parse_grouping_set)
3211
3212    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3213        if self._match(TokenType.L_PAREN):
3214            grouping_set = self._parse_csv(self._parse_column)
3215            self._match_r_paren()
3216            return self.expression(exp.Tuple, expressions=grouping_set)
3217
3218        return self._parse_column()
3219
3220    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3221        if not skip_having_token and not self._match(TokenType.HAVING):
3222            return None
3223        return self.expression(exp.Having, this=self._parse_conjunction())
3224
3225    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3226        if not self._match(TokenType.QUALIFY):
3227            return None
3228        return self.expression(exp.Qualify, this=self._parse_conjunction())
3229
3230    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3231        if skip_start_token:
3232            start = None
3233        elif self._match(TokenType.START_WITH):
3234            start = self._parse_conjunction()
3235        else:
3236            return None
3237
3238        self._match(TokenType.CONNECT_BY)
3239        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3240            exp.Prior, this=self._parse_bitwise()
3241        )
3242        connect = self._parse_conjunction()
3243        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3244
3245        if not start and self._match(TokenType.START_WITH):
3246            start = self._parse_conjunction()
3247
3248        return self.expression(exp.Connect, start=start, connect=connect)
3249
3250    def _parse_name_as_expression(self) -> exp.Alias:
3251        return self.expression(
3252            exp.Alias,
3253            alias=self._parse_id_var(any_token=True),
3254            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3255        )
3256
3257    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3258        if self._match_text_seq("INTERPOLATE"):
3259            return self._parse_wrapped_csv(self._parse_name_as_expression)
3260        return None
3261
3262    def _parse_order(
3263        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3264    ) -> t.Optional[exp.Expression]:
3265        siblings = None
3266        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3267            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3268                return this
3269
3270            siblings = True
3271
3272        return self.expression(
3273            exp.Order,
3274            this=this,
3275            expressions=self._parse_csv(self._parse_ordered),
3276            interpolate=self._parse_interpolate(),
3277            siblings=siblings,
3278        )
3279
3280    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3281        if not self._match(token):
3282            return None
3283        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3284
3285    def _parse_ordered(self, parse_method: t.Optional[t.Callable] = None) -> exp.Ordered:
3286        this = parse_method() if parse_method else self._parse_conjunction()
3287
3288        asc = self._match(TokenType.ASC)
3289        desc = self._match(TokenType.DESC) or (asc and False)
3290
3291        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3292        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3293
3294        nulls_first = is_nulls_first or False
3295        explicitly_null_ordered = is_nulls_first or is_nulls_last
3296
3297        if (
3298            not explicitly_null_ordered
3299            and (
3300                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3301                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3302            )
3303            and self.dialect.NULL_ORDERING != "nulls_are_last"
3304        ):
3305            nulls_first = True
3306
3307        if self._match_text_seq("WITH", "FILL"):
3308            with_fill = self.expression(
3309                exp.WithFill,
3310                **{  # type: ignore
3311                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3312                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3313                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3314                },
3315            )
3316        else:
3317            with_fill = None
3318
3319        return self.expression(
3320            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3321        )
3322
3323    def _parse_limit(
3324        self, this: t.Optional[exp.Expression] = None, top: bool = False
3325    ) -> t.Optional[exp.Expression]:
3326        if self._match(TokenType.TOP if top else TokenType.LIMIT):
3327            comments = self._prev_comments
3328            if top:
3329                limit_paren = self._match(TokenType.L_PAREN)
3330                expression = self._parse_term() if limit_paren else self._parse_number()
3331
3332                if limit_paren:
3333                    self._match_r_paren()
3334            else:
3335                expression = self._parse_term()
3336
3337            if self._match(TokenType.COMMA):
3338                offset = expression
3339                expression = self._parse_term()
3340            else:
3341                offset = None
3342
3343            limit_exp = self.expression(
3344                exp.Limit, this=this, expression=expression, offset=offset, comments=comments
3345            )
3346
3347            return limit_exp
3348
3349        if self._match(TokenType.FETCH):
3350            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3351            direction = self._prev.text.upper() if direction else "FIRST"
3352
3353            count = self._parse_field(tokens=self.FETCH_TOKENS)
3354            percent = self._match(TokenType.PERCENT)
3355
3356            self._match_set((TokenType.ROW, TokenType.ROWS))
3357
3358            only = self._match_text_seq("ONLY")
3359            with_ties = self._match_text_seq("WITH", "TIES")
3360
3361            if only and with_ties:
3362                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3363
3364            return self.expression(
3365                exp.Fetch,
3366                direction=direction,
3367                count=count,
3368                percent=percent,
3369                with_ties=with_ties,
3370            )
3371
3372        return this
3373
3374    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3375        if not self._match(TokenType.OFFSET):
3376            return this
3377
3378        count = self._parse_term()
3379        self._match_set((TokenType.ROW, TokenType.ROWS))
3380        return self.expression(exp.Offset, this=this, expression=count)
3381
3382    def _parse_locks(self) -> t.List[exp.Lock]:
3383        locks = []
3384        while True:
3385            if self._match_text_seq("FOR", "UPDATE"):
3386                update = True
3387            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3388                "LOCK", "IN", "SHARE", "MODE"
3389            ):
3390                update = False
3391            else:
3392                break
3393
3394            expressions = None
3395            if self._match_text_seq("OF"):
3396                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3397
3398            wait: t.Optional[bool | exp.Expression] = None
3399            if self._match_text_seq("NOWAIT"):
3400                wait = True
3401            elif self._match_text_seq("WAIT"):
3402                wait = self._parse_primary()
3403            elif self._match_text_seq("SKIP", "LOCKED"):
3404                wait = False
3405
3406            locks.append(
3407                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3408            )
3409
3410        return locks
3411
3412    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3413        while this and self._match_set(self.SET_OPERATIONS):
3414            token_type = self._prev.token_type
3415
3416            if token_type == TokenType.UNION:
3417                operation = exp.Union
3418            elif token_type == TokenType.EXCEPT:
3419                operation = exp.Except
3420            else:
3421                operation = exp.Intersect
3422
3423            comments = self._prev.comments
3424            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3425            by_name = self._match_text_seq("BY", "NAME")
3426            expression = self._parse_select(nested=True, parse_set_operation=False)
3427
3428            this = self.expression(
3429                operation,
3430                comments=comments,
3431                this=this,
3432                distinct=distinct,
3433                by_name=by_name,
3434                expression=expression,
3435            )
3436
3437        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3438            expression = this.expression
3439
3440            if expression:
3441                for arg in self.UNION_MODIFIERS:
3442                    expr = expression.args.get(arg)
3443                    if expr:
3444                        this.set(arg, expr.pop())
3445
3446        return this
3447
3448    def _parse_expression(self) -> t.Optional[exp.Expression]:
3449        return self._parse_alias(self._parse_conjunction())
3450
3451    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3452        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3453
3454    def _parse_equality(self) -> t.Optional[exp.Expression]:
3455        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3456
3457    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3458        return self._parse_tokens(self._parse_range, self.COMPARISON)
3459
3460    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3461        this = this or self._parse_bitwise()
3462        negate = self._match(TokenType.NOT)
3463
3464        if self._match_set(self.RANGE_PARSERS):
3465            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3466            if not expression:
3467                return this
3468
3469            this = expression
3470        elif self._match(TokenType.ISNULL):
3471            this = self.expression(exp.Is, this=this, expression=exp.Null())
3472
3473        # Postgres supports ISNULL and NOTNULL for conditions.
3474        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3475        if self._match(TokenType.NOTNULL):
3476            this = self.expression(exp.Is, this=this, expression=exp.Null())
3477            this = self.expression(exp.Not, this=this)
3478
3479        if negate:
3480            this = self.expression(exp.Not, this=this)
3481
3482        if self._match(TokenType.IS):
3483            this = self._parse_is(this)
3484
3485        return this
3486
3487    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3488        index = self._index - 1
3489        negate = self._match(TokenType.NOT)
3490
3491        if self._match_text_seq("DISTINCT", "FROM"):
3492            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3493            return self.expression(klass, this=this, expression=self._parse_conjunction())
3494
3495        expression = self._parse_null() or self._parse_boolean()
3496        if not expression:
3497            self._retreat(index)
3498            return None
3499
3500        this = self.expression(exp.Is, this=this, expression=expression)
3501        return self.expression(exp.Not, this=this) if negate else this
3502
3503    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3504        unnest = self._parse_unnest(with_alias=False)
3505        if unnest:
3506            this = self.expression(exp.In, this=this, unnest=unnest)
3507        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3508            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3509            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3510
3511            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
3512                this = self.expression(exp.In, this=this, query=expressions[0])
3513            else:
3514                this = self.expression(exp.In, this=this, expressions=expressions)
3515
3516            if matched_l_paren:
3517                self._match_r_paren(this)
3518            elif not self._match(TokenType.R_BRACKET, expression=this):
3519                self.raise_error("Expecting ]")
3520        else:
3521            this = self.expression(exp.In, this=this, field=self._parse_field())
3522
3523        return this
3524
3525    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3526        low = self._parse_bitwise()
3527        self._match(TokenType.AND)
3528        high = self._parse_bitwise()
3529        return self.expression(exp.Between, this=this, low=low, high=high)
3530
3531    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3532        if not self._match(TokenType.ESCAPE):
3533            return this
3534        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3535
3536    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3537        index = self._index
3538
3539        if not self._match(TokenType.INTERVAL) and match_interval:
3540            return None
3541
3542        if self._match(TokenType.STRING, advance=False):
3543            this = self._parse_primary()
3544        else:
3545            this = self._parse_term()
3546
3547        if not this or (
3548            isinstance(this, exp.Column)
3549            and not this.table
3550            and not this.this.quoted
3551            and this.name.upper() == "IS"
3552        ):
3553            self._retreat(index)
3554            return None
3555
3556        unit = self._parse_function() or (
3557            not self._match(TokenType.ALIAS, advance=False)
3558            and self._parse_var(any_token=True, upper=True)
3559        )
3560
3561        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3562        # each INTERVAL expression into this canonical form so it's easy to transpile
3563        if this and this.is_number:
3564            this = exp.Literal.string(this.name)
3565        elif this and this.is_string:
3566            parts = this.name.split()
3567
3568            if len(parts) == 2:
3569                if unit:
3570                    # This is not actually a unit, it's something else (e.g. a "window side")
3571                    unit = None
3572                    self._retreat(self._index - 1)
3573
3574                this = exp.Literal.string(parts[0])
3575                unit = self.expression(exp.Var, this=parts[1].upper())
3576
3577        return self.expression(exp.Interval, this=this, unit=unit)
3578
3579    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3580        this = self._parse_term()
3581
3582        while True:
3583            if self._match_set(self.BITWISE):
3584                this = self.expression(
3585                    self.BITWISE[self._prev.token_type],
3586                    this=this,
3587                    expression=self._parse_term(),
3588                )
3589            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3590                this = self.expression(
3591                    exp.DPipe,
3592                    this=this,
3593                    expression=self._parse_term(),
3594                    safe=not self.dialect.STRICT_STRING_CONCAT,
3595                )
3596            elif self._match(TokenType.DQMARK):
3597                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3598            elif self._match_pair(TokenType.LT, TokenType.LT):
3599                this = self.expression(
3600                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3601                )
3602            elif self._match_pair(TokenType.GT, TokenType.GT):
3603                this = self.expression(
3604                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3605                )
3606            else:
3607                break
3608
3609        return this
3610
3611    def _parse_term(self) -> t.Optional[exp.Expression]:
3612        return self._parse_tokens(self._parse_factor, self.TERM)
3613
3614    def _parse_factor(self) -> t.Optional[exp.Expression]:
3615        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
3616        this = parse_method()
3617
3618        while self._match_set(self.FACTOR):
3619            this = self.expression(
3620                self.FACTOR[self._prev.token_type],
3621                this=this,
3622                comments=self._prev_comments,
3623                expression=parse_method(),
3624            )
3625            if isinstance(this, exp.Div):
3626                this.args["typed"] = self.dialect.TYPED_DIVISION
3627                this.args["safe"] = self.dialect.SAFE_DIVISION
3628
3629        return this
3630
3631    def _parse_exponent(self) -> t.Optional[exp.Expression]:
3632        return self._parse_tokens(self._parse_unary, self.EXPONENT)
3633
3634    def _parse_unary(self) -> t.Optional[exp.Expression]:
3635        if self._match_set(self.UNARY_PARSERS):
3636            return self.UNARY_PARSERS[self._prev.token_type](self)
3637        return self._parse_at_time_zone(self._parse_type())
3638
3639    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
3640        interval = parse_interval and self._parse_interval()
3641        if interval:
3642            # Convert INTERVAL 'val_1' unit_1 ... 'val_n' unit_n into a sum of intervals
3643            while self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
3644                interval = self.expression(  # type: ignore
3645                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
3646                )
3647
3648            return interval
3649
3650        index = self._index
3651        data_type = self._parse_types(check_func=True, allow_identifiers=False)
3652        this = self._parse_column()
3653
3654        if data_type:
3655            if isinstance(this, exp.Literal):
3656                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
3657                if parser:
3658                    return parser(self, this, data_type)
3659                return self.expression(exp.Cast, this=this, to=data_type)
3660            if not data_type.expressions:
3661                self._retreat(index)
3662                return self._parse_column()
3663            return self._parse_column_ops(data_type)
3664
3665        return this and self._parse_column_ops(this)
3666
3667    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
3668        this = self._parse_type()
3669        if not this:
3670            return None
3671
3672        return self.expression(
3673            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
3674        )
3675
3676    def _parse_types(
3677        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
3678    ) -> t.Optional[exp.Expression]:
3679        index = self._index
3680
3681        prefix = self._match_text_seq("SYSUDTLIB", ".")
3682
3683        if not self._match_set(self.TYPE_TOKENS):
3684            identifier = allow_identifiers and self._parse_id_var(
3685                any_token=False, tokens=(TokenType.VAR,)
3686            )
3687            if identifier:
3688                tokens = self.dialect.tokenize(identifier.name)
3689
3690                if len(tokens) != 1:
3691                    self.raise_error("Unexpected identifier", self._prev)
3692
3693                if tokens[0].token_type in self.TYPE_TOKENS:
3694                    self._prev = tokens[0]
3695                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
3696                    type_name = identifier.name
3697
3698                    while self._match(TokenType.DOT):
3699                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
3700
3701                    return exp.DataType.build(type_name, udt=True)
3702                else:
3703                    self._retreat(self._index - 1)
3704                    return None
3705            else:
3706                return None
3707
3708        type_token = self._prev.token_type
3709
3710        if type_token == TokenType.PSEUDO_TYPE:
3711            return self.expression(exp.PseudoType, this=self._prev.text.upper())
3712
3713        if type_token == TokenType.OBJECT_IDENTIFIER:
3714            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
3715
3716        nested = type_token in self.NESTED_TYPE_TOKENS
3717        is_struct = type_token in self.STRUCT_TYPE_TOKENS
3718        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
3719        expressions = None
3720        maybe_func = False
3721
3722        if self._match(TokenType.L_PAREN):
3723            if is_struct:
3724                expressions = self._parse_csv(self._parse_struct_types)
3725            elif nested:
3726                expressions = self._parse_csv(
3727                    lambda: self._parse_types(
3728                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3729                    )
3730                )
3731            elif type_token in self.ENUM_TYPE_TOKENS:
3732                expressions = self._parse_csv(self._parse_equality)
3733            elif is_aggregate:
3734                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
3735                    any_token=False, tokens=(TokenType.VAR,)
3736                )
3737                if not func_or_ident or not self._match(TokenType.COMMA):
3738                    return None
3739                expressions = self._parse_csv(
3740                    lambda: self._parse_types(
3741                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3742                    )
3743                )
3744                expressions.insert(0, func_or_ident)
3745            else:
3746                expressions = self._parse_csv(self._parse_type_size)
3747
3748            if not expressions or not self._match(TokenType.R_PAREN):
3749                self._retreat(index)
3750                return None
3751
3752            maybe_func = True
3753
3754        this: t.Optional[exp.Expression] = None
3755        values: t.Optional[t.List[exp.Expression]] = None
3756
3757        if nested and self._match(TokenType.LT):
3758            if is_struct:
3759                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
3760            else:
3761                expressions = self._parse_csv(
3762                    lambda: self._parse_types(
3763                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3764                    )
3765                )
3766
3767            if not self._match(TokenType.GT):
3768                self.raise_error("Expecting >")
3769
3770            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
3771                values = self._parse_csv(self._parse_conjunction)
3772                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
3773
3774        if type_token in self.TIMESTAMPS:
3775            if self._match_text_seq("WITH", "TIME", "ZONE"):
3776                maybe_func = False
3777                tz_type = (
3778                    exp.DataType.Type.TIMETZ
3779                    if type_token in self.TIMES
3780                    else exp.DataType.Type.TIMESTAMPTZ
3781                )
3782                this = exp.DataType(this=tz_type, expressions=expressions)
3783            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
3784                maybe_func = False
3785                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
3786            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
3787                maybe_func = False
3788        elif type_token == TokenType.INTERVAL:
3789            unit = self._parse_var()
3790
3791            if self._match_text_seq("TO"):
3792                span = [exp.IntervalSpan(this=unit, expression=self._parse_var())]
3793            else:
3794                span = None
3795
3796            if span or not unit:
3797                this = self.expression(
3798                    exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
3799                )
3800            else:
3801                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
3802
3803        if maybe_func and check_func:
3804            index2 = self._index
3805            peek = self._parse_string()
3806
3807            if not peek:
3808                self._retreat(index)
3809                return None
3810
3811            self._retreat(index2)
3812
3813        if not this:
3814            if self._match_text_seq("UNSIGNED"):
3815                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
3816                if not unsigned_type_token:
3817                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
3818
3819                type_token = unsigned_type_token or type_token
3820
3821            this = exp.DataType(
3822                this=exp.DataType.Type[type_token.value],
3823                expressions=expressions,
3824                nested=nested,
3825                values=values,
3826                prefix=prefix,
3827            )
3828
3829        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
3830            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
3831
3832        return this
3833
3834    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
3835        index = self._index
3836        this = self._parse_type(parse_interval=False) or self._parse_id_var()
3837        self._match(TokenType.COLON)
3838        column_def = self._parse_column_def(this)
3839
3840        if type_required and (
3841            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
3842        ):
3843            self._retreat(index)
3844            return self._parse_types()
3845
3846        return column_def
3847
3848    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3849        if not self._match_text_seq("AT", "TIME", "ZONE"):
3850            return this
3851        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
3852
3853    def _parse_column(self) -> t.Optional[exp.Expression]:
3854        this = self._parse_column_reference()
3855        return self._parse_column_ops(this) if this else self._parse_bracket(this)
3856
3857    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
3858        this = self._parse_field()
3859        if isinstance(this, exp.Identifier):
3860            this = self.expression(exp.Column, this=this)
3861        return this
3862
3863    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3864        this = self._parse_bracket(this)
3865
3866        while self._match_set(self.COLUMN_OPERATORS):
3867            op_token = self._prev.token_type
3868            op = self.COLUMN_OPERATORS.get(op_token)
3869
3870            if op_token == TokenType.DCOLON:
3871                field = self._parse_types()
3872                if not field:
3873                    self.raise_error("Expected type")
3874            elif op and self._curr:
3875                field = self._parse_column_reference()
3876            else:
3877                field = self._parse_field(anonymous_func=True, any_token=True)
3878
3879            if isinstance(field, exp.Func):
3880                # bigquery allows function calls like x.y.count(...)
3881                # SAFE.SUBSTR(...)
3882                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
3883                this = self._replace_columns_with_dots(this)
3884
3885            if op:
3886                this = op(self, this, field)
3887            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
3888                this = self.expression(
3889                    exp.Column,
3890                    this=field,
3891                    table=this.this,
3892                    db=this.args.get("table"),
3893                    catalog=this.args.get("db"),
3894                )
3895            else:
3896                this = self.expression(exp.Dot, this=this, expression=field)
3897            this = self._parse_bracket(this)
3898        return this
3899
3900    def _parse_primary(self) -> t.Optional[exp.Expression]:
3901        if self._match_set(self.PRIMARY_PARSERS):
3902            token_type = self._prev.token_type
3903            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
3904
3905            if token_type == TokenType.STRING:
3906                expressions = [primary]
3907                while self._match(TokenType.STRING):
3908                    expressions.append(exp.Literal.string(self._prev.text))
3909
3910                if len(expressions) > 1:
3911                    return self.expression(exp.Concat, expressions=expressions)
3912
3913            return primary
3914
3915        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
3916            return exp.Literal.number(f"0.{self._prev.text}")
3917
3918        if self._match(TokenType.L_PAREN):
3919            comments = self._prev_comments
3920            query = self._parse_select()
3921
3922            if query:
3923                expressions = [query]
3924            else:
3925                expressions = self._parse_expressions()
3926
3927            this = self._parse_query_modifiers(seq_get(expressions, 0))
3928
3929            if isinstance(this, exp.Subqueryable):
3930                this = self._parse_set_operations(
3931                    self._parse_subquery(this=this, parse_alias=False)
3932                )
3933            elif len(expressions) > 1:
3934                this = self.expression(exp.Tuple, expressions=expressions)
3935            else:
3936                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
3937
3938            if this:
3939                this.add_comments(comments)
3940
3941            self._match_r_paren(expression=this)
3942            return this
3943
3944        return None
3945
3946    def _parse_field(
3947        self,
3948        any_token: bool = False,
3949        tokens: t.Optional[t.Collection[TokenType]] = None,
3950        anonymous_func: bool = False,
3951    ) -> t.Optional[exp.Expression]:
3952        return (
3953            self._parse_primary()
3954            or self._parse_function(anonymous=anonymous_func)
3955            or self._parse_id_var(any_token=any_token, tokens=tokens)
3956        )
3957
3958    def _parse_function(
3959        self,
3960        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3961        anonymous: bool = False,
3962        optional_parens: bool = True,
3963    ) -> t.Optional[exp.Expression]:
3964        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
3965        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
3966        fn_syntax = False
3967        if (
3968            self._match(TokenType.L_BRACE, advance=False)
3969            and self._next
3970            and self._next.text.upper() == "FN"
3971        ):
3972            self._advance(2)
3973            fn_syntax = True
3974
3975        func = self._parse_function_call(
3976            functions=functions, anonymous=anonymous, optional_parens=optional_parens
3977        )
3978
3979        if fn_syntax:
3980            self._match(TokenType.R_BRACE)
3981
3982        return func
3983
3984    def _parse_function_call(
3985        self,
3986        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3987        anonymous: bool = False,
3988        optional_parens: bool = True,
3989    ) -> t.Optional[exp.Expression]:
3990        if not self._curr:
3991            return None
3992
3993        comments = self._curr.comments
3994        token_type = self._curr.token_type
3995        this = self._curr.text
3996        upper = this.upper()
3997
3998        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
3999        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4000            self._advance()
4001            return parser(self)
4002
4003        if not self._next or self._next.token_type != TokenType.L_PAREN:
4004            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4005                self._advance()
4006                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4007
4008            return None
4009
4010        if token_type not in self.FUNC_TOKENS:
4011            return None
4012
4013        self._advance(2)
4014
4015        parser = self.FUNCTION_PARSERS.get(upper)
4016        if parser and not anonymous:
4017            this = parser(self)
4018        else:
4019            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4020
4021            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4022                this = self.expression(subquery_predicate, this=self._parse_select())
4023                self._match_r_paren()
4024                return this
4025
4026            if functions is None:
4027                functions = self.FUNCTIONS
4028
4029            function = functions.get(upper)
4030
4031            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4032            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4033
4034            if function and not anonymous:
4035                if "dialect" in function.__code__.co_varnames:
4036                    func = function(args, dialect=self.dialect)
4037                else:
4038                    func = function(args)
4039
4040                func = self.validate_expression(func, args)
4041                if not self.dialect.NORMALIZE_FUNCTIONS:
4042                    func.meta["name"] = this
4043
4044                this = func
4045            else:
4046                this = self.expression(exp.Anonymous, this=this, expressions=args)
4047
4048        if isinstance(this, exp.Expression):
4049            this.add_comments(comments)
4050
4051        self._match_r_paren(this)
4052        return self._parse_window(this)
4053
4054    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4055        return self._parse_column_def(self._parse_id_var())
4056
4057    def _parse_user_defined_function(
4058        self, kind: t.Optional[TokenType] = None
4059    ) -> t.Optional[exp.Expression]:
4060        this = self._parse_id_var()
4061
4062        while self._match(TokenType.DOT):
4063            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4064
4065        if not self._match(TokenType.L_PAREN):
4066            return this
4067
4068        expressions = self._parse_csv(self._parse_function_parameter)
4069        self._match_r_paren()
4070        return self.expression(
4071            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4072        )
4073
4074    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4075        literal = self._parse_primary()
4076        if literal:
4077            return self.expression(exp.Introducer, this=token.text, expression=literal)
4078
4079        return self.expression(exp.Identifier, this=token.text)
4080
4081    def _parse_session_parameter(self) -> exp.SessionParameter:
4082        kind = None
4083        this = self._parse_id_var() or self._parse_primary()
4084
4085        if this and self._match(TokenType.DOT):
4086            kind = this.name
4087            this = self._parse_var() or self._parse_primary()
4088
4089        return self.expression(exp.SessionParameter, this=this, kind=kind)
4090
4091    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4092        index = self._index
4093
4094        if self._match(TokenType.L_PAREN):
4095            expressions = t.cast(
4096                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4097            )
4098
4099            if not self._match(TokenType.R_PAREN):
4100                self._retreat(index)
4101        else:
4102            expressions = [self._parse_id_var()]
4103
4104        if self._match_set(self.LAMBDAS):
4105            return self.LAMBDAS[self._prev.token_type](self, expressions)
4106
4107        self._retreat(index)
4108
4109        this: t.Optional[exp.Expression]
4110
4111        if self._match(TokenType.DISTINCT):
4112            this = self.expression(
4113                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4114            )
4115        else:
4116            this = self._parse_select_or_expression(alias=alias)
4117
4118        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
4119
4120    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4121        index = self._index
4122
4123        if not self.errors:
4124            try:
4125                if self._parse_select(nested=True):
4126                    return this
4127            except ParseError:
4128                pass
4129            finally:
4130                self.errors.clear()
4131                self._retreat(index)
4132
4133        if not self._match(TokenType.L_PAREN):
4134            return this
4135
4136        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4137
4138        self._match_r_paren()
4139        return self.expression(exp.Schema, this=this, expressions=args)
4140
4141    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4142        return self._parse_column_def(self._parse_field(any_token=True))
4143
4144    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4145        # column defs are not really columns, they're identifiers
4146        if isinstance(this, exp.Column):
4147            this = this.this
4148
4149        kind = self._parse_types(schema=True)
4150
4151        if self._match_text_seq("FOR", "ORDINALITY"):
4152            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4153
4154        constraints: t.List[exp.Expression] = []
4155
4156        if not kind and self._match(TokenType.ALIAS):
4157            constraints.append(
4158                self.expression(
4159                    exp.ComputedColumnConstraint,
4160                    this=self._parse_conjunction(),
4161                    persisted=self._match_text_seq("PERSISTED"),
4162                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4163                )
4164            )
4165        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4166            self._match(TokenType.ALIAS)
4167            constraints.append(
4168                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4169            )
4170
4171        while True:
4172            constraint = self._parse_column_constraint()
4173            if not constraint:
4174                break
4175            constraints.append(constraint)
4176
4177        if not kind and not constraints:
4178            return this
4179
4180        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4181
4182    def _parse_auto_increment(
4183        self,
4184    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4185        start = None
4186        increment = None
4187
4188        if self._match(TokenType.L_PAREN, advance=False):
4189            args = self._parse_wrapped_csv(self._parse_bitwise)
4190            start = seq_get(args, 0)
4191            increment = seq_get(args, 1)
4192        elif self._match_text_seq("START"):
4193            start = self._parse_bitwise()
4194            self._match_text_seq("INCREMENT")
4195            increment = self._parse_bitwise()
4196
4197        if start and increment:
4198            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4199
4200        return exp.AutoIncrementColumnConstraint()
4201
4202    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4203        if not self._match_text_seq("REFRESH"):
4204            self._retreat(self._index - 1)
4205            return None
4206        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4207
4208    def _parse_compress(self) -> exp.CompressColumnConstraint:
4209        if self._match(TokenType.L_PAREN, advance=False):
4210            return self.expression(
4211                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4212            )
4213
4214        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4215
4216    def _parse_generated_as_identity(
4217        self,
4218    ) -> (
4219        exp.GeneratedAsIdentityColumnConstraint
4220        | exp.ComputedColumnConstraint
4221        | exp.GeneratedAsRowColumnConstraint
4222    ):
4223        if self._match_text_seq("BY", "DEFAULT"):
4224            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4225            this = self.expression(
4226                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4227            )
4228        else:
4229            self._match_text_seq("ALWAYS")
4230            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4231
4232        self._match(TokenType.ALIAS)
4233
4234        if self._match_text_seq("ROW"):
4235            start = self._match_text_seq("START")
4236            if not start:
4237                self._match(TokenType.END)
4238            hidden = self._match_text_seq("HIDDEN")
4239            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4240
4241        identity = self._match_text_seq("IDENTITY")
4242
4243        if self._match(TokenType.L_PAREN):
4244            if self._match(TokenType.START_WITH):
4245                this.set("start", self._parse_bitwise())
4246            if self._match_text_seq("INCREMENT", "BY"):
4247                this.set("increment", self._parse_bitwise())
4248            if self._match_text_seq("MINVALUE"):
4249                this.set("minvalue", self._parse_bitwise())
4250            if self._match_text_seq("MAXVALUE"):
4251                this.set("maxvalue", self._parse_bitwise())
4252
4253            if self._match_text_seq("CYCLE"):
4254                this.set("cycle", True)
4255            elif self._match_text_seq("NO", "CYCLE"):
4256                this.set("cycle", False)
4257
4258            if not identity:
4259                this.set("expression", self._parse_bitwise())
4260            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4261                args = self._parse_csv(self._parse_bitwise)
4262                this.set("start", seq_get(args, 0))
4263                this.set("increment", seq_get(args, 1))
4264
4265            self._match_r_paren()
4266
4267        return this
4268
4269    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4270        self._match_text_seq("LENGTH")
4271        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4272
4273    def _parse_not_constraint(
4274        self,
4275    ) -> t.Optional[exp.Expression]:
4276        if self._match_text_seq("NULL"):
4277            return self.expression(exp.NotNullColumnConstraint)
4278        if self._match_text_seq("CASESPECIFIC"):
4279            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4280        if self._match_text_seq("FOR", "REPLICATION"):
4281            return self.expression(exp.NotForReplicationColumnConstraint)
4282        return None
4283
4284    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4285        if self._match(TokenType.CONSTRAINT):
4286            this = self._parse_id_var()
4287        else:
4288            this = None
4289
4290        if self._match_texts(self.CONSTRAINT_PARSERS):
4291            return self.expression(
4292                exp.ColumnConstraint,
4293                this=this,
4294                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4295            )
4296
4297        return this
4298
4299    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4300        if not self._match(TokenType.CONSTRAINT):
4301            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4302
4303        this = self._parse_id_var()
4304        expressions = []
4305
4306        while True:
4307            constraint = self._parse_unnamed_constraint() or self._parse_function()
4308            if not constraint:
4309                break
4310            expressions.append(constraint)
4311
4312        return self.expression(exp.Constraint, this=this, expressions=expressions)
4313
4314    def _parse_unnamed_constraint(
4315        self, constraints: t.Optional[t.Collection[str]] = None
4316    ) -> t.Optional[exp.Expression]:
4317        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4318            constraints or self.CONSTRAINT_PARSERS
4319        ):
4320            return None
4321
4322        constraint = self._prev.text.upper()
4323        if constraint not in self.CONSTRAINT_PARSERS:
4324            self.raise_error(f"No parser found for schema constraint {constraint}.")
4325
4326        return self.CONSTRAINT_PARSERS[constraint](self)
4327
4328    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4329        self._match_text_seq("KEY")
4330        return self.expression(
4331            exp.UniqueColumnConstraint,
4332            this=self._parse_schema(self._parse_id_var(any_token=False)),
4333            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4334        )
4335
4336    def _parse_key_constraint_options(self) -> t.List[str]:
4337        options = []
4338        while True:
4339            if not self._curr:
4340                break
4341
4342            if self._match(TokenType.ON):
4343                action = None
4344                on = self._advance_any() and self._prev.text
4345
4346                if self._match_text_seq("NO", "ACTION"):
4347                    action = "NO ACTION"
4348                elif self._match_text_seq("CASCADE"):
4349                    action = "CASCADE"
4350                elif self._match_text_seq("RESTRICT"):
4351                    action = "RESTRICT"
4352                elif self._match_pair(TokenType.SET, TokenType.NULL):
4353                    action = "SET NULL"
4354                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4355                    action = "SET DEFAULT"
4356                else:
4357                    self.raise_error("Invalid key constraint")
4358
4359                options.append(f"ON {on} {action}")
4360            elif self._match_text_seq("NOT", "ENFORCED"):
4361                options.append("NOT ENFORCED")
4362            elif self._match_text_seq("DEFERRABLE"):
4363                options.append("DEFERRABLE")
4364            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4365                options.append("INITIALLY DEFERRED")
4366            elif self._match_text_seq("NORELY"):
4367                options.append("NORELY")
4368            elif self._match_text_seq("MATCH", "FULL"):
4369                options.append("MATCH FULL")
4370            else:
4371                break
4372
4373        return options
4374
4375    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4376        if match and not self._match(TokenType.REFERENCES):
4377            return None
4378
4379        expressions = None
4380        this = self._parse_table(schema=True)
4381        options = self._parse_key_constraint_options()
4382        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4383
4384    def _parse_foreign_key(self) -> exp.ForeignKey:
4385        expressions = self._parse_wrapped_id_vars()
4386        reference = self._parse_references()
4387        options = {}
4388
4389        while self._match(TokenType.ON):
4390            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4391                self.raise_error("Expected DELETE or UPDATE")
4392
4393            kind = self._prev.text.lower()
4394
4395            if self._match_text_seq("NO", "ACTION"):
4396                action = "NO ACTION"
4397            elif self._match(TokenType.SET):
4398                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4399                action = "SET " + self._prev.text.upper()
4400            else:
4401                self._advance()
4402                action = self._prev.text.upper()
4403
4404            options[kind] = action
4405
4406        return self.expression(
4407            exp.ForeignKey,
4408            expressions=expressions,
4409            reference=reference,
4410            **options,  # type: ignore
4411        )
4412
4413    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4414        return self._parse_field()
4415
4416    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4417        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4418            self._retreat(self._index - 1)
4419            return None
4420
4421        id_vars = self._parse_wrapped_id_vars()
4422        return self.expression(
4423            exp.PeriodForSystemTimeConstraint,
4424            this=seq_get(id_vars, 0),
4425            expression=seq_get(id_vars, 1),
4426        )
4427
4428    def _parse_primary_key(
4429        self, wrapped_optional: bool = False, in_props: bool = False
4430    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4431        desc = (
4432            self._match_set((TokenType.ASC, TokenType.DESC))
4433            and self._prev.token_type == TokenType.DESC
4434        )
4435
4436        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4437            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4438
4439        expressions = self._parse_wrapped_csv(
4440            self._parse_primary_key_part, optional=wrapped_optional
4441        )
4442        options = self._parse_key_constraint_options()
4443        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4444
4445    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4446        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4447
4448    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4449        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4450            return this
4451
4452        bracket_kind = self._prev.token_type
4453        expressions = self._parse_csv(
4454            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4455        )
4456
4457        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
4458            self.raise_error("Expected ]")
4459        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
4460            self.raise_error("Expected }")
4461
4462        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4463        if bracket_kind == TokenType.L_BRACE:
4464            this = self.expression(exp.Struct, expressions=expressions)
4465        elif not this or this.name.upper() == "ARRAY":
4466            this = self.expression(exp.Array, expressions=expressions)
4467        else:
4468            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4469            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4470
4471        self._add_comments(this)
4472        return self._parse_bracket(this)
4473
4474    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4475        if self._match(TokenType.COLON):
4476            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4477        return this
4478
4479    def _parse_case(self) -> t.Optional[exp.Expression]:
4480        ifs = []
4481        default = None
4482
4483        comments = self._prev_comments
4484        expression = self._parse_conjunction()
4485
4486        while self._match(TokenType.WHEN):
4487            this = self._parse_conjunction()
4488            self._match(TokenType.THEN)
4489            then = self._parse_conjunction()
4490            ifs.append(self.expression(exp.If, this=this, true=then))
4491
4492        if self._match(TokenType.ELSE):
4493            default = self._parse_conjunction()
4494
4495        if not self._match(TokenType.END):
4496            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4497                default = exp.column("interval")
4498            else:
4499                self.raise_error("Expected END after CASE", self._prev)
4500
4501        return self._parse_window(
4502            self.expression(exp.Case, comments=comments, this=expression, ifs=ifs, default=default)
4503        )
4504
4505    def _parse_if(self) -> t.Optional[exp.Expression]:
4506        if self._match(TokenType.L_PAREN):
4507            args = self._parse_csv(self._parse_conjunction)
4508            this = self.validate_expression(exp.If.from_arg_list(args), args)
4509            self._match_r_paren()
4510        else:
4511            index = self._index - 1
4512
4513            if self.NO_PAREN_IF_COMMANDS and index == 0:
4514                return self._parse_as_command(self._prev)
4515
4516            condition = self._parse_conjunction()
4517
4518            if not condition:
4519                self._retreat(index)
4520                return None
4521
4522            self._match(TokenType.THEN)
4523            true = self._parse_conjunction()
4524            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4525            self._match(TokenType.END)
4526            this = self.expression(exp.If, this=condition, true=true, false=false)
4527
4528        return self._parse_window(this)
4529
4530    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4531        if not self._match_text_seq("VALUE", "FOR"):
4532            self._retreat(self._index - 1)
4533            return None
4534
4535        return self.expression(
4536            exp.NextValueFor,
4537            this=self._parse_column(),
4538            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4539        )
4540
4541    def _parse_extract(self) -> exp.Extract:
4542        this = self._parse_function() or self._parse_var() or self._parse_type()
4543
4544        if self._match(TokenType.FROM):
4545            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4546
4547        if not self._match(TokenType.COMMA):
4548            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4549
4550        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4551
4552    def _parse_any_value(self) -> exp.AnyValue:
4553        this = self._parse_lambda()
4554        is_max = None
4555        having = None
4556
4557        if self._match(TokenType.HAVING):
4558            self._match_texts(("MAX", "MIN"))
4559            is_max = self._prev.text == "MAX"
4560            having = self._parse_column()
4561
4562        return self.expression(exp.AnyValue, this=this, having=having, max=is_max)
4563
4564    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4565        this = self._parse_conjunction()
4566
4567        if not self._match(TokenType.ALIAS):
4568            if self._match(TokenType.COMMA):
4569                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
4570
4571            self.raise_error("Expected AS after CAST")
4572
4573        fmt = None
4574        to = self._parse_types()
4575
4576        if self._match(TokenType.FORMAT):
4577            fmt_string = self._parse_string()
4578            fmt = self._parse_at_time_zone(fmt_string)
4579
4580            if not to:
4581                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
4582            if to.this in exp.DataType.TEMPORAL_TYPES:
4583                this = self.expression(
4584                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
4585                    this=this,
4586                    format=exp.Literal.string(
4587                        format_time(
4588                            fmt_string.this if fmt_string else "",
4589                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
4590                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
4591                        )
4592                    ),
4593                )
4594
4595                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
4596                    this.set("zone", fmt.args["zone"])
4597                return this
4598        elif not to:
4599            self.raise_error("Expected TYPE after CAST")
4600        elif isinstance(to, exp.Identifier):
4601            to = exp.DataType.build(to.name, udt=True)
4602        elif to.this == exp.DataType.Type.CHAR:
4603            if self._match(TokenType.CHARACTER_SET):
4604                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
4605
4606        return self.expression(
4607            exp.Cast if strict else exp.TryCast, this=this, to=to, format=fmt, safe=safe
4608        )
4609
4610    def _parse_string_agg(self) -> exp.Expression:
4611        if self._match(TokenType.DISTINCT):
4612            args: t.List[t.Optional[exp.Expression]] = [
4613                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
4614            ]
4615            if self._match(TokenType.COMMA):
4616                args.extend(self._parse_csv(self._parse_conjunction))
4617        else:
4618            args = self._parse_csv(self._parse_conjunction)  # type: ignore
4619
4620        index = self._index
4621        if not self._match(TokenType.R_PAREN) and args:
4622            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
4623            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
4624            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
4625            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
4626
4627        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
4628        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
4629        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
4630        if not self._match_text_seq("WITHIN", "GROUP"):
4631            self._retreat(index)
4632            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
4633
4634        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
4635        order = self._parse_order(this=seq_get(args, 0))
4636        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
4637
4638    def _parse_convert(
4639        self, strict: bool, safe: t.Optional[bool] = None
4640    ) -> t.Optional[exp.Expression]:
4641        this = self._parse_bitwise()
4642
4643        if self._match(TokenType.USING):
4644            to: t.Optional[exp.Expression] = self.expression(
4645                exp.CharacterSet, this=self._parse_var()
4646            )
4647        elif self._match(TokenType.COMMA):
4648            to = self._parse_types()
4649        else:
4650            to = None
4651
4652        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
4653
4654    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
4655        """
4656        There are generally two variants of the DECODE function:
4657
4658        - DECODE(bin, charset)
4659        - DECODE(expression, search, result [, search, result] ... [, default])
4660
4661        The second variant will always be parsed into a CASE expression. Note that NULL
4662        needs special treatment, since we need to explicitly check for it with `IS NULL`,
4663        instead of relying on pattern matching.
4664        """
4665        args = self._parse_csv(self._parse_conjunction)
4666
4667        if len(args) < 3:
4668            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
4669
4670        expression, *expressions = args
4671        if not expression:
4672            return None
4673
4674        ifs = []
4675        for search, result in zip(expressions[::2], expressions[1::2]):
4676            if not search or not result:
4677                return None
4678
4679            if isinstance(search, exp.Literal):
4680                ifs.append(
4681                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
4682                )
4683            elif isinstance(search, exp.Null):
4684                ifs.append(
4685                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
4686                )
4687            else:
4688                cond = exp.or_(
4689                    exp.EQ(this=expression.copy(), expression=search),
4690                    exp.and_(
4691                        exp.Is(this=expression.copy(), expression=exp.Null()),
4692                        exp.Is(this=search.copy(), expression=exp.Null()),
4693                        copy=False,
4694                    ),
4695                    copy=False,
4696                )
4697                ifs.append(exp.If(this=cond, true=result))
4698
4699        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
4700
4701    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
4702        self._match_text_seq("KEY")
4703        key = self._parse_column()
4704        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
4705        self._match_text_seq("VALUE")
4706        value = self._parse_bitwise()
4707
4708        if not key and not value:
4709            return None
4710        return self.expression(exp.JSONKeyValue, this=key, expression=value)
4711
4712    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4713        if not this or not self._match_text_seq("FORMAT", "JSON"):
4714            return this
4715
4716        return self.expression(exp.FormatJson, this=this)
4717
4718    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
4719        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
4720        for value in values:
4721            if self._match_text_seq(value, "ON", on):
4722                return f"{value} ON {on}"
4723
4724        return None
4725
4726    @t.overload
4727    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject:
4728        ...
4729
4730    @t.overload
4731    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg:
4732        ...
4733
4734    def _parse_json_object(self, agg=False):
4735        star = self._parse_star()
4736        expressions = (
4737            [star]
4738            if star
4739            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
4740        )
4741        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
4742
4743        unique_keys = None
4744        if self._match_text_seq("WITH", "UNIQUE"):
4745            unique_keys = True
4746        elif self._match_text_seq("WITHOUT", "UNIQUE"):
4747            unique_keys = False
4748
4749        self._match_text_seq("KEYS")
4750
4751        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
4752            self._parse_type()
4753        )
4754        encoding = self._match_text_seq("ENCODING") and self._parse_var()
4755
4756        return self.expression(
4757            exp.JSONObjectAgg if agg else exp.JSONObject,
4758            expressions=expressions,
4759            null_handling=null_handling,
4760            unique_keys=unique_keys,
4761            return_type=return_type,
4762            encoding=encoding,
4763        )
4764
4765    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
4766    def _parse_json_column_def(self) -> exp.JSONColumnDef:
4767        if not self._match_text_seq("NESTED"):
4768            this = self._parse_id_var()
4769            kind = self._parse_types(allow_identifiers=False)
4770            nested = None
4771        else:
4772            this = None
4773            kind = None
4774            nested = True
4775
4776        path = self._match_text_seq("PATH") and self._parse_string()
4777        nested_schema = nested and self._parse_json_schema()
4778
4779        return self.expression(
4780            exp.JSONColumnDef,
4781            this=this,
4782            kind=kind,
4783            path=path,
4784            nested_schema=nested_schema,
4785        )
4786
4787    def _parse_json_schema(self) -> exp.JSONSchema:
4788        self._match_text_seq("COLUMNS")
4789        return self.expression(
4790            exp.JSONSchema,
4791            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
4792        )
4793
4794    def _parse_json_table(self) -> exp.JSONTable:
4795        this = self._parse_format_json(self._parse_bitwise())
4796        path = self._match(TokenType.COMMA) and self._parse_string()
4797        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
4798        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
4799        schema = self._parse_json_schema()
4800
4801        return exp.JSONTable(
4802            this=this,
4803            schema=schema,
4804            path=path,
4805            error_handling=error_handling,
4806            empty_handling=empty_handling,
4807        )
4808
4809    def _parse_match_against(self) -> exp.MatchAgainst:
4810        expressions = self._parse_csv(self._parse_column)
4811
4812        self._match_text_seq(")", "AGAINST", "(")
4813
4814        this = self._parse_string()
4815
4816        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
4817            modifier = "IN NATURAL LANGUAGE MODE"
4818            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4819                modifier = f"{modifier} WITH QUERY EXPANSION"
4820        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
4821            modifier = "IN BOOLEAN MODE"
4822        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4823            modifier = "WITH QUERY EXPANSION"
4824        else:
4825            modifier = None
4826
4827        return self.expression(
4828            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
4829        )
4830
4831    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
4832    def _parse_open_json(self) -> exp.OpenJSON:
4833        this = self._parse_bitwise()
4834        path = self._match(TokenType.COMMA) and self._parse_string()
4835
4836        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
4837            this = self._parse_field(any_token=True)
4838            kind = self._parse_types()
4839            path = self._parse_string()
4840            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
4841
4842            return self.expression(
4843                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
4844            )
4845
4846        expressions = None
4847        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
4848            self._match_l_paren()
4849            expressions = self._parse_csv(_parse_open_json_column_def)
4850
4851        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
4852
4853    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
4854        args = self._parse_csv(self._parse_bitwise)
4855
4856        if self._match(TokenType.IN):
4857            return self.expression(
4858                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
4859            )
4860
4861        if haystack_first:
4862            haystack = seq_get(args, 0)
4863            needle = seq_get(args, 1)
4864        else:
4865            needle = seq_get(args, 0)
4866            haystack = seq_get(args, 1)
4867
4868        return self.expression(
4869            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
4870        )
4871
4872    def _parse_predict(self) -> exp.Predict:
4873        self._match_text_seq("MODEL")
4874        this = self._parse_table()
4875
4876        self._match(TokenType.COMMA)
4877        self._match_text_seq("TABLE")
4878
4879        return self.expression(
4880            exp.Predict,
4881            this=this,
4882            expression=self._parse_table(),
4883            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
4884        )
4885
4886    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
4887        args = self._parse_csv(self._parse_table)
4888        return exp.JoinHint(this=func_name.upper(), expressions=args)
4889
4890    def _parse_substring(self) -> exp.Substring:
4891        # Postgres supports the form: substring(string [from int] [for int])
4892        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
4893
4894        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
4895
4896        if self._match(TokenType.FROM):
4897            args.append(self._parse_bitwise())
4898            if self._match(TokenType.FOR):
4899                args.append(self._parse_bitwise())
4900
4901        return self.validate_expression(exp.Substring.from_arg_list(args), args)
4902
4903    def _parse_trim(self) -> exp.Trim:
4904        # https://www.w3resource.com/sql/character-functions/trim.php
4905        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
4906
4907        position = None
4908        collation = None
4909        expression = None
4910
4911        if self._match_texts(self.TRIM_TYPES):
4912            position = self._prev.text.upper()
4913
4914        this = self._parse_bitwise()
4915        if self._match_set((TokenType.FROM, TokenType.COMMA)):
4916            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
4917            expression = self._parse_bitwise()
4918
4919            if invert_order:
4920                this, expression = expression, this
4921
4922        if self._match(TokenType.COLLATE):
4923            collation = self._parse_bitwise()
4924
4925        return self.expression(
4926            exp.Trim, this=this, position=position, expression=expression, collation=collation
4927        )
4928
4929    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
4930        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
4931
4932    def _parse_named_window(self) -> t.Optional[exp.Expression]:
4933        return self._parse_window(self._parse_id_var(), alias=True)
4934
4935    def _parse_respect_or_ignore_nulls(
4936        self, this: t.Optional[exp.Expression]
4937    ) -> t.Optional[exp.Expression]:
4938        if self._match_text_seq("IGNORE", "NULLS"):
4939            return self.expression(exp.IgnoreNulls, this=this)
4940        if self._match_text_seq("RESPECT", "NULLS"):
4941            return self.expression(exp.RespectNulls, this=this)
4942        return this
4943
4944    def _parse_window(
4945        self, this: t.Optional[exp.Expression], alias: bool = False
4946    ) -> t.Optional[exp.Expression]:
4947        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
4948            self._match(TokenType.WHERE)
4949            this = self.expression(
4950                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
4951            )
4952            self._match_r_paren()
4953
4954        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
4955        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
4956        if self._match_text_seq("WITHIN", "GROUP"):
4957            order = self._parse_wrapped(self._parse_order)
4958            this = self.expression(exp.WithinGroup, this=this, expression=order)
4959
4960        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
4961        # Some dialects choose to implement and some do not.
4962        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
4963
4964        # There is some code above in _parse_lambda that handles
4965        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
4966
4967        # The below changes handle
4968        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
4969
4970        # Oracle allows both formats
4971        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
4972        #   and Snowflake chose to do the same for familiarity
4973        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
4974        if isinstance(this, exp.AggFunc):
4975            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
4976
4977            if ignore_respect and ignore_respect is not this:
4978                ignore_respect.replace(ignore_respect.this)
4979                this = self.expression(ignore_respect.__class__, this=this)
4980
4981        this = self._parse_respect_or_ignore_nulls(this)
4982
4983        # bigquery select from window x AS (partition by ...)
4984        if alias:
4985            over = None
4986            self._match(TokenType.ALIAS)
4987        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
4988            return this
4989        else:
4990            over = self._prev.text.upper()
4991
4992        if not self._match(TokenType.L_PAREN):
4993            return self.expression(
4994                exp.Window, this=this, alias=self._parse_id_var(False), over=over
4995            )
4996
4997        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
4998
4999        first = self._match(TokenType.FIRST)
5000        if self._match_text_seq("LAST"):
5001            first = False
5002
5003        partition, order = self._parse_partition_and_order()
5004        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5005
5006        if kind:
5007            self._match(TokenType.BETWEEN)
5008            start = self._parse_window_spec()
5009            self._match(TokenType.AND)
5010            end = self._parse_window_spec()
5011
5012            spec = self.expression(
5013                exp.WindowSpec,
5014                kind=kind,
5015                start=start["value"],
5016                start_side=start["side"],
5017                end=end["value"],
5018                end_side=end["side"],
5019            )
5020        else:
5021            spec = None
5022
5023        self._match_r_paren()
5024
5025        window = self.expression(
5026            exp.Window,
5027            this=this,
5028            partition_by=partition,
5029            order=order,
5030            spec=spec,
5031            alias=window_alias,
5032            over=over,
5033            first=first,
5034        )
5035
5036        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5037        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5038            return self._parse_window(window, alias=alias)
5039
5040        return window
5041
5042    def _parse_partition_and_order(
5043        self,
5044    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5045        return self._parse_partition_by(), self._parse_order()
5046
5047    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5048        self._match(TokenType.BETWEEN)
5049
5050        return {
5051            "value": (
5052                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5053                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5054                or self._parse_bitwise()
5055            ),
5056            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5057        }
5058
5059    def _parse_alias(
5060        self, this: t.Optional[exp.Expression], explicit: bool = False
5061    ) -> t.Optional[exp.Expression]:
5062        any_token = self._match(TokenType.ALIAS)
5063        comments = self._prev_comments
5064
5065        if explicit and not any_token:
5066            return this
5067
5068        if self._match(TokenType.L_PAREN):
5069            aliases = self.expression(
5070                exp.Aliases,
5071                comments=comments,
5072                this=this,
5073                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5074            )
5075            self._match_r_paren(aliases)
5076            return aliases
5077
5078        alias = self._parse_id_var(any_token) or (
5079            self.STRING_ALIASES and self._parse_string_as_identifier()
5080        )
5081
5082        if alias:
5083            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5084            column = this.this
5085
5086            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5087            if not this.comments and column and column.comments:
5088                this.comments = column.comments
5089                column.comments = None
5090
5091        return this
5092
5093    def _parse_id_var(
5094        self,
5095        any_token: bool = True,
5096        tokens: t.Optional[t.Collection[TokenType]] = None,
5097    ) -> t.Optional[exp.Expression]:
5098        identifier = self._parse_identifier()
5099
5100        if identifier:
5101            return identifier
5102
5103        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
5104            quoted = self._prev.token_type == TokenType.STRING
5105            return exp.Identifier(this=self._prev.text, quoted=quoted)
5106
5107        return None
5108
5109    def _parse_string(self) -> t.Optional[exp.Expression]:
5110        if self._match_set((TokenType.STRING, TokenType.RAW_STRING)):
5111            return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
5112        return self._parse_placeholder()
5113
5114    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5115        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5116
5117    def _parse_number(self) -> t.Optional[exp.Expression]:
5118        if self._match(TokenType.NUMBER):
5119            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
5120        return self._parse_placeholder()
5121
5122    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5123        if self._match(TokenType.IDENTIFIER):
5124            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5125        return self._parse_placeholder()
5126
5127    def _parse_var(
5128        self,
5129        any_token: bool = False,
5130        tokens: t.Optional[t.Collection[TokenType]] = None,
5131        upper: bool = False,
5132    ) -> t.Optional[exp.Expression]:
5133        if (
5134            (any_token and self._advance_any())
5135            or self._match(TokenType.VAR)
5136            or (self._match_set(tokens) if tokens else False)
5137        ):
5138            return self.expression(
5139                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5140            )
5141        return self._parse_placeholder()
5142
5143    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5144        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5145            self._advance()
5146            return self._prev
5147        return None
5148
5149    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5150        return self._parse_var() or self._parse_string()
5151
5152    def _parse_null(self) -> t.Optional[exp.Expression]:
5153        if self._match_set(self.NULL_TOKENS):
5154            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5155        return self._parse_placeholder()
5156
5157    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5158        if self._match(TokenType.TRUE):
5159            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5160        if self._match(TokenType.FALSE):
5161            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5162        return self._parse_placeholder()
5163
5164    def _parse_star(self) -> t.Optional[exp.Expression]:
5165        if self._match(TokenType.STAR):
5166            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5167        return self._parse_placeholder()
5168
5169    def _parse_parameter(self) -> exp.Parameter:
5170        def _parse_parameter_part() -> t.Optional[exp.Expression]:
5171            return (
5172                self._parse_identifier() or self._parse_primary() or self._parse_var(any_token=True)
5173            )
5174
5175        self._match(TokenType.L_BRACE)
5176        this = _parse_parameter_part()
5177        expression = self._match(TokenType.COLON) and _parse_parameter_part()
5178        self._match(TokenType.R_BRACE)
5179
5180        return self.expression(exp.Parameter, this=this, expression=expression)
5181
5182    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5183        if self._match_set(self.PLACEHOLDER_PARSERS):
5184            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5185            if placeholder:
5186                return placeholder
5187            self._advance(-1)
5188        return None
5189
5190    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5191        if not self._match(TokenType.EXCEPT):
5192            return None
5193        if self._match(TokenType.L_PAREN, advance=False):
5194            return self._parse_wrapped_csv(self._parse_column)
5195
5196        except_column = self._parse_column()
5197        return [except_column] if except_column else None
5198
5199    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5200        if not self._match(TokenType.REPLACE):
5201            return None
5202        if self._match(TokenType.L_PAREN, advance=False):
5203            return self._parse_wrapped_csv(self._parse_expression)
5204
5205        replace_expression = self._parse_expression()
5206        return [replace_expression] if replace_expression else None
5207
5208    def _parse_csv(
5209        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5210    ) -> t.List[exp.Expression]:
5211        parse_result = parse_method()
5212        items = [parse_result] if parse_result is not None else []
5213
5214        while self._match(sep):
5215            self._add_comments(parse_result)
5216            parse_result = parse_method()
5217            if parse_result is not None:
5218                items.append(parse_result)
5219
5220        return items
5221
5222    def _parse_tokens(
5223        self, parse_method: t.Callable, expressions: t.Dict
5224    ) -> t.Optional[exp.Expression]:
5225        this = parse_method()
5226
5227        while self._match_set(expressions):
5228            this = self.expression(
5229                expressions[self._prev.token_type],
5230                this=this,
5231                comments=self._prev_comments,
5232                expression=parse_method(),
5233            )
5234
5235        return this
5236
5237    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5238        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5239
5240    def _parse_wrapped_csv(
5241        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5242    ) -> t.List[exp.Expression]:
5243        return self._parse_wrapped(
5244            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5245        )
5246
5247    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5248        wrapped = self._match(TokenType.L_PAREN)
5249        if not wrapped and not optional:
5250            self.raise_error("Expecting (")
5251        parse_result = parse_method()
5252        if wrapped:
5253            self._match_r_paren()
5254        return parse_result
5255
5256    def _parse_expressions(self) -> t.List[exp.Expression]:
5257        return self._parse_csv(self._parse_expression)
5258
5259    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5260        return self._parse_select() or self._parse_set_operations(
5261            self._parse_expression() if alias else self._parse_conjunction()
5262        )
5263
5264    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5265        return self._parse_query_modifiers(
5266            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5267        )
5268
5269    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5270        this = None
5271        if self._match_texts(self.TRANSACTION_KIND):
5272            this = self._prev.text
5273
5274        self._match_texts(("TRANSACTION", "WORK"))
5275
5276        modes = []
5277        while True:
5278            mode = []
5279            while self._match(TokenType.VAR):
5280                mode.append(self._prev.text)
5281
5282            if mode:
5283                modes.append(" ".join(mode))
5284            if not self._match(TokenType.COMMA):
5285                break
5286
5287        return self.expression(exp.Transaction, this=this, modes=modes)
5288
5289    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5290        chain = None
5291        savepoint = None
5292        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5293
5294        self._match_texts(("TRANSACTION", "WORK"))
5295
5296        if self._match_text_seq("TO"):
5297            self._match_text_seq("SAVEPOINT")
5298            savepoint = self._parse_id_var()
5299
5300        if self._match(TokenType.AND):
5301            chain = not self._match_text_seq("NO")
5302            self._match_text_seq("CHAIN")
5303
5304        if is_rollback:
5305            return self.expression(exp.Rollback, savepoint=savepoint)
5306
5307        return self.expression(exp.Commit, chain=chain)
5308
5309    def _parse_refresh(self) -> exp.Refresh:
5310        self._match(TokenType.TABLE)
5311        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5312
5313    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5314        if not self._match_text_seq("ADD"):
5315            return None
5316
5317        self._match(TokenType.COLUMN)
5318        exists_column = self._parse_exists(not_=True)
5319        expression = self._parse_field_def()
5320
5321        if expression:
5322            expression.set("exists", exists_column)
5323
5324            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5325            if self._match_texts(("FIRST", "AFTER")):
5326                position = self._prev.text
5327                column_position = self.expression(
5328                    exp.ColumnPosition, this=self._parse_column(), position=position
5329                )
5330                expression.set("position", column_position)
5331
5332        return expression
5333
5334    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5335        drop = self._match(TokenType.DROP) and self._parse_drop()
5336        if drop and not isinstance(drop, exp.Command):
5337            drop.set("kind", drop.args.get("kind", "COLUMN"))
5338        return drop
5339
5340    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5341    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5342        return self.expression(
5343            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5344        )
5345
5346    def _parse_add_constraint(self) -> exp.AddConstraint:
5347        this = None
5348        kind = self._prev.token_type
5349
5350        if kind == TokenType.CONSTRAINT:
5351            this = self._parse_id_var()
5352
5353            if self._match_text_seq("CHECK"):
5354                expression = self._parse_wrapped(self._parse_conjunction)
5355                enforced = self._match_text_seq("ENFORCED") or False
5356
5357                return self.expression(
5358                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
5359                )
5360
5361        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
5362            expression = self._parse_foreign_key()
5363        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
5364            expression = self._parse_primary_key()
5365        else:
5366            expression = None
5367
5368        return self.expression(exp.AddConstraint, this=this, expression=expression)
5369
5370    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5371        index = self._index - 1
5372
5373        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
5374            return self._parse_csv(self._parse_add_constraint)
5375
5376        self._retreat(index)
5377        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5378            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5379        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5380
5381    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5382        self._match(TokenType.COLUMN)
5383        column = self._parse_field(any_token=True)
5384
5385        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5386            return self.expression(exp.AlterColumn, this=column, drop=True)
5387        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5388            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5389        if self._match(TokenType.COMMENT):
5390            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
5391
5392        self._match_text_seq("SET", "DATA")
5393        return self.expression(
5394            exp.AlterColumn,
5395            this=column,
5396            dtype=self._match_text_seq("TYPE") and self._parse_types(),
5397            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5398            using=self._match(TokenType.USING) and self._parse_conjunction(),
5399        )
5400
5401    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5402        index = self._index - 1
5403
5404        partition_exists = self._parse_exists()
5405        if self._match(TokenType.PARTITION, advance=False):
5406            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5407
5408        self._retreat(index)
5409        return self._parse_csv(self._parse_drop_column)
5410
5411    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
5412        if self._match(TokenType.COLUMN):
5413            exists = self._parse_exists()
5414            old_column = self._parse_column()
5415            to = self._match_text_seq("TO")
5416            new_column = self._parse_column()
5417
5418            if old_column is None or to is None or new_column is None:
5419                return None
5420
5421            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
5422
5423        self._match_text_seq("TO")
5424        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5425
5426    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5427        start = self._prev
5428
5429        if not self._match(TokenType.TABLE):
5430            return self._parse_as_command(start)
5431
5432        exists = self._parse_exists()
5433        only = self._match_text_seq("ONLY")
5434        this = self._parse_table(schema=True)
5435
5436        if self._next:
5437            self._advance()
5438
5439        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5440        if parser:
5441            actions = ensure_list(parser(self))
5442
5443            if not self._curr and actions:
5444                return self.expression(
5445                    exp.AlterTable,
5446                    this=this,
5447                    exists=exists,
5448                    actions=actions,
5449                    only=only,
5450                )
5451
5452        return self._parse_as_command(start)
5453
5454    def _parse_merge(self) -> exp.Merge:
5455        self._match(TokenType.INTO)
5456        target = self._parse_table()
5457
5458        if target and self._match(TokenType.ALIAS, advance=False):
5459            target.set("alias", self._parse_table_alias())
5460
5461        self._match(TokenType.USING)
5462        using = self._parse_table()
5463
5464        self._match(TokenType.ON)
5465        on = self._parse_conjunction()
5466
5467        return self.expression(
5468            exp.Merge,
5469            this=target,
5470            using=using,
5471            on=on,
5472            expressions=self._parse_when_matched(),
5473        )
5474
5475    def _parse_when_matched(self) -> t.List[exp.When]:
5476        whens = []
5477
5478        while self._match(TokenType.WHEN):
5479            matched = not self._match(TokenType.NOT)
5480            self._match_text_seq("MATCHED")
5481            source = (
5482                False
5483                if self._match_text_seq("BY", "TARGET")
5484                else self._match_text_seq("BY", "SOURCE")
5485            )
5486            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5487
5488            self._match(TokenType.THEN)
5489
5490            if self._match(TokenType.INSERT):
5491                _this = self._parse_star()
5492                if _this:
5493                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5494                else:
5495                    then = self.expression(
5496                        exp.Insert,
5497                        this=self._parse_value(),
5498                        expression=self._match(TokenType.VALUES) and self._parse_value(),
5499                    )
5500            elif self._match(TokenType.UPDATE):
5501                expressions = self._parse_star()
5502                if expressions:
5503                    then = self.expression(exp.Update, expressions=expressions)
5504                else:
5505                    then = self.expression(
5506                        exp.Update,
5507                        expressions=self._match(TokenType.SET)
5508                        and self._parse_csv(self._parse_equality),
5509                    )
5510            elif self._match(TokenType.DELETE):
5511                then = self.expression(exp.Var, this=self._prev.text)
5512            else:
5513                then = None
5514
5515            whens.append(
5516                self.expression(
5517                    exp.When,
5518                    matched=matched,
5519                    source=source,
5520                    condition=condition,
5521                    then=then,
5522                )
5523            )
5524        return whens
5525
5526    def _parse_show(self) -> t.Optional[exp.Expression]:
5527        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5528        if parser:
5529            return parser(self)
5530        return self._parse_as_command(self._prev)
5531
5532    def _parse_set_item_assignment(
5533        self, kind: t.Optional[str] = None
5534    ) -> t.Optional[exp.Expression]:
5535        index = self._index
5536
5537        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5538            return self._parse_set_transaction(global_=kind == "GLOBAL")
5539
5540        left = self._parse_primary() or self._parse_id_var()
5541        assignment_delimiter = self._match_texts(("=", "TO"))
5542
5543        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5544            self._retreat(index)
5545            return None
5546
5547        right = self._parse_statement() or self._parse_id_var()
5548        this = self.expression(exp.EQ, this=left, expression=right)
5549
5550        return self.expression(exp.SetItem, this=this, kind=kind)
5551
5552    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5553        self._match_text_seq("TRANSACTION")
5554        characteristics = self._parse_csv(
5555            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5556        )
5557        return self.expression(
5558            exp.SetItem,
5559            expressions=characteristics,
5560            kind="TRANSACTION",
5561            **{"global": global_},  # type: ignore
5562        )
5563
5564    def _parse_set_item(self) -> t.Optional[exp.Expression]:
5565        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
5566        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
5567
5568    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
5569        index = self._index
5570        set_ = self.expression(
5571            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
5572        )
5573
5574        if self._curr:
5575            self._retreat(index)
5576            return self._parse_as_command(self._prev)
5577
5578        return set_
5579
5580    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
5581        for option in options:
5582            if self._match_text_seq(*option.split(" ")):
5583                return exp.var(option)
5584        return None
5585
5586    def _parse_as_command(self, start: Token) -> exp.Command:
5587        while self._curr:
5588            self._advance()
5589        text = self._find_sql(start, self._prev)
5590        size = len(start.text)
5591        self._warn_unsupported()
5592        return exp.Command(this=text[:size], expression=text[size:])
5593
5594    def _parse_dict_property(self, this: str) -> exp.DictProperty:
5595        settings = []
5596
5597        self._match_l_paren()
5598        kind = self._parse_id_var()
5599
5600        if self._match(TokenType.L_PAREN):
5601            while True:
5602                key = self._parse_id_var()
5603                value = self._parse_primary()
5604
5605                if not key and value is None:
5606                    break
5607                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
5608            self._match(TokenType.R_PAREN)
5609
5610        self._match_r_paren()
5611
5612        return self.expression(
5613            exp.DictProperty,
5614            this=this,
5615            kind=kind.this if kind else None,
5616            settings=settings,
5617        )
5618
5619    def _parse_dict_range(self, this: str) -> exp.DictRange:
5620        self._match_l_paren()
5621        has_min = self._match_text_seq("MIN")
5622        if has_min:
5623            min = self._parse_var() or self._parse_primary()
5624            self._match_text_seq("MAX")
5625            max = self._parse_var() or self._parse_primary()
5626        else:
5627            max = self._parse_var() or self._parse_primary()
5628            min = exp.Literal.number(0)
5629        self._match_r_paren()
5630        return self.expression(exp.DictRange, this=this, min=min, max=max)
5631
5632    def _parse_comprehension(
5633        self, this: t.Optional[exp.Expression]
5634    ) -> t.Optional[exp.Comprehension]:
5635        index = self._index
5636        expression = self._parse_column()
5637        if not self._match(TokenType.IN):
5638            self._retreat(index - 1)
5639            return None
5640        iterator = self._parse_column()
5641        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
5642        return self.expression(
5643            exp.Comprehension,
5644            this=this,
5645            expression=expression,
5646            iterator=iterator,
5647            condition=condition,
5648        )
5649
5650    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
5651        if self._match(TokenType.HEREDOC_STRING):
5652            return self.expression(exp.Heredoc, this=self._prev.text)
5653
5654        if not self._match_text_seq("$"):
5655            return None
5656
5657        tags = ["$"]
5658        tag_text = None
5659
5660        if self._is_connected():
5661            self._advance()
5662            tags.append(self._prev.text.upper())
5663        else:
5664            self.raise_error("No closing $ found")
5665
5666        if tags[-1] != "$":
5667            if self._is_connected() and self._match_text_seq("$"):
5668                tag_text = tags[-1]
5669                tags.append("$")
5670            else:
5671                self.raise_error("No closing $ found")
5672
5673        heredoc_start = self._curr
5674
5675        while self._curr:
5676            if self._match_text_seq(*tags, advance=False):
5677                this = self._find_sql(heredoc_start, self._prev)
5678                self._advance(len(tags))
5679                return self.expression(exp.Heredoc, this=this, tag=tag_text)
5680
5681            self._advance()
5682
5683        self.raise_error(f"No closing {''.join(tags)} found")
5684        return None
5685
5686    def _find_parser(
5687        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
5688    ) -> t.Optional[t.Callable]:
5689        if not self._curr:
5690            return None
5691
5692        index = self._index
5693        this = []
5694        while True:
5695            # The current token might be multiple words
5696            curr = self._curr.text.upper()
5697            key = curr.split(" ")
5698            this.append(curr)
5699
5700            self._advance()
5701            result, trie = in_trie(trie, key)
5702            if result == TrieResult.FAILED:
5703                break
5704
5705            if result == TrieResult.EXISTS:
5706                subparser = parsers[" ".join(this)]
5707                return subparser
5708
5709        self._retreat(index)
5710        return None
5711
5712    def _match(self, token_type, advance=True, expression=None):
5713        if not self._curr:
5714            return None
5715
5716        if self._curr.token_type == token_type:
5717            if advance:
5718                self._advance()
5719            self._add_comments(expression)
5720            return True
5721
5722        return None
5723
5724    def _match_set(self, types, advance=True):
5725        if not self._curr:
5726            return None
5727
5728        if self._curr.token_type in types:
5729            if advance:
5730                self._advance()
5731            return True
5732
5733        return None
5734
5735    def _match_pair(self, token_type_a, token_type_b, advance=True):
5736        if not self._curr or not self._next:
5737            return None
5738
5739        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
5740            if advance:
5741                self._advance(2)
5742            return True
5743
5744        return None
5745
5746    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5747        if not self._match(TokenType.L_PAREN, expression=expression):
5748            self.raise_error("Expecting (")
5749
5750    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5751        if not self._match(TokenType.R_PAREN, expression=expression):
5752            self.raise_error("Expecting )")
5753
5754    def _match_texts(self, texts, advance=True):
5755        if self._curr and self._curr.text.upper() in texts:
5756            if advance:
5757                self._advance()
5758            return True
5759        return None
5760
5761    def _match_text_seq(self, *texts, advance=True):
5762        index = self._index
5763        for text in texts:
5764            if self._curr and self._curr.text.upper() == text:
5765                self._advance()
5766            else:
5767                self._retreat(index)
5768                return None
5769
5770        if not advance:
5771            self._retreat(index)
5772
5773        return True
5774
5775    @t.overload
5776    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
5777        ...
5778
5779    @t.overload
5780    def _replace_columns_with_dots(
5781        self, this: t.Optional[exp.Expression]
5782    ) -> t.Optional[exp.Expression]:
5783        ...
5784
5785    def _replace_columns_with_dots(self, this):
5786        if isinstance(this, exp.Dot):
5787            exp.replace_children(this, self._replace_columns_with_dots)
5788        elif isinstance(this, exp.Column):
5789            exp.replace_children(this, self._replace_columns_with_dots)
5790            table = this.args.get("table")
5791            this = (
5792                self.expression(exp.Dot, this=table, expression=this.this) if table else this.this
5793            )
5794
5795        return this
5796
5797    def _replace_lambda(
5798        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
5799    ) -> t.Optional[exp.Expression]:
5800        if not node:
5801            return node
5802
5803        for column in node.find_all(exp.Column):
5804            if column.parts[0].name in lambda_variables:
5805                dot_or_id = column.to_dot() if column.table else column.this
5806                parent = column.parent
5807
5808                while isinstance(parent, exp.Dot):
5809                    if not isinstance(parent.parent, exp.Dot):
5810                        parent.replace(dot_or_id)
5811                        break
5812                    parent = parent.parent
5813                else:
5814                    if column is node:
5815                        node = dot_or_id
5816                    else:
5817                        column.replace(dot_or_id)
5818        return node
logger = <Logger sqlglot (WARNING)>
def parse_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
22def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
23    if len(args) == 1 and args[0].is_star:
24        return exp.StarMap(this=args[0])
25
26    keys = []
27    values = []
28    for i in range(0, len(args), 2):
29        keys.append(args[i])
30        values.append(args[i + 1])
31
32    return exp.VarMap(
33        keys=exp.Array(expressions=keys),
34        values=exp.Array(expressions=values),
35    )
def parse_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
38def parse_like(args: t.List) -> exp.Escape | exp.Like:
39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression]) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
43def binary_range_parser(
44    expr_type: t.Type[exp.Expression],
45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
46    return lambda self, this: self._parse_escape(
47        self.expression(expr_type, this=this, expression=self._parse_bitwise())
48    )
def parse_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
51def parse_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
52    # Default argument order is base, expression
53    this = seq_get(args, 0)
54    expression = seq_get(args, 1)
55
56    if expression:
57        if not dialect.LOG_BASE_FIRST:
58            this, expression = expression, this
59        return exp.Log(this=this, expression=expression)
60
61    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
def parse_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]:
64def parse_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
65    def _parser(args: t.List, dialect: Dialect) -> E:
66        expression = expr_type(
67            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
68        )
69        if len(args) > 2 and expr_type is exp.JSONExtract:
70            expression.set("expressions", args[2:])
71
72        return expression
73
74    return _parser
class Parser:
  87class Parser(metaclass=_Parser):
  88    """
  89    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  90
  91    Args:
  92        error_level: The desired error level.
  93            Default: ErrorLevel.IMMEDIATE
  94        error_message_context: Determines the amount of context to capture from a
  95            query string when displaying the error message (in number of characters).
  96            Default: 100
  97        max_errors: Maximum number of error messages to include in a raised ParseError.
  98            This is only relevant if error_level is ErrorLevel.RAISE.
  99            Default: 3
 100    """
 101
 102    FUNCTIONS: t.Dict[str, t.Callable] = {
 103        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 104        "CONCAT": lambda args, dialect: exp.Concat(
 105            expressions=args,
 106            safe=not dialect.STRICT_STRING_CONCAT,
 107            coalesce=dialect.CONCAT_COALESCE,
 108        ),
 109        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 110            expressions=args,
 111            safe=not dialect.STRICT_STRING_CONCAT,
 112            coalesce=dialect.CONCAT_COALESCE,
 113        ),
 114        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 115            this=seq_get(args, 0),
 116            to=exp.DataType(this=exp.DataType.Type.TEXT),
 117        ),
 118        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 119        "JSON_EXTRACT": parse_extract_json_with_path(exp.JSONExtract),
 120        "JSON_EXTRACT_SCALAR": parse_extract_json_with_path(exp.JSONExtractScalar),
 121        "JSON_EXTRACT_PATH_TEXT": parse_extract_json_with_path(exp.JSONExtractScalar),
 122        "LIKE": parse_like,
 123        "LOG": parse_logarithm,
 124        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 125            this=seq_get(args, 0),
 126            to=exp.DataType(this=exp.DataType.Type.TEXT),
 127        ),
 128        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 129            this=exp.Cast(
 130                this=seq_get(args, 0),
 131                to=exp.DataType(this=exp.DataType.Type.TEXT),
 132            ),
 133            start=exp.Literal.number(1),
 134            length=exp.Literal.number(10),
 135        ),
 136        "VAR_MAP": parse_var_map,
 137    }
 138
 139    NO_PAREN_FUNCTIONS = {
 140        TokenType.CURRENT_DATE: exp.CurrentDate,
 141        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 142        TokenType.CURRENT_TIME: exp.CurrentTime,
 143        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 144        TokenType.CURRENT_USER: exp.CurrentUser,
 145    }
 146
 147    STRUCT_TYPE_TOKENS = {
 148        TokenType.NESTED,
 149        TokenType.STRUCT,
 150    }
 151
 152    NESTED_TYPE_TOKENS = {
 153        TokenType.ARRAY,
 154        TokenType.LOWCARDINALITY,
 155        TokenType.MAP,
 156        TokenType.NULLABLE,
 157        *STRUCT_TYPE_TOKENS,
 158    }
 159
 160    ENUM_TYPE_TOKENS = {
 161        TokenType.ENUM,
 162        TokenType.ENUM8,
 163        TokenType.ENUM16,
 164    }
 165
 166    AGGREGATE_TYPE_TOKENS = {
 167        TokenType.AGGREGATEFUNCTION,
 168        TokenType.SIMPLEAGGREGATEFUNCTION,
 169    }
 170
 171    TYPE_TOKENS = {
 172        TokenType.BIT,
 173        TokenType.BOOLEAN,
 174        TokenType.TINYINT,
 175        TokenType.UTINYINT,
 176        TokenType.SMALLINT,
 177        TokenType.USMALLINT,
 178        TokenType.INT,
 179        TokenType.UINT,
 180        TokenType.BIGINT,
 181        TokenType.UBIGINT,
 182        TokenType.INT128,
 183        TokenType.UINT128,
 184        TokenType.INT256,
 185        TokenType.UINT256,
 186        TokenType.MEDIUMINT,
 187        TokenType.UMEDIUMINT,
 188        TokenType.FIXEDSTRING,
 189        TokenType.FLOAT,
 190        TokenType.DOUBLE,
 191        TokenType.CHAR,
 192        TokenType.NCHAR,
 193        TokenType.VARCHAR,
 194        TokenType.NVARCHAR,
 195        TokenType.BPCHAR,
 196        TokenType.TEXT,
 197        TokenType.MEDIUMTEXT,
 198        TokenType.LONGTEXT,
 199        TokenType.MEDIUMBLOB,
 200        TokenType.LONGBLOB,
 201        TokenType.BINARY,
 202        TokenType.VARBINARY,
 203        TokenType.JSON,
 204        TokenType.JSONB,
 205        TokenType.INTERVAL,
 206        TokenType.TINYBLOB,
 207        TokenType.TINYTEXT,
 208        TokenType.TIME,
 209        TokenType.TIMETZ,
 210        TokenType.TIMESTAMP,
 211        TokenType.TIMESTAMP_S,
 212        TokenType.TIMESTAMP_MS,
 213        TokenType.TIMESTAMP_NS,
 214        TokenType.TIMESTAMPTZ,
 215        TokenType.TIMESTAMPLTZ,
 216        TokenType.DATETIME,
 217        TokenType.DATETIME64,
 218        TokenType.DATE,
 219        TokenType.DATE32,
 220        TokenType.INT4RANGE,
 221        TokenType.INT4MULTIRANGE,
 222        TokenType.INT8RANGE,
 223        TokenType.INT8MULTIRANGE,
 224        TokenType.NUMRANGE,
 225        TokenType.NUMMULTIRANGE,
 226        TokenType.TSRANGE,
 227        TokenType.TSMULTIRANGE,
 228        TokenType.TSTZRANGE,
 229        TokenType.TSTZMULTIRANGE,
 230        TokenType.DATERANGE,
 231        TokenType.DATEMULTIRANGE,
 232        TokenType.DECIMAL,
 233        TokenType.UDECIMAL,
 234        TokenType.BIGDECIMAL,
 235        TokenType.UUID,
 236        TokenType.GEOGRAPHY,
 237        TokenType.GEOMETRY,
 238        TokenType.HLLSKETCH,
 239        TokenType.HSTORE,
 240        TokenType.PSEUDO_TYPE,
 241        TokenType.SUPER,
 242        TokenType.SERIAL,
 243        TokenType.SMALLSERIAL,
 244        TokenType.BIGSERIAL,
 245        TokenType.XML,
 246        TokenType.YEAR,
 247        TokenType.UNIQUEIDENTIFIER,
 248        TokenType.USERDEFINED,
 249        TokenType.MONEY,
 250        TokenType.SMALLMONEY,
 251        TokenType.ROWVERSION,
 252        TokenType.IMAGE,
 253        TokenType.VARIANT,
 254        TokenType.OBJECT,
 255        TokenType.OBJECT_IDENTIFIER,
 256        TokenType.INET,
 257        TokenType.IPADDRESS,
 258        TokenType.IPPREFIX,
 259        TokenType.IPV4,
 260        TokenType.IPV6,
 261        TokenType.UNKNOWN,
 262        TokenType.NULL,
 263        *ENUM_TYPE_TOKENS,
 264        *NESTED_TYPE_TOKENS,
 265        *AGGREGATE_TYPE_TOKENS,
 266    }
 267
 268    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 269        TokenType.BIGINT: TokenType.UBIGINT,
 270        TokenType.INT: TokenType.UINT,
 271        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 272        TokenType.SMALLINT: TokenType.USMALLINT,
 273        TokenType.TINYINT: TokenType.UTINYINT,
 274        TokenType.DECIMAL: TokenType.UDECIMAL,
 275    }
 276
 277    SUBQUERY_PREDICATES = {
 278        TokenType.ANY: exp.Any,
 279        TokenType.ALL: exp.All,
 280        TokenType.EXISTS: exp.Exists,
 281        TokenType.SOME: exp.Any,
 282    }
 283
 284    RESERVED_TOKENS = {
 285        *Tokenizer.SINGLE_TOKENS.values(),
 286        TokenType.SELECT,
 287    }
 288
 289    DB_CREATABLES = {
 290        TokenType.DATABASE,
 291        TokenType.SCHEMA,
 292        TokenType.TABLE,
 293        TokenType.VIEW,
 294        TokenType.MODEL,
 295        TokenType.DICTIONARY,
 296    }
 297
 298    CREATABLES = {
 299        TokenType.COLUMN,
 300        TokenType.CONSTRAINT,
 301        TokenType.FUNCTION,
 302        TokenType.INDEX,
 303        TokenType.PROCEDURE,
 304        TokenType.FOREIGN_KEY,
 305        *DB_CREATABLES,
 306    }
 307
 308    # Tokens that can represent identifiers
 309    ID_VAR_TOKENS = {
 310        TokenType.VAR,
 311        TokenType.ANTI,
 312        TokenType.APPLY,
 313        TokenType.ASC,
 314        TokenType.AUTO_INCREMENT,
 315        TokenType.BEGIN,
 316        TokenType.BPCHAR,
 317        TokenType.CACHE,
 318        TokenType.CASE,
 319        TokenType.COLLATE,
 320        TokenType.COMMAND,
 321        TokenType.COMMENT,
 322        TokenType.COMMIT,
 323        TokenType.CONSTRAINT,
 324        TokenType.DEFAULT,
 325        TokenType.DELETE,
 326        TokenType.DESC,
 327        TokenType.DESCRIBE,
 328        TokenType.DICTIONARY,
 329        TokenType.DIV,
 330        TokenType.END,
 331        TokenType.EXECUTE,
 332        TokenType.ESCAPE,
 333        TokenType.FALSE,
 334        TokenType.FIRST,
 335        TokenType.FILTER,
 336        TokenType.FINAL,
 337        TokenType.FORMAT,
 338        TokenType.FULL,
 339        TokenType.IS,
 340        TokenType.ISNULL,
 341        TokenType.INTERVAL,
 342        TokenType.KEEP,
 343        TokenType.KILL,
 344        TokenType.LEFT,
 345        TokenType.LOAD,
 346        TokenType.MERGE,
 347        TokenType.NATURAL,
 348        TokenType.NEXT,
 349        TokenType.OFFSET,
 350        TokenType.OPERATOR,
 351        TokenType.ORDINALITY,
 352        TokenType.OVERLAPS,
 353        TokenType.OVERWRITE,
 354        TokenType.PARTITION,
 355        TokenType.PERCENT,
 356        TokenType.PIVOT,
 357        TokenType.PRAGMA,
 358        TokenType.RANGE,
 359        TokenType.RECURSIVE,
 360        TokenType.REFERENCES,
 361        TokenType.REFRESH,
 362        TokenType.REPLACE,
 363        TokenType.RIGHT,
 364        TokenType.ROW,
 365        TokenType.ROWS,
 366        TokenType.SEMI,
 367        TokenType.SET,
 368        TokenType.SETTINGS,
 369        TokenType.SHOW,
 370        TokenType.TEMPORARY,
 371        TokenType.TOP,
 372        TokenType.TRUE,
 373        TokenType.UNIQUE,
 374        TokenType.UNPIVOT,
 375        TokenType.UPDATE,
 376        TokenType.USE,
 377        TokenType.VOLATILE,
 378        TokenType.WINDOW,
 379        *CREATABLES,
 380        *SUBQUERY_PREDICATES,
 381        *TYPE_TOKENS,
 382        *NO_PAREN_FUNCTIONS,
 383    }
 384
 385    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 386
 387    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 388        TokenType.ANTI,
 389        TokenType.APPLY,
 390        TokenType.ASOF,
 391        TokenType.FULL,
 392        TokenType.LEFT,
 393        TokenType.LOCK,
 394        TokenType.NATURAL,
 395        TokenType.OFFSET,
 396        TokenType.RIGHT,
 397        TokenType.SEMI,
 398        TokenType.WINDOW,
 399    }
 400
 401    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 402
 403    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 404
 405    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 406
 407    FUNC_TOKENS = {
 408        TokenType.COLLATE,
 409        TokenType.COMMAND,
 410        TokenType.CURRENT_DATE,
 411        TokenType.CURRENT_DATETIME,
 412        TokenType.CURRENT_TIMESTAMP,
 413        TokenType.CURRENT_TIME,
 414        TokenType.CURRENT_USER,
 415        TokenType.FILTER,
 416        TokenType.FIRST,
 417        TokenType.FORMAT,
 418        TokenType.GLOB,
 419        TokenType.IDENTIFIER,
 420        TokenType.INDEX,
 421        TokenType.ISNULL,
 422        TokenType.ILIKE,
 423        TokenType.INSERT,
 424        TokenType.LIKE,
 425        TokenType.MERGE,
 426        TokenType.OFFSET,
 427        TokenType.PRIMARY_KEY,
 428        TokenType.RANGE,
 429        TokenType.REPLACE,
 430        TokenType.RLIKE,
 431        TokenType.ROW,
 432        TokenType.UNNEST,
 433        TokenType.VAR,
 434        TokenType.LEFT,
 435        TokenType.RIGHT,
 436        TokenType.DATE,
 437        TokenType.DATETIME,
 438        TokenType.TABLE,
 439        TokenType.TIMESTAMP,
 440        TokenType.TIMESTAMPTZ,
 441        TokenType.WINDOW,
 442        TokenType.XOR,
 443        *TYPE_TOKENS,
 444        *SUBQUERY_PREDICATES,
 445    }
 446
 447    CONJUNCTION = {
 448        TokenType.AND: exp.And,
 449        TokenType.OR: exp.Or,
 450    }
 451
 452    EQUALITY = {
 453        TokenType.COLON_EQ: exp.PropertyEQ,
 454        TokenType.EQ: exp.EQ,
 455        TokenType.NEQ: exp.NEQ,
 456        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 457    }
 458
 459    COMPARISON = {
 460        TokenType.GT: exp.GT,
 461        TokenType.GTE: exp.GTE,
 462        TokenType.LT: exp.LT,
 463        TokenType.LTE: exp.LTE,
 464    }
 465
 466    BITWISE = {
 467        TokenType.AMP: exp.BitwiseAnd,
 468        TokenType.CARET: exp.BitwiseXor,
 469        TokenType.PIPE: exp.BitwiseOr,
 470    }
 471
 472    TERM = {
 473        TokenType.DASH: exp.Sub,
 474        TokenType.PLUS: exp.Add,
 475        TokenType.MOD: exp.Mod,
 476        TokenType.COLLATE: exp.Collate,
 477    }
 478
 479    FACTOR = {
 480        TokenType.DIV: exp.IntDiv,
 481        TokenType.LR_ARROW: exp.Distance,
 482        TokenType.SLASH: exp.Div,
 483        TokenType.STAR: exp.Mul,
 484    }
 485
 486    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 487
 488    TIMES = {
 489        TokenType.TIME,
 490        TokenType.TIMETZ,
 491    }
 492
 493    TIMESTAMPS = {
 494        TokenType.TIMESTAMP,
 495        TokenType.TIMESTAMPTZ,
 496        TokenType.TIMESTAMPLTZ,
 497        *TIMES,
 498    }
 499
 500    SET_OPERATIONS = {
 501        TokenType.UNION,
 502        TokenType.INTERSECT,
 503        TokenType.EXCEPT,
 504    }
 505
 506    JOIN_METHODS = {
 507        TokenType.NATURAL,
 508        TokenType.ASOF,
 509    }
 510
 511    JOIN_SIDES = {
 512        TokenType.LEFT,
 513        TokenType.RIGHT,
 514        TokenType.FULL,
 515    }
 516
 517    JOIN_KINDS = {
 518        TokenType.INNER,
 519        TokenType.OUTER,
 520        TokenType.CROSS,
 521        TokenType.SEMI,
 522        TokenType.ANTI,
 523    }
 524
 525    JOIN_HINTS: t.Set[str] = set()
 526
 527    LAMBDAS = {
 528        TokenType.ARROW: lambda self, expressions: self.expression(
 529            exp.Lambda,
 530            this=self._replace_lambda(
 531                self._parse_conjunction(),
 532                {node.name for node in expressions},
 533            ),
 534            expressions=expressions,
 535        ),
 536        TokenType.FARROW: lambda self, expressions: self.expression(
 537            exp.Kwarg,
 538            this=exp.var(expressions[0].name),
 539            expression=self._parse_conjunction(),
 540        ),
 541    }
 542
 543    COLUMN_OPERATORS = {
 544        TokenType.DOT: None,
 545        TokenType.DCOLON: lambda self, this, to: self.expression(
 546            exp.Cast if self.STRICT_CAST else exp.TryCast,
 547            this=this,
 548            to=to,
 549        ),
 550        TokenType.ARROW: lambda self, this, path: self.expression(
 551            exp.JSONExtract,
 552            this=this,
 553            expression=self.dialect.to_json_path(path),
 554        ),
 555        TokenType.DARROW: lambda self, this, path: self.expression(
 556            exp.JSONExtractScalar,
 557            this=this,
 558            expression=self.dialect.to_json_path(path),
 559        ),
 560        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 561            exp.JSONBExtract,
 562            this=this,
 563            expression=path,
 564        ),
 565        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 566            exp.JSONBExtractScalar,
 567            this=this,
 568            expression=path,
 569        ),
 570        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 571            exp.JSONBContains,
 572            this=this,
 573            expression=key,
 574        ),
 575    }
 576
 577    EXPRESSION_PARSERS = {
 578        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 579        exp.Column: lambda self: self._parse_column(),
 580        exp.Condition: lambda self: self._parse_conjunction(),
 581        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 582        exp.Expression: lambda self: self._parse_statement(),
 583        exp.From: lambda self: self._parse_from(),
 584        exp.Group: lambda self: self._parse_group(),
 585        exp.Having: lambda self: self._parse_having(),
 586        exp.Identifier: lambda self: self._parse_id_var(),
 587        exp.Join: lambda self: self._parse_join(),
 588        exp.Lambda: lambda self: self._parse_lambda(),
 589        exp.Lateral: lambda self: self._parse_lateral(),
 590        exp.Limit: lambda self: self._parse_limit(),
 591        exp.Offset: lambda self: self._parse_offset(),
 592        exp.Order: lambda self: self._parse_order(),
 593        exp.Ordered: lambda self: self._parse_ordered(),
 594        exp.Properties: lambda self: self._parse_properties(),
 595        exp.Qualify: lambda self: self._parse_qualify(),
 596        exp.Returning: lambda self: self._parse_returning(),
 597        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 598        exp.Table: lambda self: self._parse_table_parts(),
 599        exp.TableAlias: lambda self: self._parse_table_alias(),
 600        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 601        exp.Where: lambda self: self._parse_where(),
 602        exp.Window: lambda self: self._parse_named_window(),
 603        exp.With: lambda self: self._parse_with(),
 604        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 605    }
 606
 607    STATEMENT_PARSERS = {
 608        TokenType.ALTER: lambda self: self._parse_alter(),
 609        TokenType.BEGIN: lambda self: self._parse_transaction(),
 610        TokenType.CACHE: lambda self: self._parse_cache(),
 611        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 612        TokenType.COMMENT: lambda self: self._parse_comment(),
 613        TokenType.CREATE: lambda self: self._parse_create(),
 614        TokenType.DELETE: lambda self: self._parse_delete(),
 615        TokenType.DESC: lambda self: self._parse_describe(),
 616        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 617        TokenType.DROP: lambda self: self._parse_drop(),
 618        TokenType.INSERT: lambda self: self._parse_insert(),
 619        TokenType.KILL: lambda self: self._parse_kill(),
 620        TokenType.LOAD: lambda self: self._parse_load(),
 621        TokenType.MERGE: lambda self: self._parse_merge(),
 622        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 623        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 624        TokenType.REFRESH: lambda self: self._parse_refresh(),
 625        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 626        TokenType.SET: lambda self: self._parse_set(),
 627        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 628        TokenType.UPDATE: lambda self: self._parse_update(),
 629        TokenType.USE: lambda self: self.expression(
 630            exp.Use,
 631            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
 632            and exp.var(self._prev.text),
 633            this=self._parse_table(schema=False),
 634        ),
 635    }
 636
 637    UNARY_PARSERS = {
 638        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 639        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 640        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 641        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 642    }
 643
 644    PRIMARY_PARSERS = {
 645        TokenType.STRING: lambda self, token: self.expression(
 646            exp.Literal, this=token.text, is_string=True
 647        ),
 648        TokenType.NUMBER: lambda self, token: self.expression(
 649            exp.Literal, this=token.text, is_string=False
 650        ),
 651        TokenType.STAR: lambda self, _: self.expression(
 652            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 653        ),
 654        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 655        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 656        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 657        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 658        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 659        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 660        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 661        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 662            exp.National, this=token.text
 663        ),
 664        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 665        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 666            exp.RawString, this=token.text
 667        ),
 668        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 669            exp.UnicodeString,
 670            this=token.text,
 671            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 672        ),
 673        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 674    }
 675
 676    PLACEHOLDER_PARSERS = {
 677        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 678        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 679        TokenType.COLON: lambda self: (
 680            self.expression(exp.Placeholder, this=self._prev.text)
 681            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 682            else None
 683        ),
 684    }
 685
 686    RANGE_PARSERS = {
 687        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 688        TokenType.GLOB: binary_range_parser(exp.Glob),
 689        TokenType.ILIKE: binary_range_parser(exp.ILike),
 690        TokenType.IN: lambda self, this: self._parse_in(this),
 691        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 692        TokenType.IS: lambda self, this: self._parse_is(this),
 693        TokenType.LIKE: binary_range_parser(exp.Like),
 694        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 695        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 696        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 697        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 698    }
 699
 700    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 701        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 702        "AUTO": lambda self: self._parse_auto_property(),
 703        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 704        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 705        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 706        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 707        "CHECKSUM": lambda self: self._parse_checksum(),
 708        "CLUSTER BY": lambda self: self._parse_cluster(),
 709        "CLUSTERED": lambda self: self._parse_clustered_by(),
 710        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 711            exp.CollateProperty, **kwargs
 712        ),
 713        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 714        "CONTAINS": lambda self: self._parse_contains_property(),
 715        "COPY": lambda self: self._parse_copy_property(),
 716        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 717        "DEFINER": lambda self: self._parse_definer(),
 718        "DETERMINISTIC": lambda self: self.expression(
 719            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 720        ),
 721        "DISTKEY": lambda self: self._parse_distkey(),
 722        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 723        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 724        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 725        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 726        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 727        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 728        "FREESPACE": lambda self: self._parse_freespace(),
 729        "HEAP": lambda self: self.expression(exp.HeapProperty),
 730        "IMMUTABLE": lambda self: self.expression(
 731            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 732        ),
 733        "INHERITS": lambda self: self.expression(
 734            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 735        ),
 736        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 737        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 738        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 739        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 740        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 741        "LIKE": lambda self: self._parse_create_like(),
 742        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 743        "LOCK": lambda self: self._parse_locking(),
 744        "LOCKING": lambda self: self._parse_locking(),
 745        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 746        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 747        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 748        "MODIFIES": lambda self: self._parse_modifies_property(),
 749        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 750        "NO": lambda self: self._parse_no_property(),
 751        "ON": lambda self: self._parse_on_property(),
 752        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 753        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 754        "PARTITION": lambda self: self._parse_partitioned_of(),
 755        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 756        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 757        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 758        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 759        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 760        "READS": lambda self: self._parse_reads_property(),
 761        "REMOTE": lambda self: self._parse_remote_with_connection(),
 762        "RETURNS": lambda self: self._parse_returns(),
 763        "ROW": lambda self: self._parse_row(),
 764        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 765        "SAMPLE": lambda self: self.expression(
 766            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 767        ),
 768        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 769        "SETTINGS": lambda self: self.expression(
 770            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 771        ),
 772        "SORTKEY": lambda self: self._parse_sortkey(),
 773        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 774        "STABLE": lambda self: self.expression(
 775            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 776        ),
 777        "STORED": lambda self: self._parse_stored(),
 778        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 779        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
 780        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 781        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 782        "TO": lambda self: self._parse_to_table(),
 783        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 784        "TRANSFORM": lambda self: self.expression(
 785            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 786        ),
 787        "TTL": lambda self: self._parse_ttl(),
 788        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 789        "VOLATILE": lambda self: self._parse_volatile_property(),
 790        "WITH": lambda self: self._parse_with_property(),
 791    }
 792
 793    CONSTRAINT_PARSERS = {
 794        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 795        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 796        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 797        "CHARACTER SET": lambda self: self.expression(
 798            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 799        ),
 800        "CHECK": lambda self: self.expression(
 801            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
 802        ),
 803        "COLLATE": lambda self: self.expression(
 804            exp.CollateColumnConstraint, this=self._parse_var()
 805        ),
 806        "COMMENT": lambda self: self.expression(
 807            exp.CommentColumnConstraint, this=self._parse_string()
 808        ),
 809        "COMPRESS": lambda self: self._parse_compress(),
 810        "CLUSTERED": lambda self: self.expression(
 811            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 812        ),
 813        "NONCLUSTERED": lambda self: self.expression(
 814            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 815        ),
 816        "DEFAULT": lambda self: self.expression(
 817            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 818        ),
 819        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 820        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 821        "FORMAT": lambda self: self.expression(
 822            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 823        ),
 824        "GENERATED": lambda self: self._parse_generated_as_identity(),
 825        "IDENTITY": lambda self: self._parse_auto_increment(),
 826        "INLINE": lambda self: self._parse_inline(),
 827        "LIKE": lambda self: self._parse_create_like(),
 828        "NOT": lambda self: self._parse_not_constraint(),
 829        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 830        "ON": lambda self: (
 831            self._match(TokenType.UPDATE)
 832            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 833        )
 834        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 835        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 836        "PERIOD": lambda self: self._parse_period_for_system_time(),
 837        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 838        "REFERENCES": lambda self: self._parse_references(match=False),
 839        "TITLE": lambda self: self.expression(
 840            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 841        ),
 842        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 843        "UNIQUE": lambda self: self._parse_unique(),
 844        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 845        "WITH": lambda self: self.expression(
 846            exp.Properties, expressions=self._parse_wrapped_csv(self._parse_property)
 847        ),
 848    }
 849
 850    ALTER_PARSERS = {
 851        "ADD": lambda self: self._parse_alter_table_add(),
 852        "ALTER": lambda self: self._parse_alter_table_alter(),
 853        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 854        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 855        "DROP": lambda self: self._parse_alter_table_drop(),
 856        "RENAME": lambda self: self._parse_alter_table_rename(),
 857    }
 858
 859    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE", "PERIOD"}
 860
 861    NO_PAREN_FUNCTION_PARSERS = {
 862        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 863        "CASE": lambda self: self._parse_case(),
 864        "IF": lambda self: self._parse_if(),
 865        "NEXT": lambda self: self._parse_next_value_for(),
 866    }
 867
 868    INVALID_FUNC_NAME_TOKENS = {
 869        TokenType.IDENTIFIER,
 870        TokenType.STRING,
 871    }
 872
 873    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 874
 875    FUNCTION_PARSERS = {
 876        "ANY_VALUE": lambda self: self._parse_any_value(),
 877        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 878        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 879        "DECODE": lambda self: self._parse_decode(),
 880        "EXTRACT": lambda self: self._parse_extract(),
 881        "JSON_OBJECT": lambda self: self._parse_json_object(),
 882        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 883        "JSON_TABLE": lambda self: self._parse_json_table(),
 884        "MATCH": lambda self: self._parse_match_against(),
 885        "OPENJSON": lambda self: self._parse_open_json(),
 886        "POSITION": lambda self: self._parse_position(),
 887        "PREDICT": lambda self: self._parse_predict(),
 888        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 889        "STRING_AGG": lambda self: self._parse_string_agg(),
 890        "SUBSTRING": lambda self: self._parse_substring(),
 891        "TRIM": lambda self: self._parse_trim(),
 892        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 893        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 894    }
 895
 896    QUERY_MODIFIER_PARSERS = {
 897        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 898        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 899        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 900        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 901        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 902        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 903        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 904        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 905        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 906        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 907        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 908        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 909        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 910        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 911        TokenType.CLUSTER_BY: lambda self: (
 912            "cluster",
 913            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 914        ),
 915        TokenType.DISTRIBUTE_BY: lambda self: (
 916            "distribute",
 917            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 918        ),
 919        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 920        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 921        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 922    }
 923
 924    SET_PARSERS = {
 925        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 926        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 927        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 928        "TRANSACTION": lambda self: self._parse_set_transaction(),
 929    }
 930
 931    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 932
 933    TYPE_LITERAL_PARSERS = {
 934        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 935    }
 936
 937    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
 938
 939    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 940
 941    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 942
 943    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 944    TRANSACTION_CHARACTERISTICS = {
 945        "ISOLATION LEVEL REPEATABLE READ",
 946        "ISOLATION LEVEL READ COMMITTED",
 947        "ISOLATION LEVEL READ UNCOMMITTED",
 948        "ISOLATION LEVEL SERIALIZABLE",
 949        "READ WRITE",
 950        "READ ONLY",
 951    }
 952
 953    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
 954
 955    CLONE_KEYWORDS = {"CLONE", "COPY"}
 956    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
 957
 958    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS"}
 959    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
 960
 961    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
 962
 963    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
 964    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
 965    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
 966
 967    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
 968
 969    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
 970
 971    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
 972
 973    DISTINCT_TOKENS = {TokenType.DISTINCT}
 974
 975    NULL_TOKENS = {TokenType.NULL}
 976
 977    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
 978
 979    STRICT_CAST = True
 980
 981    PREFIXED_PIVOT_COLUMNS = False
 982    IDENTIFY_PIVOT_STRINGS = False
 983
 984    LOG_DEFAULTS_TO_LN = False
 985
 986    # Whether or not ADD is present for each column added by ALTER TABLE
 987    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
 988
 989    # Whether or not the table sample clause expects CSV syntax
 990    TABLESAMPLE_CSV = False
 991
 992    # Whether or not the SET command needs a delimiter (e.g. "=") for assignments
 993    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
 994
 995    # Whether the TRIM function expects the characters to trim as its first argument
 996    TRIM_PATTERN_FIRST = False
 997
 998    # Whether or not string aliases are supported `SELECT COUNT(*) 'count'`
 999    STRING_ALIASES = False
1000
1001    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1002    MODIFIERS_ATTACHED_TO_UNION = True
1003    UNION_MODIFIERS = {"order", "limit", "offset"}
1004
1005    # parses no parenthesis if statements as commands
1006    NO_PAREN_IF_COMMANDS = True
1007
1008    __slots__ = (
1009        "error_level",
1010        "error_message_context",
1011        "max_errors",
1012        "dialect",
1013        "sql",
1014        "errors",
1015        "_tokens",
1016        "_index",
1017        "_curr",
1018        "_next",
1019        "_prev",
1020        "_prev_comments",
1021    )
1022
1023    # Autofilled
1024    SHOW_TRIE: t.Dict = {}
1025    SET_TRIE: t.Dict = {}
1026
1027    def __init__(
1028        self,
1029        error_level: t.Optional[ErrorLevel] = None,
1030        error_message_context: int = 100,
1031        max_errors: int = 3,
1032        dialect: DialectType = None,
1033    ):
1034        from sqlglot.dialects import Dialect
1035
1036        self.error_level = error_level or ErrorLevel.IMMEDIATE
1037        self.error_message_context = error_message_context
1038        self.max_errors = max_errors
1039        self.dialect = Dialect.get_or_raise(dialect)
1040        self.reset()
1041
1042    def reset(self):
1043        self.sql = ""
1044        self.errors = []
1045        self._tokens = []
1046        self._index = 0
1047        self._curr = None
1048        self._next = None
1049        self._prev = None
1050        self._prev_comments = None
1051
1052    def parse(
1053        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1054    ) -> t.List[t.Optional[exp.Expression]]:
1055        """
1056        Parses a list of tokens and returns a list of syntax trees, one tree
1057        per parsed SQL statement.
1058
1059        Args:
1060            raw_tokens: The list of tokens.
1061            sql: The original SQL string, used to produce helpful debug messages.
1062
1063        Returns:
1064            The list of the produced syntax trees.
1065        """
1066        return self._parse(
1067            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1068        )
1069
1070    def parse_into(
1071        self,
1072        expression_types: exp.IntoType,
1073        raw_tokens: t.List[Token],
1074        sql: t.Optional[str] = None,
1075    ) -> t.List[t.Optional[exp.Expression]]:
1076        """
1077        Parses a list of tokens into a given Expression type. If a collection of Expression
1078        types is given instead, this method will try to parse the token list into each one
1079        of them, stopping at the first for which the parsing succeeds.
1080
1081        Args:
1082            expression_types: The expression type(s) to try and parse the token list into.
1083            raw_tokens: The list of tokens.
1084            sql: The original SQL string, used to produce helpful debug messages.
1085
1086        Returns:
1087            The target Expression.
1088        """
1089        errors = []
1090        for expression_type in ensure_list(expression_types):
1091            parser = self.EXPRESSION_PARSERS.get(expression_type)
1092            if not parser:
1093                raise TypeError(f"No parser registered for {expression_type}")
1094
1095            try:
1096                return self._parse(parser, raw_tokens, sql)
1097            except ParseError as e:
1098                e.errors[0]["into_expression"] = expression_type
1099                errors.append(e)
1100
1101        raise ParseError(
1102            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1103            errors=merge_errors(errors),
1104        ) from errors[-1]
1105
1106    def _parse(
1107        self,
1108        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1109        raw_tokens: t.List[Token],
1110        sql: t.Optional[str] = None,
1111    ) -> t.List[t.Optional[exp.Expression]]:
1112        self.reset()
1113        self.sql = sql or ""
1114
1115        total = len(raw_tokens)
1116        chunks: t.List[t.List[Token]] = [[]]
1117
1118        for i, token in enumerate(raw_tokens):
1119            if token.token_type == TokenType.SEMICOLON:
1120                if i < total - 1:
1121                    chunks.append([])
1122            else:
1123                chunks[-1].append(token)
1124
1125        expressions = []
1126
1127        for tokens in chunks:
1128            self._index = -1
1129            self._tokens = tokens
1130            self._advance()
1131
1132            expressions.append(parse_method(self))
1133
1134            if self._index < len(self._tokens):
1135                self.raise_error("Invalid expression / Unexpected token")
1136
1137            self.check_errors()
1138
1139        return expressions
1140
1141    def check_errors(self) -> None:
1142        """Logs or raises any found errors, depending on the chosen error level setting."""
1143        if self.error_level == ErrorLevel.WARN:
1144            for error in self.errors:
1145                logger.error(str(error))
1146        elif self.error_level == ErrorLevel.RAISE and self.errors:
1147            raise ParseError(
1148                concat_messages(self.errors, self.max_errors),
1149                errors=merge_errors(self.errors),
1150            )
1151
1152    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1153        """
1154        Appends an error in the list of recorded errors or raises it, depending on the chosen
1155        error level setting.
1156        """
1157        token = token or self._curr or self._prev or Token.string("")
1158        start = token.start
1159        end = token.end + 1
1160        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1161        highlight = self.sql[start:end]
1162        end_context = self.sql[end : end + self.error_message_context]
1163
1164        error = ParseError.new(
1165            f"{message}. Line {token.line}, Col: {token.col}.\n"
1166            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1167            description=message,
1168            line=token.line,
1169            col=token.col,
1170            start_context=start_context,
1171            highlight=highlight,
1172            end_context=end_context,
1173        )
1174
1175        if self.error_level == ErrorLevel.IMMEDIATE:
1176            raise error
1177
1178        self.errors.append(error)
1179
1180    def expression(
1181        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1182    ) -> E:
1183        """
1184        Creates a new, validated Expression.
1185
1186        Args:
1187            exp_class: The expression class to instantiate.
1188            comments: An optional list of comments to attach to the expression.
1189            kwargs: The arguments to set for the expression along with their respective values.
1190
1191        Returns:
1192            The target expression.
1193        """
1194        instance = exp_class(**kwargs)
1195        instance.add_comments(comments) if comments else self._add_comments(instance)
1196        return self.validate_expression(instance)
1197
1198    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1199        if expression and self._prev_comments:
1200            expression.add_comments(self._prev_comments)
1201            self._prev_comments = None
1202
1203    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1204        """
1205        Validates an Expression, making sure that all its mandatory arguments are set.
1206
1207        Args:
1208            expression: The expression to validate.
1209            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1210
1211        Returns:
1212            The validated expression.
1213        """
1214        if self.error_level != ErrorLevel.IGNORE:
1215            for error_message in expression.error_messages(args):
1216                self.raise_error(error_message)
1217
1218        return expression
1219
1220    def _find_sql(self, start: Token, end: Token) -> str:
1221        return self.sql[start.start : end.end + 1]
1222
1223    def _is_connected(self) -> bool:
1224        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1225
1226    def _advance(self, times: int = 1) -> None:
1227        self._index += times
1228        self._curr = seq_get(self._tokens, self._index)
1229        self._next = seq_get(self._tokens, self._index + 1)
1230
1231        if self._index > 0:
1232            self._prev = self._tokens[self._index - 1]
1233            self._prev_comments = self._prev.comments
1234        else:
1235            self._prev = None
1236            self._prev_comments = None
1237
1238    def _retreat(self, index: int) -> None:
1239        if index != self._index:
1240            self._advance(index - self._index)
1241
1242    def _warn_unsupported(self) -> None:
1243        if len(self._tokens) <= 1:
1244            return
1245
1246        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1247        # interested in emitting a warning for the one being currently processed.
1248        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1249
1250        logger.warning(
1251            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1252        )
1253
1254    def _parse_command(self) -> exp.Command:
1255        self._warn_unsupported()
1256        return self.expression(
1257            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1258        )
1259
1260    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1261        start = self._prev
1262        exists = self._parse_exists() if allow_exists else None
1263
1264        self._match(TokenType.ON)
1265
1266        kind = self._match_set(self.CREATABLES) and self._prev
1267        if not kind:
1268            return self._parse_as_command(start)
1269
1270        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1271            this = self._parse_user_defined_function(kind=kind.token_type)
1272        elif kind.token_type == TokenType.TABLE:
1273            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1274        elif kind.token_type == TokenType.COLUMN:
1275            this = self._parse_column()
1276        else:
1277            this = self._parse_id_var()
1278
1279        self._match(TokenType.IS)
1280
1281        return self.expression(
1282            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
1283        )
1284
1285    def _parse_to_table(
1286        self,
1287    ) -> exp.ToTableProperty:
1288        table = self._parse_table_parts(schema=True)
1289        return self.expression(exp.ToTableProperty, this=table)
1290
1291    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1292    def _parse_ttl(self) -> exp.Expression:
1293        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1294            this = self._parse_bitwise()
1295
1296            if self._match_text_seq("DELETE"):
1297                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1298            if self._match_text_seq("RECOMPRESS"):
1299                return self.expression(
1300                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1301                )
1302            if self._match_text_seq("TO", "DISK"):
1303                return self.expression(
1304                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1305                )
1306            if self._match_text_seq("TO", "VOLUME"):
1307                return self.expression(
1308                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1309                )
1310
1311            return this
1312
1313        expressions = self._parse_csv(_parse_ttl_action)
1314        where = self._parse_where()
1315        group = self._parse_group()
1316
1317        aggregates = None
1318        if group and self._match(TokenType.SET):
1319            aggregates = self._parse_csv(self._parse_set_item)
1320
1321        return self.expression(
1322            exp.MergeTreeTTL,
1323            expressions=expressions,
1324            where=where,
1325            group=group,
1326            aggregates=aggregates,
1327        )
1328
1329    def _parse_statement(self) -> t.Optional[exp.Expression]:
1330        if self._curr is None:
1331            return None
1332
1333        if self._match_set(self.STATEMENT_PARSERS):
1334            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1335
1336        if self._match_set(Tokenizer.COMMANDS):
1337            return self._parse_command()
1338
1339        expression = self._parse_expression()
1340        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1341        return self._parse_query_modifiers(expression)
1342
1343    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1344        start = self._prev
1345        temporary = self._match(TokenType.TEMPORARY)
1346        materialized = self._match_text_seq("MATERIALIZED")
1347
1348        kind = self._match_set(self.CREATABLES) and self._prev.text
1349        if not kind:
1350            return self._parse_as_command(start)
1351
1352        return self.expression(
1353            exp.Drop,
1354            comments=start.comments,
1355            exists=exists or self._parse_exists(),
1356            this=self._parse_table(
1357                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1358            ),
1359            kind=kind,
1360            temporary=temporary,
1361            materialized=materialized,
1362            cascade=self._match_text_seq("CASCADE"),
1363            constraints=self._match_text_seq("CONSTRAINTS"),
1364            purge=self._match_text_seq("PURGE"),
1365        )
1366
1367    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1368        return (
1369            self._match_text_seq("IF")
1370            and (not not_ or self._match(TokenType.NOT))
1371            and self._match(TokenType.EXISTS)
1372        )
1373
1374    def _parse_create(self) -> exp.Create | exp.Command:
1375        # Note: this can't be None because we've matched a statement parser
1376        start = self._prev
1377        comments = self._prev_comments
1378
1379        replace = (
1380            start.token_type == TokenType.REPLACE
1381            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1382            or self._match_pair(TokenType.OR, TokenType.ALTER)
1383        )
1384        unique = self._match(TokenType.UNIQUE)
1385
1386        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1387            self._advance()
1388
1389        properties = None
1390        create_token = self._match_set(self.CREATABLES) and self._prev
1391
1392        if not create_token:
1393            # exp.Properties.Location.POST_CREATE
1394            properties = self._parse_properties()
1395            create_token = self._match_set(self.CREATABLES) and self._prev
1396
1397            if not properties or not create_token:
1398                return self._parse_as_command(start)
1399
1400        exists = self._parse_exists(not_=True)
1401        this = None
1402        expression: t.Optional[exp.Expression] = None
1403        indexes = None
1404        no_schema_binding = None
1405        begin = None
1406        end = None
1407        clone = None
1408
1409        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1410            nonlocal properties
1411            if properties and temp_props:
1412                properties.expressions.extend(temp_props.expressions)
1413            elif temp_props:
1414                properties = temp_props
1415
1416        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1417            this = self._parse_user_defined_function(kind=create_token.token_type)
1418
1419            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1420            extend_props(self._parse_properties())
1421
1422            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1423
1424            if not expression:
1425                if self._match(TokenType.COMMAND):
1426                    expression = self._parse_as_command(self._prev)
1427                else:
1428                    begin = self._match(TokenType.BEGIN)
1429                    return_ = self._match_text_seq("RETURN")
1430
1431                    if self._match(TokenType.STRING, advance=False):
1432                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1433                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1434                        expression = self._parse_string()
1435                        extend_props(self._parse_properties())
1436                    else:
1437                        expression = self._parse_statement()
1438
1439                    end = self._match_text_seq("END")
1440
1441                    if return_:
1442                        expression = self.expression(exp.Return, this=expression)
1443        elif create_token.token_type == TokenType.INDEX:
1444            this = self._parse_index(index=self._parse_id_var())
1445        elif create_token.token_type in self.DB_CREATABLES:
1446            table_parts = self._parse_table_parts(
1447                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1448            )
1449
1450            # exp.Properties.Location.POST_NAME
1451            self._match(TokenType.COMMA)
1452            extend_props(self._parse_properties(before=True))
1453
1454            this = self._parse_schema(this=table_parts)
1455
1456            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1457            extend_props(self._parse_properties())
1458
1459            self._match(TokenType.ALIAS)
1460            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1461                # exp.Properties.Location.POST_ALIAS
1462                extend_props(self._parse_properties())
1463
1464            expression = self._parse_ddl_select()
1465
1466            if create_token.token_type == TokenType.TABLE:
1467                # exp.Properties.Location.POST_EXPRESSION
1468                extend_props(self._parse_properties())
1469
1470                indexes = []
1471                while True:
1472                    index = self._parse_index()
1473
1474                    # exp.Properties.Location.POST_INDEX
1475                    extend_props(self._parse_properties())
1476
1477                    if not index:
1478                        break
1479                    else:
1480                        self._match(TokenType.COMMA)
1481                        indexes.append(index)
1482            elif create_token.token_type == TokenType.VIEW:
1483                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1484                    no_schema_binding = True
1485
1486            shallow = self._match_text_seq("SHALLOW")
1487
1488            if self._match_texts(self.CLONE_KEYWORDS):
1489                copy = self._prev.text.lower() == "copy"
1490                clone = self.expression(
1491                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1492                )
1493
1494        if self._curr:
1495            return self._parse_as_command(start)
1496
1497        return self.expression(
1498            exp.Create,
1499            comments=comments,
1500            this=this,
1501            kind=create_token.text.upper(),
1502            replace=replace,
1503            unique=unique,
1504            expression=expression,
1505            exists=exists,
1506            properties=properties,
1507            indexes=indexes,
1508            no_schema_binding=no_schema_binding,
1509            begin=begin,
1510            end=end,
1511            clone=clone,
1512        )
1513
1514    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1515        # only used for teradata currently
1516        self._match(TokenType.COMMA)
1517
1518        kwargs = {
1519            "no": self._match_text_seq("NO"),
1520            "dual": self._match_text_seq("DUAL"),
1521            "before": self._match_text_seq("BEFORE"),
1522            "default": self._match_text_seq("DEFAULT"),
1523            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1524            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1525            "after": self._match_text_seq("AFTER"),
1526            "minimum": self._match_texts(("MIN", "MINIMUM")),
1527            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1528        }
1529
1530        if self._match_texts(self.PROPERTY_PARSERS):
1531            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1532            try:
1533                return parser(self, **{k: v for k, v in kwargs.items() if v})
1534            except TypeError:
1535                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1536
1537        return None
1538
1539    def _parse_property(self) -> t.Optional[exp.Expression]:
1540        if self._match_texts(self.PROPERTY_PARSERS):
1541            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1542
1543        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1544            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1545
1546        if self._match_text_seq("COMPOUND", "SORTKEY"):
1547            return self._parse_sortkey(compound=True)
1548
1549        if self._match_text_seq("SQL", "SECURITY"):
1550            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1551
1552        index = self._index
1553        key = self._parse_column()
1554
1555        if not self._match(TokenType.EQ):
1556            self._retreat(index)
1557            return None
1558
1559        return self.expression(
1560            exp.Property,
1561            this=key.to_dot() if isinstance(key, exp.Column) else key,
1562            value=self._parse_column() or self._parse_var(any_token=True),
1563        )
1564
1565    def _parse_stored(self) -> exp.FileFormatProperty:
1566        self._match(TokenType.ALIAS)
1567
1568        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1569        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1570
1571        return self.expression(
1572            exp.FileFormatProperty,
1573            this=(
1574                self.expression(
1575                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1576                )
1577                if input_format or output_format
1578                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1579            ),
1580        )
1581
1582    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1583        self._match(TokenType.EQ)
1584        self._match(TokenType.ALIAS)
1585        return self.expression(exp_class, this=self._parse_field(), **kwargs)
1586
1587    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1588        properties = []
1589        while True:
1590            if before:
1591                prop = self._parse_property_before()
1592            else:
1593                prop = self._parse_property()
1594
1595            if not prop:
1596                break
1597            for p in ensure_list(prop):
1598                properties.append(p)
1599
1600        if properties:
1601            return self.expression(exp.Properties, expressions=properties)
1602
1603        return None
1604
1605    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1606        return self.expression(
1607            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1608        )
1609
1610    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1611        if self._index >= 2:
1612            pre_volatile_token = self._tokens[self._index - 2]
1613        else:
1614            pre_volatile_token = None
1615
1616        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1617            return exp.VolatileProperty()
1618
1619        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1620
1621    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1622        self._match_pair(TokenType.EQ, TokenType.ON)
1623
1624        prop = self.expression(exp.WithSystemVersioningProperty)
1625        if self._match(TokenType.L_PAREN):
1626            self._match_text_seq("HISTORY_TABLE", "=")
1627            prop.set("this", self._parse_table_parts())
1628
1629            if self._match(TokenType.COMMA):
1630                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1631                prop.set("expression", self._advance_any() and self._prev.text.upper())
1632
1633            self._match_r_paren()
1634
1635        return prop
1636
1637    def _parse_with_property(
1638        self,
1639    ) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1640        if self._match(TokenType.L_PAREN, advance=False):
1641            return self._parse_wrapped_csv(self._parse_property)
1642
1643        if self._match_text_seq("JOURNAL"):
1644            return self._parse_withjournaltable()
1645
1646        if self._match_text_seq("DATA"):
1647            return self._parse_withdata(no=False)
1648        elif self._match_text_seq("NO", "DATA"):
1649            return self._parse_withdata(no=True)
1650
1651        if not self._next:
1652            return None
1653
1654        return self._parse_withisolatedloading()
1655
1656    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1657    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1658        self._match(TokenType.EQ)
1659
1660        user = self._parse_id_var()
1661        self._match(TokenType.PARAMETER)
1662        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1663
1664        if not user or not host:
1665            return None
1666
1667        return exp.DefinerProperty(this=f"{user}@{host}")
1668
1669    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1670        self._match(TokenType.TABLE)
1671        self._match(TokenType.EQ)
1672        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1673
1674    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1675        return self.expression(exp.LogProperty, no=no)
1676
1677    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1678        return self.expression(exp.JournalProperty, **kwargs)
1679
1680    def _parse_checksum(self) -> exp.ChecksumProperty:
1681        self._match(TokenType.EQ)
1682
1683        on = None
1684        if self._match(TokenType.ON):
1685            on = True
1686        elif self._match_text_seq("OFF"):
1687            on = False
1688
1689        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1690
1691    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
1692        return self.expression(
1693            exp.Cluster,
1694            expressions=(
1695                self._parse_wrapped_csv(self._parse_ordered)
1696                if wrapped
1697                else self._parse_csv(self._parse_ordered)
1698            ),
1699        )
1700
1701    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1702        self._match_text_seq("BY")
1703
1704        self._match_l_paren()
1705        expressions = self._parse_csv(self._parse_column)
1706        self._match_r_paren()
1707
1708        if self._match_text_seq("SORTED", "BY"):
1709            self._match_l_paren()
1710            sorted_by = self._parse_csv(self._parse_ordered)
1711            self._match_r_paren()
1712        else:
1713            sorted_by = None
1714
1715        self._match(TokenType.INTO)
1716        buckets = self._parse_number()
1717        self._match_text_seq("BUCKETS")
1718
1719        return self.expression(
1720            exp.ClusteredByProperty,
1721            expressions=expressions,
1722            sorted_by=sorted_by,
1723            buckets=buckets,
1724        )
1725
1726    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1727        if not self._match_text_seq("GRANTS"):
1728            self._retreat(self._index - 1)
1729            return None
1730
1731        return self.expression(exp.CopyGrantsProperty)
1732
1733    def _parse_freespace(self) -> exp.FreespaceProperty:
1734        self._match(TokenType.EQ)
1735        return self.expression(
1736            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1737        )
1738
1739    def _parse_mergeblockratio(
1740        self, no: bool = False, default: bool = False
1741    ) -> exp.MergeBlockRatioProperty:
1742        if self._match(TokenType.EQ):
1743            return self.expression(
1744                exp.MergeBlockRatioProperty,
1745                this=self._parse_number(),
1746                percent=self._match(TokenType.PERCENT),
1747            )
1748
1749        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1750
1751    def _parse_datablocksize(
1752        self,
1753        default: t.Optional[bool] = None,
1754        minimum: t.Optional[bool] = None,
1755        maximum: t.Optional[bool] = None,
1756    ) -> exp.DataBlocksizeProperty:
1757        self._match(TokenType.EQ)
1758        size = self._parse_number()
1759
1760        units = None
1761        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1762            units = self._prev.text
1763
1764        return self.expression(
1765            exp.DataBlocksizeProperty,
1766            size=size,
1767            units=units,
1768            default=default,
1769            minimum=minimum,
1770            maximum=maximum,
1771        )
1772
1773    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1774        self._match(TokenType.EQ)
1775        always = self._match_text_seq("ALWAYS")
1776        manual = self._match_text_seq("MANUAL")
1777        never = self._match_text_seq("NEVER")
1778        default = self._match_text_seq("DEFAULT")
1779
1780        autotemp = None
1781        if self._match_text_seq("AUTOTEMP"):
1782            autotemp = self._parse_schema()
1783
1784        return self.expression(
1785            exp.BlockCompressionProperty,
1786            always=always,
1787            manual=manual,
1788            never=never,
1789            default=default,
1790            autotemp=autotemp,
1791        )
1792
1793    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
1794        no = self._match_text_seq("NO")
1795        concurrent = self._match_text_seq("CONCURRENT")
1796        self._match_text_seq("ISOLATED", "LOADING")
1797        for_all = self._match_text_seq("FOR", "ALL")
1798        for_insert = self._match_text_seq("FOR", "INSERT")
1799        for_none = self._match_text_seq("FOR", "NONE")
1800        return self.expression(
1801            exp.IsolatedLoadingProperty,
1802            no=no,
1803            concurrent=concurrent,
1804            for_all=for_all,
1805            for_insert=for_insert,
1806            for_none=for_none,
1807        )
1808
1809    def _parse_locking(self) -> exp.LockingProperty:
1810        if self._match(TokenType.TABLE):
1811            kind = "TABLE"
1812        elif self._match(TokenType.VIEW):
1813            kind = "VIEW"
1814        elif self._match(TokenType.ROW):
1815            kind = "ROW"
1816        elif self._match_text_seq("DATABASE"):
1817            kind = "DATABASE"
1818        else:
1819            kind = None
1820
1821        if kind in ("DATABASE", "TABLE", "VIEW"):
1822            this = self._parse_table_parts()
1823        else:
1824            this = None
1825
1826        if self._match(TokenType.FOR):
1827            for_or_in = "FOR"
1828        elif self._match(TokenType.IN):
1829            for_or_in = "IN"
1830        else:
1831            for_or_in = None
1832
1833        if self._match_text_seq("ACCESS"):
1834            lock_type = "ACCESS"
1835        elif self._match_texts(("EXCL", "EXCLUSIVE")):
1836            lock_type = "EXCLUSIVE"
1837        elif self._match_text_seq("SHARE"):
1838            lock_type = "SHARE"
1839        elif self._match_text_seq("READ"):
1840            lock_type = "READ"
1841        elif self._match_text_seq("WRITE"):
1842            lock_type = "WRITE"
1843        elif self._match_text_seq("CHECKSUM"):
1844            lock_type = "CHECKSUM"
1845        else:
1846            lock_type = None
1847
1848        override = self._match_text_seq("OVERRIDE")
1849
1850        return self.expression(
1851            exp.LockingProperty,
1852            this=this,
1853            kind=kind,
1854            for_or_in=for_or_in,
1855            lock_type=lock_type,
1856            override=override,
1857        )
1858
1859    def _parse_partition_by(self) -> t.List[exp.Expression]:
1860        if self._match(TokenType.PARTITION_BY):
1861            return self._parse_csv(self._parse_conjunction)
1862        return []
1863
1864    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
1865        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
1866            if self._match_text_seq("MINVALUE"):
1867                return exp.var("MINVALUE")
1868            if self._match_text_seq("MAXVALUE"):
1869                return exp.var("MAXVALUE")
1870            return self._parse_bitwise()
1871
1872        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
1873        expression = None
1874        from_expressions = None
1875        to_expressions = None
1876
1877        if self._match(TokenType.IN):
1878            this = self._parse_wrapped_csv(self._parse_bitwise)
1879        elif self._match(TokenType.FROM):
1880            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1881            self._match_text_seq("TO")
1882            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1883        elif self._match_text_seq("WITH", "(", "MODULUS"):
1884            this = self._parse_number()
1885            self._match_text_seq(",", "REMAINDER")
1886            expression = self._parse_number()
1887            self._match_r_paren()
1888        else:
1889            self.raise_error("Failed to parse partition bound spec.")
1890
1891        return self.expression(
1892            exp.PartitionBoundSpec,
1893            this=this,
1894            expression=expression,
1895            from_expressions=from_expressions,
1896            to_expressions=to_expressions,
1897        )
1898
1899    # https://www.postgresql.org/docs/current/sql-createtable.html
1900    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
1901        if not self._match_text_seq("OF"):
1902            self._retreat(self._index - 1)
1903            return None
1904
1905        this = self._parse_table(schema=True)
1906
1907        if self._match(TokenType.DEFAULT):
1908            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
1909        elif self._match_text_seq("FOR", "VALUES"):
1910            expression = self._parse_partition_bound_spec()
1911        else:
1912            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
1913
1914        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
1915
1916    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
1917        self._match(TokenType.EQ)
1918        return self.expression(
1919            exp.PartitionedByProperty,
1920            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
1921        )
1922
1923    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
1924        if self._match_text_seq("AND", "STATISTICS"):
1925            statistics = True
1926        elif self._match_text_seq("AND", "NO", "STATISTICS"):
1927            statistics = False
1928        else:
1929            statistics = None
1930
1931        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
1932
1933    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1934        if self._match_text_seq("SQL"):
1935            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
1936        return None
1937
1938    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1939        if self._match_text_seq("SQL", "DATA"):
1940            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
1941        return None
1942
1943    def _parse_no_property(self) -> t.Optional[exp.Expression]:
1944        if self._match_text_seq("PRIMARY", "INDEX"):
1945            return exp.NoPrimaryIndexProperty()
1946        if self._match_text_seq("SQL"):
1947            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
1948        return None
1949
1950    def _parse_on_property(self) -> t.Optional[exp.Expression]:
1951        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
1952            return exp.OnCommitProperty()
1953        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
1954            return exp.OnCommitProperty(delete=True)
1955        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
1956
1957    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1958        if self._match_text_seq("SQL", "DATA"):
1959            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
1960        return None
1961
1962    def _parse_distkey(self) -> exp.DistKeyProperty:
1963        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
1964
1965    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
1966        table = self._parse_table(schema=True)
1967
1968        options = []
1969        while self._match_texts(("INCLUDING", "EXCLUDING")):
1970            this = self._prev.text.upper()
1971
1972            id_var = self._parse_id_var()
1973            if not id_var:
1974                return None
1975
1976            options.append(
1977                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
1978            )
1979
1980        return self.expression(exp.LikeProperty, this=table, expressions=options)
1981
1982    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
1983        return self.expression(
1984            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
1985        )
1986
1987    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
1988        self._match(TokenType.EQ)
1989        return self.expression(
1990            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
1991        )
1992
1993    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
1994        self._match_text_seq("WITH", "CONNECTION")
1995        return self.expression(
1996            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
1997        )
1998
1999    def _parse_returns(self) -> exp.ReturnsProperty:
2000        value: t.Optional[exp.Expression]
2001        is_table = self._match(TokenType.TABLE)
2002
2003        if is_table:
2004            if self._match(TokenType.LT):
2005                value = self.expression(
2006                    exp.Schema,
2007                    this="TABLE",
2008                    expressions=self._parse_csv(self._parse_struct_types),
2009                )
2010                if not self._match(TokenType.GT):
2011                    self.raise_error("Expecting >")
2012            else:
2013                value = self._parse_schema(exp.var("TABLE"))
2014        else:
2015            value = self._parse_types()
2016
2017        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
2018
2019    def _parse_describe(self) -> exp.Describe:
2020        kind = self._match_set(self.CREATABLES) and self._prev.text
2021        extended = self._match_text_seq("EXTENDED")
2022        this = self._parse_table(schema=True)
2023        properties = self._parse_properties()
2024        expressions = properties.expressions if properties else None
2025        return self.expression(
2026            exp.Describe, this=this, extended=extended, kind=kind, expressions=expressions
2027        )
2028
2029    def _parse_insert(self) -> exp.Insert:
2030        comments = ensure_list(self._prev_comments)
2031        overwrite = self._match(TokenType.OVERWRITE)
2032        ignore = self._match(TokenType.IGNORE)
2033        local = self._match_text_seq("LOCAL")
2034        alternative = None
2035
2036        if self._match_text_seq("DIRECTORY"):
2037            this: t.Optional[exp.Expression] = self.expression(
2038                exp.Directory,
2039                this=self._parse_var_or_string(),
2040                local=local,
2041                row_format=self._parse_row_format(match_row=True),
2042            )
2043        else:
2044            if self._match(TokenType.OR):
2045                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2046
2047            self._match(TokenType.INTO)
2048            comments += ensure_list(self._prev_comments)
2049            self._match(TokenType.TABLE)
2050            this = self._parse_table(schema=True)
2051
2052        returning = self._parse_returning()
2053
2054        return self.expression(
2055            exp.Insert,
2056            comments=comments,
2057            this=this,
2058            by_name=self._match_text_seq("BY", "NAME"),
2059            exists=self._parse_exists(),
2060            partition=self._parse_partition(),
2061            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
2062            and self._parse_conjunction(),
2063            expression=self._parse_ddl_select(),
2064            conflict=self._parse_on_conflict(),
2065            returning=returning or self._parse_returning(),
2066            overwrite=overwrite,
2067            alternative=alternative,
2068            ignore=ignore,
2069        )
2070
2071    def _parse_kill(self) -> exp.Kill:
2072        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2073
2074        return self.expression(
2075            exp.Kill,
2076            this=self._parse_primary(),
2077            kind=kind,
2078        )
2079
2080    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2081        conflict = self._match_text_seq("ON", "CONFLICT")
2082        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2083
2084        if not conflict and not duplicate:
2085            return None
2086
2087        nothing = None
2088        expressions = None
2089        key = None
2090        constraint = None
2091
2092        if conflict:
2093            if self._match_text_seq("ON", "CONSTRAINT"):
2094                constraint = self._parse_id_var()
2095            else:
2096                key = self._parse_csv(self._parse_value)
2097
2098        self._match_text_seq("DO")
2099        if self._match_text_seq("NOTHING"):
2100            nothing = True
2101        else:
2102            self._match(TokenType.UPDATE)
2103            self._match(TokenType.SET)
2104            expressions = self._parse_csv(self._parse_equality)
2105
2106        return self.expression(
2107            exp.OnConflict,
2108            duplicate=duplicate,
2109            expressions=expressions,
2110            nothing=nothing,
2111            key=key,
2112            constraint=constraint,
2113        )
2114
2115    def _parse_returning(self) -> t.Optional[exp.Returning]:
2116        if not self._match(TokenType.RETURNING):
2117            return None
2118        return self.expression(
2119            exp.Returning,
2120            expressions=self._parse_csv(self._parse_expression),
2121            into=self._match(TokenType.INTO) and self._parse_table_part(),
2122        )
2123
2124    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2125        if not self._match(TokenType.FORMAT):
2126            return None
2127        return self._parse_row_format()
2128
2129    def _parse_row_format(
2130        self, match_row: bool = False
2131    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2132        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2133            return None
2134
2135        if self._match_text_seq("SERDE"):
2136            this = self._parse_string()
2137
2138            serde_properties = None
2139            if self._match(TokenType.SERDE_PROPERTIES):
2140                serde_properties = self.expression(
2141                    exp.SerdeProperties, expressions=self._parse_wrapped_csv(self._parse_property)
2142                )
2143
2144            return self.expression(
2145                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2146            )
2147
2148        self._match_text_seq("DELIMITED")
2149
2150        kwargs = {}
2151
2152        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2153            kwargs["fields"] = self._parse_string()
2154            if self._match_text_seq("ESCAPED", "BY"):
2155                kwargs["escaped"] = self._parse_string()
2156        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2157            kwargs["collection_items"] = self._parse_string()
2158        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2159            kwargs["map_keys"] = self._parse_string()
2160        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2161            kwargs["lines"] = self._parse_string()
2162        if self._match_text_seq("NULL", "DEFINED", "AS"):
2163            kwargs["null"] = self._parse_string()
2164
2165        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2166
2167    def _parse_load(self) -> exp.LoadData | exp.Command:
2168        if self._match_text_seq("DATA"):
2169            local = self._match_text_seq("LOCAL")
2170            self._match_text_seq("INPATH")
2171            inpath = self._parse_string()
2172            overwrite = self._match(TokenType.OVERWRITE)
2173            self._match_pair(TokenType.INTO, TokenType.TABLE)
2174
2175            return self.expression(
2176                exp.LoadData,
2177                this=self._parse_table(schema=True),
2178                local=local,
2179                overwrite=overwrite,
2180                inpath=inpath,
2181                partition=self._parse_partition(),
2182                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2183                serde=self._match_text_seq("SERDE") and self._parse_string(),
2184            )
2185        return self._parse_as_command(self._prev)
2186
2187    def _parse_delete(self) -> exp.Delete:
2188        # This handles MySQL's "Multiple-Table Syntax"
2189        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2190        tables = None
2191        comments = self._prev_comments
2192        if not self._match(TokenType.FROM, advance=False):
2193            tables = self._parse_csv(self._parse_table) or None
2194
2195        returning = self._parse_returning()
2196
2197        return self.expression(
2198            exp.Delete,
2199            comments=comments,
2200            tables=tables,
2201            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2202            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2203            where=self._parse_where(),
2204            returning=returning or self._parse_returning(),
2205            limit=self._parse_limit(),
2206        )
2207
2208    def _parse_update(self) -> exp.Update:
2209        comments = self._prev_comments
2210        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2211        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2212        returning = self._parse_returning()
2213        return self.expression(
2214            exp.Update,
2215            comments=comments,
2216            **{  # type: ignore
2217                "this": this,
2218                "expressions": expressions,
2219                "from": self._parse_from(joins=True),
2220                "where": self._parse_where(),
2221                "returning": returning or self._parse_returning(),
2222                "order": self._parse_order(),
2223                "limit": self._parse_limit(),
2224            },
2225        )
2226
2227    def _parse_uncache(self) -> exp.Uncache:
2228        if not self._match(TokenType.TABLE):
2229            self.raise_error("Expecting TABLE after UNCACHE")
2230
2231        return self.expression(
2232            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2233        )
2234
2235    def _parse_cache(self) -> exp.Cache:
2236        lazy = self._match_text_seq("LAZY")
2237        self._match(TokenType.TABLE)
2238        table = self._parse_table(schema=True)
2239
2240        options = []
2241        if self._match_text_seq("OPTIONS"):
2242            self._match_l_paren()
2243            k = self._parse_string()
2244            self._match(TokenType.EQ)
2245            v = self._parse_string()
2246            options = [k, v]
2247            self._match_r_paren()
2248
2249        self._match(TokenType.ALIAS)
2250        return self.expression(
2251            exp.Cache,
2252            this=table,
2253            lazy=lazy,
2254            options=options,
2255            expression=self._parse_select(nested=True),
2256        )
2257
2258    def _parse_partition(self) -> t.Optional[exp.Partition]:
2259        if not self._match(TokenType.PARTITION):
2260            return None
2261
2262        return self.expression(
2263            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2264        )
2265
2266    def _parse_value(self) -> exp.Tuple:
2267        if self._match(TokenType.L_PAREN):
2268            expressions = self._parse_csv(self._parse_expression)
2269            self._match_r_paren()
2270            return self.expression(exp.Tuple, expressions=expressions)
2271
2272        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
2273        # https://prestodb.io/docs/current/sql/values.html
2274        return self.expression(exp.Tuple, expressions=[self._parse_expression()])
2275
2276    def _parse_projections(self) -> t.List[exp.Expression]:
2277        return self._parse_expressions()
2278
2279    def _parse_select(
2280        self,
2281        nested: bool = False,
2282        table: bool = False,
2283        parse_subquery_alias: bool = True,
2284        parse_set_operation: bool = True,
2285    ) -> t.Optional[exp.Expression]:
2286        cte = self._parse_with()
2287
2288        if cte:
2289            this = self._parse_statement()
2290
2291            if not this:
2292                self.raise_error("Failed to parse any statement following CTE")
2293                return cte
2294
2295            if "with" in this.arg_types:
2296                this.set("with", cte)
2297            else:
2298                self.raise_error(f"{this.key} does not support CTE")
2299                this = cte
2300
2301            return this
2302
2303        # duckdb supports leading with FROM x
2304        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2305
2306        if self._match(TokenType.SELECT):
2307            comments = self._prev_comments
2308
2309            hint = self._parse_hint()
2310            all_ = self._match(TokenType.ALL)
2311            distinct = self._match_set(self.DISTINCT_TOKENS)
2312
2313            kind = (
2314                self._match(TokenType.ALIAS)
2315                and self._match_texts(("STRUCT", "VALUE"))
2316                and self._prev.text.upper()
2317            )
2318
2319            if distinct:
2320                distinct = self.expression(
2321                    exp.Distinct,
2322                    on=self._parse_value() if self._match(TokenType.ON) else None,
2323                )
2324
2325            if all_ and distinct:
2326                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2327
2328            limit = self._parse_limit(top=True)
2329            projections = self._parse_projections()
2330
2331            this = self.expression(
2332                exp.Select,
2333                kind=kind,
2334                hint=hint,
2335                distinct=distinct,
2336                expressions=projections,
2337                limit=limit,
2338            )
2339            this.comments = comments
2340
2341            into = self._parse_into()
2342            if into:
2343                this.set("into", into)
2344
2345            if not from_:
2346                from_ = self._parse_from()
2347
2348            if from_:
2349                this.set("from", from_)
2350
2351            this = self._parse_query_modifiers(this)
2352        elif (table or nested) and self._match(TokenType.L_PAREN):
2353            if self._match(TokenType.PIVOT):
2354                this = self._parse_simplified_pivot()
2355            elif self._match(TokenType.FROM):
2356                this = exp.select("*").from_(
2357                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2358                )
2359            else:
2360                this = (
2361                    self._parse_table()
2362                    if table
2363                    else self._parse_select(nested=True, parse_set_operation=False)
2364                )
2365                this = self._parse_query_modifiers(self._parse_set_operations(this))
2366
2367            self._match_r_paren()
2368
2369            # We return early here so that the UNION isn't attached to the subquery by the
2370            # following call to _parse_set_operations, but instead becomes the parent node
2371            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2372        elif self._match(TokenType.VALUES):
2373            this = self.expression(
2374                exp.Values,
2375                expressions=self._parse_csv(self._parse_value),
2376                alias=self._parse_table_alias(),
2377            )
2378        elif from_:
2379            this = exp.select("*").from_(from_.this, copy=False)
2380        else:
2381            this = None
2382
2383        if parse_set_operation:
2384            return self._parse_set_operations(this)
2385        return this
2386
2387    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2388        if not skip_with_token and not self._match(TokenType.WITH):
2389            return None
2390
2391        comments = self._prev_comments
2392        recursive = self._match(TokenType.RECURSIVE)
2393
2394        expressions = []
2395        while True:
2396            expressions.append(self._parse_cte())
2397
2398            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2399                break
2400            else:
2401                self._match(TokenType.WITH)
2402
2403        return self.expression(
2404            exp.With, comments=comments, expressions=expressions, recursive=recursive
2405        )
2406
2407    def _parse_cte(self) -> exp.CTE:
2408        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2409        if not alias or not alias.this:
2410            self.raise_error("Expected CTE to have alias")
2411
2412        self._match(TokenType.ALIAS)
2413        return self.expression(
2414            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
2415        )
2416
2417    def _parse_table_alias(
2418        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2419    ) -> t.Optional[exp.TableAlias]:
2420        any_token = self._match(TokenType.ALIAS)
2421        alias = (
2422            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2423            or self._parse_string_as_identifier()
2424        )
2425
2426        index = self._index
2427        if self._match(TokenType.L_PAREN):
2428            columns = self._parse_csv(self._parse_function_parameter)
2429            self._match_r_paren() if columns else self._retreat(index)
2430        else:
2431            columns = None
2432
2433        if not alias and not columns:
2434            return None
2435
2436        return self.expression(exp.TableAlias, this=alias, columns=columns)
2437
2438    def _parse_subquery(
2439        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2440    ) -> t.Optional[exp.Subquery]:
2441        if not this:
2442            return None
2443
2444        return self.expression(
2445            exp.Subquery,
2446            this=this,
2447            pivots=self._parse_pivots(),
2448            alias=self._parse_table_alias() if parse_alias else None,
2449        )
2450
2451    def _parse_query_modifiers(
2452        self, this: t.Optional[exp.Expression]
2453    ) -> t.Optional[exp.Expression]:
2454        if isinstance(this, self.MODIFIABLES):
2455            for join in iter(self._parse_join, None):
2456                this.append("joins", join)
2457            for lateral in iter(self._parse_lateral, None):
2458                this.append("laterals", lateral)
2459
2460            while True:
2461                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2462                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2463                    key, expression = parser(self)
2464
2465                    if expression:
2466                        this.set(key, expression)
2467                        if key == "limit":
2468                            offset = expression.args.pop("offset", None)
2469                            if offset:
2470                                this.set("offset", exp.Offset(expression=offset))
2471                        continue
2472                break
2473        return this
2474
2475    def _parse_hint(self) -> t.Optional[exp.Hint]:
2476        if self._match(TokenType.HINT):
2477            hints = []
2478            for hint in iter(lambda: self._parse_csv(self._parse_function), []):
2479                hints.extend(hint)
2480
2481            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2482                self.raise_error("Expected */ after HINT")
2483
2484            return self.expression(exp.Hint, expressions=hints)
2485
2486        return None
2487
2488    def _parse_into(self) -> t.Optional[exp.Into]:
2489        if not self._match(TokenType.INTO):
2490            return None
2491
2492        temp = self._match(TokenType.TEMPORARY)
2493        unlogged = self._match_text_seq("UNLOGGED")
2494        self._match(TokenType.TABLE)
2495
2496        return self.expression(
2497            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2498        )
2499
2500    def _parse_from(
2501        self, joins: bool = False, skip_from_token: bool = False
2502    ) -> t.Optional[exp.From]:
2503        if not skip_from_token and not self._match(TokenType.FROM):
2504            return None
2505
2506        return self.expression(
2507            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2508        )
2509
2510    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2511        if not self._match(TokenType.MATCH_RECOGNIZE):
2512            return None
2513
2514        self._match_l_paren()
2515
2516        partition = self._parse_partition_by()
2517        order = self._parse_order()
2518        measures = self._parse_expressions() if self._match_text_seq("MEASURES") else None
2519
2520        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2521            rows = exp.var("ONE ROW PER MATCH")
2522        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2523            text = "ALL ROWS PER MATCH"
2524            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2525                text += " SHOW EMPTY MATCHES"
2526            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2527                text += " OMIT EMPTY MATCHES"
2528            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2529                text += " WITH UNMATCHED ROWS"
2530            rows = exp.var(text)
2531        else:
2532            rows = None
2533
2534        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2535            text = "AFTER MATCH SKIP"
2536            if self._match_text_seq("PAST", "LAST", "ROW"):
2537                text += " PAST LAST ROW"
2538            elif self._match_text_seq("TO", "NEXT", "ROW"):
2539                text += " TO NEXT ROW"
2540            elif self._match_text_seq("TO", "FIRST"):
2541                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2542            elif self._match_text_seq("TO", "LAST"):
2543                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2544            after = exp.var(text)
2545        else:
2546            after = None
2547
2548        if self._match_text_seq("PATTERN"):
2549            self._match_l_paren()
2550
2551            if not self._curr:
2552                self.raise_error("Expecting )", self._curr)
2553
2554            paren = 1
2555            start = self._curr
2556
2557            while self._curr and paren > 0:
2558                if self._curr.token_type == TokenType.L_PAREN:
2559                    paren += 1
2560                if self._curr.token_type == TokenType.R_PAREN:
2561                    paren -= 1
2562
2563                end = self._prev
2564                self._advance()
2565
2566            if paren > 0:
2567                self.raise_error("Expecting )", self._curr)
2568
2569            pattern = exp.var(self._find_sql(start, end))
2570        else:
2571            pattern = None
2572
2573        define = (
2574            self._parse_csv(self._parse_name_as_expression)
2575            if self._match_text_seq("DEFINE")
2576            else None
2577        )
2578
2579        self._match_r_paren()
2580
2581        return self.expression(
2582            exp.MatchRecognize,
2583            partition_by=partition,
2584            order=order,
2585            measures=measures,
2586            rows=rows,
2587            after=after,
2588            pattern=pattern,
2589            define=define,
2590            alias=self._parse_table_alias(),
2591        )
2592
2593    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2594        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2595        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2596            cross_apply = False
2597
2598        if cross_apply is not None:
2599            this = self._parse_select(table=True)
2600            view = None
2601            outer = None
2602        elif self._match(TokenType.LATERAL):
2603            this = self._parse_select(table=True)
2604            view = self._match(TokenType.VIEW)
2605            outer = self._match(TokenType.OUTER)
2606        else:
2607            return None
2608
2609        if not this:
2610            this = (
2611                self._parse_unnest()
2612                or self._parse_function()
2613                or self._parse_id_var(any_token=False)
2614            )
2615
2616            while self._match(TokenType.DOT):
2617                this = exp.Dot(
2618                    this=this,
2619                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2620                )
2621
2622        if view:
2623            table = self._parse_id_var(any_token=False)
2624            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2625            table_alias: t.Optional[exp.TableAlias] = self.expression(
2626                exp.TableAlias, this=table, columns=columns
2627            )
2628        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2629            # We move the alias from the lateral's child node to the lateral itself
2630            table_alias = this.args["alias"].pop()
2631        else:
2632            table_alias = self._parse_table_alias()
2633
2634        return self.expression(
2635            exp.Lateral,
2636            this=this,
2637            view=view,
2638            outer=outer,
2639            alias=table_alias,
2640            cross_apply=cross_apply,
2641        )
2642
2643    def _parse_join_parts(
2644        self,
2645    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2646        return (
2647            self._match_set(self.JOIN_METHODS) and self._prev,
2648            self._match_set(self.JOIN_SIDES) and self._prev,
2649            self._match_set(self.JOIN_KINDS) and self._prev,
2650        )
2651
2652    def _parse_join(
2653        self, skip_join_token: bool = False, parse_bracket: bool = False
2654    ) -> t.Optional[exp.Join]:
2655        if self._match(TokenType.COMMA):
2656            return self.expression(exp.Join, this=self._parse_table())
2657
2658        index = self._index
2659        method, side, kind = self._parse_join_parts()
2660        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2661        join = self._match(TokenType.JOIN)
2662
2663        if not skip_join_token and not join:
2664            self._retreat(index)
2665            kind = None
2666            method = None
2667            side = None
2668
2669        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2670        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2671
2672        if not skip_join_token and not join and not outer_apply and not cross_apply:
2673            return None
2674
2675        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2676
2677        if method:
2678            kwargs["method"] = method.text
2679        if side:
2680            kwargs["side"] = side.text
2681        if kind:
2682            kwargs["kind"] = kind.text
2683        if hint:
2684            kwargs["hint"] = hint
2685
2686        if self._match(TokenType.ON):
2687            kwargs["on"] = self._parse_conjunction()
2688        elif self._match(TokenType.USING):
2689            kwargs["using"] = self._parse_wrapped_id_vars()
2690        elif not (kind and kind.token_type == TokenType.CROSS):
2691            index = self._index
2692            join = self._parse_join()
2693
2694            if join and self._match(TokenType.ON):
2695                kwargs["on"] = self._parse_conjunction()
2696            elif join and self._match(TokenType.USING):
2697                kwargs["using"] = self._parse_wrapped_id_vars()
2698            else:
2699                join = None
2700                self._retreat(index)
2701
2702            kwargs["this"].set("joins", [join] if join else None)
2703
2704        comments = [c for token in (method, side, kind) if token for c in token.comments]
2705        return self.expression(exp.Join, comments=comments, **kwargs)
2706
2707    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2708        this = self._parse_conjunction()
2709        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2710            return this
2711
2712        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2713            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
2714
2715        return this
2716
2717    def _parse_index(
2718        self,
2719        index: t.Optional[exp.Expression] = None,
2720    ) -> t.Optional[exp.Index]:
2721        if index:
2722            unique = None
2723            primary = None
2724            amp = None
2725
2726            self._match(TokenType.ON)
2727            self._match(TokenType.TABLE)  # hive
2728            table = self._parse_table_parts(schema=True)
2729        else:
2730            unique = self._match(TokenType.UNIQUE)
2731            primary = self._match_text_seq("PRIMARY")
2732            amp = self._match_text_seq("AMP")
2733
2734            if not self._match(TokenType.INDEX):
2735                return None
2736
2737            index = self._parse_id_var()
2738            table = None
2739
2740        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
2741
2742        if self._match(TokenType.L_PAREN, advance=False):
2743            columns = self._parse_wrapped_csv(lambda: self._parse_ordered(self._parse_opclass))
2744        else:
2745            columns = None
2746
2747        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
2748
2749        return self.expression(
2750            exp.Index,
2751            this=index,
2752            table=table,
2753            using=using,
2754            columns=columns,
2755            unique=unique,
2756            primary=primary,
2757            amp=amp,
2758            include=include,
2759            partition_by=self._parse_partition_by(),
2760            where=self._parse_where(),
2761        )
2762
2763    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
2764        hints: t.List[exp.Expression] = []
2765        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
2766            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
2767            hints.append(
2768                self.expression(
2769                    exp.WithTableHint,
2770                    expressions=self._parse_csv(
2771                        lambda: self._parse_function() or self._parse_var(any_token=True)
2772                    ),
2773                )
2774            )
2775            self._match_r_paren()
2776        else:
2777            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
2778            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
2779                hint = exp.IndexTableHint(this=self._prev.text.upper())
2780
2781                self._match_texts(("INDEX", "KEY"))
2782                if self._match(TokenType.FOR):
2783                    hint.set("target", self._advance_any() and self._prev.text.upper())
2784
2785                hint.set("expressions", self._parse_wrapped_id_vars())
2786                hints.append(hint)
2787
2788        return hints or None
2789
2790    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
2791        return (
2792            (not schema and self._parse_function(optional_parens=False))
2793            or self._parse_id_var(any_token=False)
2794            or self._parse_string_as_identifier()
2795            or self._parse_placeholder()
2796        )
2797
2798    def _parse_table_parts(self, schema: bool = False, is_db_reference: bool = False) -> exp.Table:
2799        catalog = None
2800        db = None
2801        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
2802
2803        while self._match(TokenType.DOT):
2804            if catalog:
2805                # This allows nesting the table in arbitrarily many dot expressions if needed
2806                table = self.expression(
2807                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
2808                )
2809            else:
2810                catalog = db
2811                db = table
2812                table = self._parse_table_part(schema=schema) or ""
2813
2814        if is_db_reference:
2815            catalog = db
2816            db = table
2817            table = None
2818
2819        if not table and not is_db_reference:
2820            self.raise_error(f"Expected table name but got {self._curr}")
2821        if not db and is_db_reference:
2822            self.raise_error(f"Expected database name but got {self._curr}")
2823
2824        return self.expression(
2825            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
2826        )
2827
2828    def _parse_table(
2829        self,
2830        schema: bool = False,
2831        joins: bool = False,
2832        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
2833        parse_bracket: bool = False,
2834        is_db_reference: bool = False,
2835    ) -> t.Optional[exp.Expression]:
2836        lateral = self._parse_lateral()
2837        if lateral:
2838            return lateral
2839
2840        unnest = self._parse_unnest()
2841        if unnest:
2842            return unnest
2843
2844        values = self._parse_derived_table_values()
2845        if values:
2846            return values
2847
2848        subquery = self._parse_select(table=True)
2849        if subquery:
2850            if not subquery.args.get("pivots"):
2851                subquery.set("pivots", self._parse_pivots())
2852            return subquery
2853
2854        bracket = parse_bracket and self._parse_bracket(None)
2855        bracket = self.expression(exp.Table, this=bracket) if bracket else None
2856        this = t.cast(
2857            exp.Expression,
2858            bracket
2859            or self._parse_bracket(
2860                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
2861            ),
2862        )
2863
2864        if schema:
2865            return self._parse_schema(this=this)
2866
2867        version = self._parse_version()
2868
2869        if version:
2870            this.set("version", version)
2871
2872        if self.dialect.ALIAS_POST_TABLESAMPLE:
2873            table_sample = self._parse_table_sample()
2874
2875        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2876        if alias:
2877            this.set("alias", alias)
2878
2879        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
2880            return self.expression(
2881                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
2882            )
2883
2884        this.set("hints", self._parse_table_hints())
2885
2886        if not this.args.get("pivots"):
2887            this.set("pivots", self._parse_pivots())
2888
2889        if not self.dialect.ALIAS_POST_TABLESAMPLE:
2890            table_sample = self._parse_table_sample()
2891
2892        if table_sample:
2893            table_sample.set("this", this)
2894            this = table_sample
2895
2896        if joins:
2897            for join in iter(self._parse_join, None):
2898                this.append("joins", join)
2899
2900        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
2901            this.set("ordinality", True)
2902            this.set("alias", self._parse_table_alias())
2903
2904        return this
2905
2906    def _parse_version(self) -> t.Optional[exp.Version]:
2907        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
2908            this = "TIMESTAMP"
2909        elif self._match(TokenType.VERSION_SNAPSHOT):
2910            this = "VERSION"
2911        else:
2912            return None
2913
2914        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
2915            kind = self._prev.text.upper()
2916            start = self._parse_bitwise()
2917            self._match_texts(("TO", "AND"))
2918            end = self._parse_bitwise()
2919            expression: t.Optional[exp.Expression] = self.expression(
2920                exp.Tuple, expressions=[start, end]
2921            )
2922        elif self._match_text_seq("CONTAINED", "IN"):
2923            kind = "CONTAINED IN"
2924            expression = self.expression(
2925                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
2926            )
2927        elif self._match(TokenType.ALL):
2928            kind = "ALL"
2929            expression = None
2930        else:
2931            self._match_text_seq("AS", "OF")
2932            kind = "AS OF"
2933            expression = self._parse_type()
2934
2935        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
2936
2937    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
2938        if not self._match(TokenType.UNNEST):
2939            return None
2940
2941        expressions = self._parse_wrapped_csv(self._parse_equality)
2942        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
2943
2944        alias = self._parse_table_alias() if with_alias else None
2945
2946        if alias:
2947            if self.dialect.UNNEST_COLUMN_ONLY:
2948                if alias.args.get("columns"):
2949                    self.raise_error("Unexpected extra column alias in unnest.")
2950
2951                alias.set("columns", [alias.this])
2952                alias.set("this", None)
2953
2954            columns = alias.args.get("columns") or []
2955            if offset and len(expressions) < len(columns):
2956                offset = columns.pop()
2957
2958        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
2959            self._match(TokenType.ALIAS)
2960            offset = self._parse_id_var(
2961                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
2962            ) or exp.to_identifier("offset")
2963
2964        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
2965
2966    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
2967        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
2968        if not is_derived and not self._match(TokenType.VALUES):
2969            return None
2970
2971        expressions = self._parse_csv(self._parse_value)
2972        alias = self._parse_table_alias()
2973
2974        if is_derived:
2975            self._match_r_paren()
2976
2977        return self.expression(
2978            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
2979        )
2980
2981    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
2982        if not self._match(TokenType.TABLE_SAMPLE) and not (
2983            as_modifier and self._match_text_seq("USING", "SAMPLE")
2984        ):
2985            return None
2986
2987        bucket_numerator = None
2988        bucket_denominator = None
2989        bucket_field = None
2990        percent = None
2991        size = None
2992        seed = None
2993
2994        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
2995        matched_l_paren = self._match(TokenType.L_PAREN)
2996
2997        if self.TABLESAMPLE_CSV:
2998            num = None
2999            expressions = self._parse_csv(self._parse_primary)
3000        else:
3001            expressions = None
3002            num = (
3003                self._parse_factor()
3004                if self._match(TokenType.NUMBER, advance=False)
3005                else self._parse_primary() or self._parse_placeholder()
3006            )
3007
3008        if self._match_text_seq("BUCKET"):
3009            bucket_numerator = self._parse_number()
3010            self._match_text_seq("OUT", "OF")
3011            bucket_denominator = bucket_denominator = self._parse_number()
3012            self._match(TokenType.ON)
3013            bucket_field = self._parse_field()
3014        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3015            percent = num
3016        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3017            size = num
3018        else:
3019            percent = num
3020
3021        if matched_l_paren:
3022            self._match_r_paren()
3023
3024        if self._match(TokenType.L_PAREN):
3025            method = self._parse_var(upper=True)
3026            seed = self._match(TokenType.COMMA) and self._parse_number()
3027            self._match_r_paren()
3028        elif self._match_texts(("SEED", "REPEATABLE")):
3029            seed = self._parse_wrapped(self._parse_number)
3030
3031        return self.expression(
3032            exp.TableSample,
3033            expressions=expressions,
3034            method=method,
3035            bucket_numerator=bucket_numerator,
3036            bucket_denominator=bucket_denominator,
3037            bucket_field=bucket_field,
3038            percent=percent,
3039            size=size,
3040            seed=seed,
3041        )
3042
3043    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3044        return list(iter(self._parse_pivot, None)) or None
3045
3046    def _parse_joins(self) -> t.Optional[t.List[exp.Join]]:
3047        return list(iter(self._parse_join, None)) or None
3048
3049    # https://duckdb.org/docs/sql/statements/pivot
3050    def _parse_simplified_pivot(self) -> exp.Pivot:
3051        def _parse_on() -> t.Optional[exp.Expression]:
3052            this = self._parse_bitwise()
3053            return self._parse_in(this) if self._match(TokenType.IN) else this
3054
3055        this = self._parse_table()
3056        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3057        using = self._match(TokenType.USING) and self._parse_csv(
3058            lambda: self._parse_alias(self._parse_function())
3059        )
3060        group = self._parse_group()
3061        return self.expression(
3062            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3063        )
3064
3065    def _parse_pivot_in(self) -> exp.In:
3066        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3067            this = self._parse_conjunction()
3068
3069            self._match(TokenType.ALIAS)
3070            alias = self._parse_field()
3071            if alias:
3072                return self.expression(exp.PivotAlias, this=this, alias=alias)
3073
3074            return this
3075
3076        value = self._parse_column()
3077
3078        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3079            self.raise_error("Expecting IN (")
3080
3081        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3082
3083        self._match_r_paren()
3084        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3085
3086    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3087        index = self._index
3088        include_nulls = None
3089
3090        if self._match(TokenType.PIVOT):
3091            unpivot = False
3092        elif self._match(TokenType.UNPIVOT):
3093            unpivot = True
3094
3095            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3096            if self._match_text_seq("INCLUDE", "NULLS"):
3097                include_nulls = True
3098            elif self._match_text_seq("EXCLUDE", "NULLS"):
3099                include_nulls = False
3100        else:
3101            return None
3102
3103        expressions = []
3104
3105        if not self._match(TokenType.L_PAREN):
3106            self._retreat(index)
3107            return None
3108
3109        if unpivot:
3110            expressions = self._parse_csv(self._parse_column)
3111        else:
3112            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3113
3114        if not expressions:
3115            self.raise_error("Failed to parse PIVOT's aggregation list")
3116
3117        if not self._match(TokenType.FOR):
3118            self.raise_error("Expecting FOR")
3119
3120        field = self._parse_pivot_in()
3121
3122        self._match_r_paren()
3123
3124        pivot = self.expression(
3125            exp.Pivot,
3126            expressions=expressions,
3127            field=field,
3128            unpivot=unpivot,
3129            include_nulls=include_nulls,
3130        )
3131
3132        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3133            pivot.set("alias", self._parse_table_alias())
3134
3135        if not unpivot:
3136            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3137
3138            columns: t.List[exp.Expression] = []
3139            for fld in pivot.args["field"].expressions:
3140                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3141                for name in names:
3142                    if self.PREFIXED_PIVOT_COLUMNS:
3143                        name = f"{name}_{field_name}" if name else field_name
3144                    else:
3145                        name = f"{field_name}_{name}" if name else field_name
3146
3147                    columns.append(exp.to_identifier(name))
3148
3149            pivot.set("columns", columns)
3150
3151        return pivot
3152
3153    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3154        return [agg.alias for agg in aggregations]
3155
3156    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3157        if not skip_where_token and not self._match(TokenType.WHERE):
3158            return None
3159
3160        return self.expression(
3161            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3162        )
3163
3164    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3165        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3166            return None
3167
3168        elements = defaultdict(list)
3169
3170        if self._match(TokenType.ALL):
3171            return self.expression(exp.Group, all=True)
3172
3173        while True:
3174            expressions = self._parse_csv(self._parse_conjunction)
3175            if expressions:
3176                elements["expressions"].extend(expressions)
3177
3178            grouping_sets = self._parse_grouping_sets()
3179            if grouping_sets:
3180                elements["grouping_sets"].extend(grouping_sets)
3181
3182            rollup = None
3183            cube = None
3184            totals = None
3185
3186            index = self._index
3187            with_ = self._match(TokenType.WITH)
3188            if self._match(TokenType.ROLLUP):
3189                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3190                elements["rollup"].extend(ensure_list(rollup))
3191
3192            if self._match(TokenType.CUBE):
3193                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3194                elements["cube"].extend(ensure_list(cube))
3195
3196            if self._match_text_seq("TOTALS"):
3197                totals = True
3198                elements["totals"] = True  # type: ignore
3199
3200            if not (grouping_sets or rollup or cube or totals):
3201                if with_:
3202                    self._retreat(index)
3203                break
3204
3205        return self.expression(exp.Group, **elements)  # type: ignore
3206
3207    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3208        if not self._match(TokenType.GROUPING_SETS):
3209            return None
3210
3211        return self._parse_wrapped_csv(self._parse_grouping_set)
3212
3213    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3214        if self._match(TokenType.L_PAREN):
3215            grouping_set = self._parse_csv(self._parse_column)
3216            self._match_r_paren()
3217            return self.expression(exp.Tuple, expressions=grouping_set)
3218
3219        return self._parse_column()
3220
3221    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3222        if not skip_having_token and not self._match(TokenType.HAVING):
3223            return None
3224        return self.expression(exp.Having, this=self._parse_conjunction())
3225
3226    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3227        if not self._match(TokenType.QUALIFY):
3228            return None
3229        return self.expression(exp.Qualify, this=self._parse_conjunction())
3230
3231    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3232        if skip_start_token:
3233            start = None
3234        elif self._match(TokenType.START_WITH):
3235            start = self._parse_conjunction()
3236        else:
3237            return None
3238
3239        self._match(TokenType.CONNECT_BY)
3240        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3241            exp.Prior, this=self._parse_bitwise()
3242        )
3243        connect = self._parse_conjunction()
3244        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3245
3246        if not start and self._match(TokenType.START_WITH):
3247            start = self._parse_conjunction()
3248
3249        return self.expression(exp.Connect, start=start, connect=connect)
3250
3251    def _parse_name_as_expression(self) -> exp.Alias:
3252        return self.expression(
3253            exp.Alias,
3254            alias=self._parse_id_var(any_token=True),
3255            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3256        )
3257
3258    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3259        if self._match_text_seq("INTERPOLATE"):
3260            return self._parse_wrapped_csv(self._parse_name_as_expression)
3261        return None
3262
3263    def _parse_order(
3264        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3265    ) -> t.Optional[exp.Expression]:
3266        siblings = None
3267        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3268            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3269                return this
3270
3271            siblings = True
3272
3273        return self.expression(
3274            exp.Order,
3275            this=this,
3276            expressions=self._parse_csv(self._parse_ordered),
3277            interpolate=self._parse_interpolate(),
3278            siblings=siblings,
3279        )
3280
3281    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3282        if not self._match(token):
3283            return None
3284        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3285
3286    def _parse_ordered(self, parse_method: t.Optional[t.Callable] = None) -> exp.Ordered:
3287        this = parse_method() if parse_method else self._parse_conjunction()
3288
3289        asc = self._match(TokenType.ASC)
3290        desc = self._match(TokenType.DESC) or (asc and False)
3291
3292        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3293        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3294
3295        nulls_first = is_nulls_first or False
3296        explicitly_null_ordered = is_nulls_first or is_nulls_last
3297
3298        if (
3299            not explicitly_null_ordered
3300            and (
3301                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3302                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3303            )
3304            and self.dialect.NULL_ORDERING != "nulls_are_last"
3305        ):
3306            nulls_first = True
3307
3308        if self._match_text_seq("WITH", "FILL"):
3309            with_fill = self.expression(
3310                exp.WithFill,
3311                **{  # type: ignore
3312                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3313                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3314                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3315                },
3316            )
3317        else:
3318            with_fill = None
3319
3320        return self.expression(
3321            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3322        )
3323
3324    def _parse_limit(
3325        self, this: t.Optional[exp.Expression] = None, top: bool = False
3326    ) -> t.Optional[exp.Expression]:
3327        if self._match(TokenType.TOP if top else TokenType.LIMIT):
3328            comments = self._prev_comments
3329            if top:
3330                limit_paren = self._match(TokenType.L_PAREN)
3331                expression = self._parse_term() if limit_paren else self._parse_number()
3332
3333                if limit_paren:
3334                    self._match_r_paren()
3335            else:
3336                expression = self._parse_term()
3337
3338            if self._match(TokenType.COMMA):
3339                offset = expression
3340                expression = self._parse_term()
3341            else:
3342                offset = None
3343
3344            limit_exp = self.expression(
3345                exp.Limit, this=this, expression=expression, offset=offset, comments=comments
3346            )
3347
3348            return limit_exp
3349
3350        if self._match(TokenType.FETCH):
3351            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3352            direction = self._prev.text.upper() if direction else "FIRST"
3353
3354            count = self._parse_field(tokens=self.FETCH_TOKENS)
3355            percent = self._match(TokenType.PERCENT)
3356
3357            self._match_set((TokenType.ROW, TokenType.ROWS))
3358
3359            only = self._match_text_seq("ONLY")
3360            with_ties = self._match_text_seq("WITH", "TIES")
3361
3362            if only and with_ties:
3363                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3364
3365            return self.expression(
3366                exp.Fetch,
3367                direction=direction,
3368                count=count,
3369                percent=percent,
3370                with_ties=with_ties,
3371            )
3372
3373        return this
3374
3375    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3376        if not self._match(TokenType.OFFSET):
3377            return this
3378
3379        count = self._parse_term()
3380        self._match_set((TokenType.ROW, TokenType.ROWS))
3381        return self.expression(exp.Offset, this=this, expression=count)
3382
3383    def _parse_locks(self) -> t.List[exp.Lock]:
3384        locks = []
3385        while True:
3386            if self._match_text_seq("FOR", "UPDATE"):
3387                update = True
3388            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3389                "LOCK", "IN", "SHARE", "MODE"
3390            ):
3391                update = False
3392            else:
3393                break
3394
3395            expressions = None
3396            if self._match_text_seq("OF"):
3397                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3398
3399            wait: t.Optional[bool | exp.Expression] = None
3400            if self._match_text_seq("NOWAIT"):
3401                wait = True
3402            elif self._match_text_seq("WAIT"):
3403                wait = self._parse_primary()
3404            elif self._match_text_seq("SKIP", "LOCKED"):
3405                wait = False
3406
3407            locks.append(
3408                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3409            )
3410
3411        return locks
3412
3413    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3414        while this and self._match_set(self.SET_OPERATIONS):
3415            token_type = self._prev.token_type
3416
3417            if token_type == TokenType.UNION:
3418                operation = exp.Union
3419            elif token_type == TokenType.EXCEPT:
3420                operation = exp.Except
3421            else:
3422                operation = exp.Intersect
3423
3424            comments = self._prev.comments
3425            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3426            by_name = self._match_text_seq("BY", "NAME")
3427            expression = self._parse_select(nested=True, parse_set_operation=False)
3428
3429            this = self.expression(
3430                operation,
3431                comments=comments,
3432                this=this,
3433                distinct=distinct,
3434                by_name=by_name,
3435                expression=expression,
3436            )
3437
3438        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3439            expression = this.expression
3440
3441            if expression:
3442                for arg in self.UNION_MODIFIERS:
3443                    expr = expression.args.get(arg)
3444                    if expr:
3445                        this.set(arg, expr.pop())
3446
3447        return this
3448
3449    def _parse_expression(self) -> t.Optional[exp.Expression]:
3450        return self._parse_alias(self._parse_conjunction())
3451
3452    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3453        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3454
3455    def _parse_equality(self) -> t.Optional[exp.Expression]:
3456        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3457
3458    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3459        return self._parse_tokens(self._parse_range, self.COMPARISON)
3460
3461    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3462        this = this or self._parse_bitwise()
3463        negate = self._match(TokenType.NOT)
3464
3465        if self._match_set(self.RANGE_PARSERS):
3466            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3467            if not expression:
3468                return this
3469
3470            this = expression
3471        elif self._match(TokenType.ISNULL):
3472            this = self.expression(exp.Is, this=this, expression=exp.Null())
3473
3474        # Postgres supports ISNULL and NOTNULL for conditions.
3475        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3476        if self._match(TokenType.NOTNULL):
3477            this = self.expression(exp.Is, this=this, expression=exp.Null())
3478            this = self.expression(exp.Not, this=this)
3479
3480        if negate:
3481            this = self.expression(exp.Not, this=this)
3482
3483        if self._match(TokenType.IS):
3484            this = self._parse_is(this)
3485
3486        return this
3487
3488    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3489        index = self._index - 1
3490        negate = self._match(TokenType.NOT)
3491
3492        if self._match_text_seq("DISTINCT", "FROM"):
3493            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3494            return self.expression(klass, this=this, expression=self._parse_conjunction())
3495
3496        expression = self._parse_null() or self._parse_boolean()
3497        if not expression:
3498            self._retreat(index)
3499            return None
3500
3501        this = self.expression(exp.Is, this=this, expression=expression)
3502        return self.expression(exp.Not, this=this) if negate else this
3503
3504    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3505        unnest = self._parse_unnest(with_alias=False)
3506        if unnest:
3507            this = self.expression(exp.In, this=this, unnest=unnest)
3508        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3509            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3510            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3511
3512            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
3513                this = self.expression(exp.In, this=this, query=expressions[0])
3514            else:
3515                this = self.expression(exp.In, this=this, expressions=expressions)
3516
3517            if matched_l_paren:
3518                self._match_r_paren(this)
3519            elif not self._match(TokenType.R_BRACKET, expression=this):
3520                self.raise_error("Expecting ]")
3521        else:
3522            this = self.expression(exp.In, this=this, field=self._parse_field())
3523
3524        return this
3525
3526    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3527        low = self._parse_bitwise()
3528        self._match(TokenType.AND)
3529        high = self._parse_bitwise()
3530        return self.expression(exp.Between, this=this, low=low, high=high)
3531
3532    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3533        if not self._match(TokenType.ESCAPE):
3534            return this
3535        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3536
3537    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3538        index = self._index
3539
3540        if not self._match(TokenType.INTERVAL) and match_interval:
3541            return None
3542
3543        if self._match(TokenType.STRING, advance=False):
3544            this = self._parse_primary()
3545        else:
3546            this = self._parse_term()
3547
3548        if not this or (
3549            isinstance(this, exp.Column)
3550            and not this.table
3551            and not this.this.quoted
3552            and this.name.upper() == "IS"
3553        ):
3554            self._retreat(index)
3555            return None
3556
3557        unit = self._parse_function() or (
3558            not self._match(TokenType.ALIAS, advance=False)
3559            and self._parse_var(any_token=True, upper=True)
3560        )
3561
3562        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3563        # each INTERVAL expression into this canonical form so it's easy to transpile
3564        if this and this.is_number:
3565            this = exp.Literal.string(this.name)
3566        elif this and this.is_string:
3567            parts = this.name.split()
3568
3569            if len(parts) == 2:
3570                if unit:
3571                    # This is not actually a unit, it's something else (e.g. a "window side")
3572                    unit = None
3573                    self._retreat(self._index - 1)
3574
3575                this = exp.Literal.string(parts[0])
3576                unit = self.expression(exp.Var, this=parts[1].upper())
3577
3578        return self.expression(exp.Interval, this=this, unit=unit)
3579
3580    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3581        this = self._parse_term()
3582
3583        while True:
3584            if self._match_set(self.BITWISE):
3585                this = self.expression(
3586                    self.BITWISE[self._prev.token_type],
3587                    this=this,
3588                    expression=self._parse_term(),
3589                )
3590            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3591                this = self.expression(
3592                    exp.DPipe,
3593                    this=this,
3594                    expression=self._parse_term(),
3595                    safe=not self.dialect.STRICT_STRING_CONCAT,
3596                )
3597            elif self._match(TokenType.DQMARK):
3598                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3599            elif self._match_pair(TokenType.LT, TokenType.LT):
3600                this = self.expression(
3601                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3602                )
3603            elif self._match_pair(TokenType.GT, TokenType.GT):
3604                this = self.expression(
3605                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3606                )
3607            else:
3608                break
3609
3610        return this
3611
3612    def _parse_term(self) -> t.Optional[exp.Expression]:
3613        return self._parse_tokens(self._parse_factor, self.TERM)
3614
3615    def _parse_factor(self) -> t.Optional[exp.Expression]:
3616        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
3617        this = parse_method()
3618
3619        while self._match_set(self.FACTOR):
3620            this = self.expression(
3621                self.FACTOR[self._prev.token_type],
3622                this=this,
3623                comments=self._prev_comments,
3624                expression=parse_method(),
3625            )
3626            if isinstance(this, exp.Div):
3627                this.args["typed"] = self.dialect.TYPED_DIVISION
3628                this.args["safe"] = self.dialect.SAFE_DIVISION
3629
3630        return this
3631
3632    def _parse_exponent(self) -> t.Optional[exp.Expression]:
3633        return self._parse_tokens(self._parse_unary, self.EXPONENT)
3634
3635    def _parse_unary(self) -> t.Optional[exp.Expression]:
3636        if self._match_set(self.UNARY_PARSERS):
3637            return self.UNARY_PARSERS[self._prev.token_type](self)
3638        return self._parse_at_time_zone(self._parse_type())
3639
3640    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
3641        interval = parse_interval and self._parse_interval()
3642        if interval:
3643            # Convert INTERVAL 'val_1' unit_1 ... 'val_n' unit_n into a sum of intervals
3644            while self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
3645                interval = self.expression(  # type: ignore
3646                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
3647                )
3648
3649            return interval
3650
3651        index = self._index
3652        data_type = self._parse_types(check_func=True, allow_identifiers=False)
3653        this = self._parse_column()
3654
3655        if data_type:
3656            if isinstance(this, exp.Literal):
3657                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
3658                if parser:
3659                    return parser(self, this, data_type)
3660                return self.expression(exp.Cast, this=this, to=data_type)
3661            if not data_type.expressions:
3662                self._retreat(index)
3663                return self._parse_column()
3664            return self._parse_column_ops(data_type)
3665
3666        return this and self._parse_column_ops(this)
3667
3668    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
3669        this = self._parse_type()
3670        if not this:
3671            return None
3672
3673        return self.expression(
3674            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
3675        )
3676
3677    def _parse_types(
3678        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
3679    ) -> t.Optional[exp.Expression]:
3680        index = self._index
3681
3682        prefix = self._match_text_seq("SYSUDTLIB", ".")
3683
3684        if not self._match_set(self.TYPE_TOKENS):
3685            identifier = allow_identifiers and self._parse_id_var(
3686                any_token=False, tokens=(TokenType.VAR,)
3687            )
3688            if identifier:
3689                tokens = self.dialect.tokenize(identifier.name)
3690
3691                if len(tokens) != 1:
3692                    self.raise_error("Unexpected identifier", self._prev)
3693
3694                if tokens[0].token_type in self.TYPE_TOKENS:
3695                    self._prev = tokens[0]
3696                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
3697                    type_name = identifier.name
3698
3699                    while self._match(TokenType.DOT):
3700                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
3701
3702                    return exp.DataType.build(type_name, udt=True)
3703                else:
3704                    self._retreat(self._index - 1)
3705                    return None
3706            else:
3707                return None
3708
3709        type_token = self._prev.token_type
3710
3711        if type_token == TokenType.PSEUDO_TYPE:
3712            return self.expression(exp.PseudoType, this=self._prev.text.upper())
3713
3714        if type_token == TokenType.OBJECT_IDENTIFIER:
3715            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
3716
3717        nested = type_token in self.NESTED_TYPE_TOKENS
3718        is_struct = type_token in self.STRUCT_TYPE_TOKENS
3719        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
3720        expressions = None
3721        maybe_func = False
3722
3723        if self._match(TokenType.L_PAREN):
3724            if is_struct:
3725                expressions = self._parse_csv(self._parse_struct_types)
3726            elif nested:
3727                expressions = self._parse_csv(
3728                    lambda: self._parse_types(
3729                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3730                    )
3731                )
3732            elif type_token in self.ENUM_TYPE_TOKENS:
3733                expressions = self._parse_csv(self._parse_equality)
3734            elif is_aggregate:
3735                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
3736                    any_token=False, tokens=(TokenType.VAR,)
3737                )
3738                if not func_or_ident or not self._match(TokenType.COMMA):
3739                    return None
3740                expressions = self._parse_csv(
3741                    lambda: self._parse_types(
3742                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3743                    )
3744                )
3745                expressions.insert(0, func_or_ident)
3746            else:
3747                expressions = self._parse_csv(self._parse_type_size)
3748
3749            if not expressions or not self._match(TokenType.R_PAREN):
3750                self._retreat(index)
3751                return None
3752
3753            maybe_func = True
3754
3755        this: t.Optional[exp.Expression] = None
3756        values: t.Optional[t.List[exp.Expression]] = None
3757
3758        if nested and self._match(TokenType.LT):
3759            if is_struct:
3760                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
3761            else:
3762                expressions = self._parse_csv(
3763                    lambda: self._parse_types(
3764                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3765                    )
3766                )
3767
3768            if not self._match(TokenType.GT):
3769                self.raise_error("Expecting >")
3770
3771            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
3772                values = self._parse_csv(self._parse_conjunction)
3773                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
3774
3775        if type_token in self.TIMESTAMPS:
3776            if self._match_text_seq("WITH", "TIME", "ZONE"):
3777                maybe_func = False
3778                tz_type = (
3779                    exp.DataType.Type.TIMETZ
3780                    if type_token in self.TIMES
3781                    else exp.DataType.Type.TIMESTAMPTZ
3782                )
3783                this = exp.DataType(this=tz_type, expressions=expressions)
3784            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
3785                maybe_func = False
3786                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
3787            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
3788                maybe_func = False
3789        elif type_token == TokenType.INTERVAL:
3790            unit = self._parse_var()
3791
3792            if self._match_text_seq("TO"):
3793                span = [exp.IntervalSpan(this=unit, expression=self._parse_var())]
3794            else:
3795                span = None
3796
3797            if span or not unit:
3798                this = self.expression(
3799                    exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
3800                )
3801            else:
3802                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
3803
3804        if maybe_func and check_func:
3805            index2 = self._index
3806            peek = self._parse_string()
3807
3808            if not peek:
3809                self._retreat(index)
3810                return None
3811
3812            self._retreat(index2)
3813
3814        if not this:
3815            if self._match_text_seq("UNSIGNED"):
3816                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
3817                if not unsigned_type_token:
3818                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
3819
3820                type_token = unsigned_type_token or type_token
3821
3822            this = exp.DataType(
3823                this=exp.DataType.Type[type_token.value],
3824                expressions=expressions,
3825                nested=nested,
3826                values=values,
3827                prefix=prefix,
3828            )
3829
3830        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
3831            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
3832
3833        return this
3834
3835    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
3836        index = self._index
3837        this = self._parse_type(parse_interval=False) or self._parse_id_var()
3838        self._match(TokenType.COLON)
3839        column_def = self._parse_column_def(this)
3840
3841        if type_required and (
3842            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
3843        ):
3844            self._retreat(index)
3845            return self._parse_types()
3846
3847        return column_def
3848
3849    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3850        if not self._match_text_seq("AT", "TIME", "ZONE"):
3851            return this
3852        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
3853
3854    def _parse_column(self) -> t.Optional[exp.Expression]:
3855        this = self._parse_column_reference()
3856        return self._parse_column_ops(this) if this else self._parse_bracket(this)
3857
3858    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
3859        this = self._parse_field()
3860        if isinstance(this, exp.Identifier):
3861            this = self.expression(exp.Column, this=this)
3862        return this
3863
3864    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3865        this = self._parse_bracket(this)
3866
3867        while self._match_set(self.COLUMN_OPERATORS):
3868            op_token = self._prev.token_type
3869            op = self.COLUMN_OPERATORS.get(op_token)
3870
3871            if op_token == TokenType.DCOLON:
3872                field = self._parse_types()
3873                if not field:
3874                    self.raise_error("Expected type")
3875            elif op and self._curr:
3876                field = self._parse_column_reference()
3877            else:
3878                field = self._parse_field(anonymous_func=True, any_token=True)
3879
3880            if isinstance(field, exp.Func):
3881                # bigquery allows function calls like x.y.count(...)
3882                # SAFE.SUBSTR(...)
3883                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
3884                this = self._replace_columns_with_dots(this)
3885
3886            if op:
3887                this = op(self, this, field)
3888            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
3889                this = self.expression(
3890                    exp.Column,
3891                    this=field,
3892                    table=this.this,
3893                    db=this.args.get("table"),
3894                    catalog=this.args.get("db"),
3895                )
3896            else:
3897                this = self.expression(exp.Dot, this=this, expression=field)
3898            this = self._parse_bracket(this)
3899        return this
3900
3901    def _parse_primary(self) -> t.Optional[exp.Expression]:
3902        if self._match_set(self.PRIMARY_PARSERS):
3903            token_type = self._prev.token_type
3904            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
3905
3906            if token_type == TokenType.STRING:
3907                expressions = [primary]
3908                while self._match(TokenType.STRING):
3909                    expressions.append(exp.Literal.string(self._prev.text))
3910
3911                if len(expressions) > 1:
3912                    return self.expression(exp.Concat, expressions=expressions)
3913
3914            return primary
3915
3916        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
3917            return exp.Literal.number(f"0.{self._prev.text}")
3918
3919        if self._match(TokenType.L_PAREN):
3920            comments = self._prev_comments
3921            query = self._parse_select()
3922
3923            if query:
3924                expressions = [query]
3925            else:
3926                expressions = self._parse_expressions()
3927
3928            this = self._parse_query_modifiers(seq_get(expressions, 0))
3929
3930            if isinstance(this, exp.Subqueryable):
3931                this = self._parse_set_operations(
3932                    self._parse_subquery(this=this, parse_alias=False)
3933                )
3934            elif len(expressions) > 1:
3935                this = self.expression(exp.Tuple, expressions=expressions)
3936            else:
3937                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
3938
3939            if this:
3940                this.add_comments(comments)
3941
3942            self._match_r_paren(expression=this)
3943            return this
3944
3945        return None
3946
3947    def _parse_field(
3948        self,
3949        any_token: bool = False,
3950        tokens: t.Optional[t.Collection[TokenType]] = None,
3951        anonymous_func: bool = False,
3952    ) -> t.Optional[exp.Expression]:
3953        return (
3954            self._parse_primary()
3955            or self._parse_function(anonymous=anonymous_func)
3956            or self._parse_id_var(any_token=any_token, tokens=tokens)
3957        )
3958
3959    def _parse_function(
3960        self,
3961        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3962        anonymous: bool = False,
3963        optional_parens: bool = True,
3964    ) -> t.Optional[exp.Expression]:
3965        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
3966        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
3967        fn_syntax = False
3968        if (
3969            self._match(TokenType.L_BRACE, advance=False)
3970            and self._next
3971            and self._next.text.upper() == "FN"
3972        ):
3973            self._advance(2)
3974            fn_syntax = True
3975
3976        func = self._parse_function_call(
3977            functions=functions, anonymous=anonymous, optional_parens=optional_parens
3978        )
3979
3980        if fn_syntax:
3981            self._match(TokenType.R_BRACE)
3982
3983        return func
3984
3985    def _parse_function_call(
3986        self,
3987        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3988        anonymous: bool = False,
3989        optional_parens: bool = True,
3990    ) -> t.Optional[exp.Expression]:
3991        if not self._curr:
3992            return None
3993
3994        comments = self._curr.comments
3995        token_type = self._curr.token_type
3996        this = self._curr.text
3997        upper = this.upper()
3998
3999        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4000        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4001            self._advance()
4002            return parser(self)
4003
4004        if not self._next or self._next.token_type != TokenType.L_PAREN:
4005            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4006                self._advance()
4007                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4008
4009            return None
4010
4011        if token_type not in self.FUNC_TOKENS:
4012            return None
4013
4014        self._advance(2)
4015
4016        parser = self.FUNCTION_PARSERS.get(upper)
4017        if parser and not anonymous:
4018            this = parser(self)
4019        else:
4020            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4021
4022            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4023                this = self.expression(subquery_predicate, this=self._parse_select())
4024                self._match_r_paren()
4025                return this
4026
4027            if functions is None:
4028                functions = self.FUNCTIONS
4029
4030            function = functions.get(upper)
4031
4032            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4033            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4034
4035            if function and not anonymous:
4036                if "dialect" in function.__code__.co_varnames:
4037                    func = function(args, dialect=self.dialect)
4038                else:
4039                    func = function(args)
4040
4041                func = self.validate_expression(func, args)
4042                if not self.dialect.NORMALIZE_FUNCTIONS:
4043                    func.meta["name"] = this
4044
4045                this = func
4046            else:
4047                this = self.expression(exp.Anonymous, this=this, expressions=args)
4048
4049        if isinstance(this, exp.Expression):
4050            this.add_comments(comments)
4051
4052        self._match_r_paren(this)
4053        return self._parse_window(this)
4054
4055    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4056        return self._parse_column_def(self._parse_id_var())
4057
4058    def _parse_user_defined_function(
4059        self, kind: t.Optional[TokenType] = None
4060    ) -> t.Optional[exp.Expression]:
4061        this = self._parse_id_var()
4062
4063        while self._match(TokenType.DOT):
4064            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4065
4066        if not self._match(TokenType.L_PAREN):
4067            return this
4068
4069        expressions = self._parse_csv(self._parse_function_parameter)
4070        self._match_r_paren()
4071        return self.expression(
4072            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4073        )
4074
4075    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4076        literal = self._parse_primary()
4077        if literal:
4078            return self.expression(exp.Introducer, this=token.text, expression=literal)
4079
4080        return self.expression(exp.Identifier, this=token.text)
4081
4082    def _parse_session_parameter(self) -> exp.SessionParameter:
4083        kind = None
4084        this = self._parse_id_var() or self._parse_primary()
4085
4086        if this and self._match(TokenType.DOT):
4087            kind = this.name
4088            this = self._parse_var() or self._parse_primary()
4089
4090        return self.expression(exp.SessionParameter, this=this, kind=kind)
4091
4092    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4093        index = self._index
4094
4095        if self._match(TokenType.L_PAREN):
4096            expressions = t.cast(
4097                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4098            )
4099
4100            if not self._match(TokenType.R_PAREN):
4101                self._retreat(index)
4102        else:
4103            expressions = [self._parse_id_var()]
4104
4105        if self._match_set(self.LAMBDAS):
4106            return self.LAMBDAS[self._prev.token_type](self, expressions)
4107
4108        self._retreat(index)
4109
4110        this: t.Optional[exp.Expression]
4111
4112        if self._match(TokenType.DISTINCT):
4113            this = self.expression(
4114                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4115            )
4116        else:
4117            this = self._parse_select_or_expression(alias=alias)
4118
4119        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
4120
4121    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4122        index = self._index
4123
4124        if not self.errors:
4125            try:
4126                if self._parse_select(nested=True):
4127                    return this
4128            except ParseError:
4129                pass
4130            finally:
4131                self.errors.clear()
4132                self._retreat(index)
4133
4134        if not self._match(TokenType.L_PAREN):
4135            return this
4136
4137        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4138
4139        self._match_r_paren()
4140        return self.expression(exp.Schema, this=this, expressions=args)
4141
4142    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4143        return self._parse_column_def(self._parse_field(any_token=True))
4144
4145    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4146        # column defs are not really columns, they're identifiers
4147        if isinstance(this, exp.Column):
4148            this = this.this
4149
4150        kind = self._parse_types(schema=True)
4151
4152        if self._match_text_seq("FOR", "ORDINALITY"):
4153            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4154
4155        constraints: t.List[exp.Expression] = []
4156
4157        if not kind and self._match(TokenType.ALIAS):
4158            constraints.append(
4159                self.expression(
4160                    exp.ComputedColumnConstraint,
4161                    this=self._parse_conjunction(),
4162                    persisted=self._match_text_seq("PERSISTED"),
4163                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4164                )
4165            )
4166        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4167            self._match(TokenType.ALIAS)
4168            constraints.append(
4169                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4170            )
4171
4172        while True:
4173            constraint = self._parse_column_constraint()
4174            if not constraint:
4175                break
4176            constraints.append(constraint)
4177
4178        if not kind and not constraints:
4179            return this
4180
4181        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4182
4183    def _parse_auto_increment(
4184        self,
4185    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4186        start = None
4187        increment = None
4188
4189        if self._match(TokenType.L_PAREN, advance=False):
4190            args = self._parse_wrapped_csv(self._parse_bitwise)
4191            start = seq_get(args, 0)
4192            increment = seq_get(args, 1)
4193        elif self._match_text_seq("START"):
4194            start = self._parse_bitwise()
4195            self._match_text_seq("INCREMENT")
4196            increment = self._parse_bitwise()
4197
4198        if start and increment:
4199            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4200
4201        return exp.AutoIncrementColumnConstraint()
4202
4203    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4204        if not self._match_text_seq("REFRESH"):
4205            self._retreat(self._index - 1)
4206            return None
4207        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4208
4209    def _parse_compress(self) -> exp.CompressColumnConstraint:
4210        if self._match(TokenType.L_PAREN, advance=False):
4211            return self.expression(
4212                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4213            )
4214
4215        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4216
4217    def _parse_generated_as_identity(
4218        self,
4219    ) -> (
4220        exp.GeneratedAsIdentityColumnConstraint
4221        | exp.ComputedColumnConstraint
4222        | exp.GeneratedAsRowColumnConstraint
4223    ):
4224        if self._match_text_seq("BY", "DEFAULT"):
4225            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4226            this = self.expression(
4227                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4228            )
4229        else:
4230            self._match_text_seq("ALWAYS")
4231            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4232
4233        self._match(TokenType.ALIAS)
4234
4235        if self._match_text_seq("ROW"):
4236            start = self._match_text_seq("START")
4237            if not start:
4238                self._match(TokenType.END)
4239            hidden = self._match_text_seq("HIDDEN")
4240            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4241
4242        identity = self._match_text_seq("IDENTITY")
4243
4244        if self._match(TokenType.L_PAREN):
4245            if self._match(TokenType.START_WITH):
4246                this.set("start", self._parse_bitwise())
4247            if self._match_text_seq("INCREMENT", "BY"):
4248                this.set("increment", self._parse_bitwise())
4249            if self._match_text_seq("MINVALUE"):
4250                this.set("minvalue", self._parse_bitwise())
4251            if self._match_text_seq("MAXVALUE"):
4252                this.set("maxvalue", self._parse_bitwise())
4253
4254            if self._match_text_seq("CYCLE"):
4255                this.set("cycle", True)
4256            elif self._match_text_seq("NO", "CYCLE"):
4257                this.set("cycle", False)
4258
4259            if not identity:
4260                this.set("expression", self._parse_bitwise())
4261            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4262                args = self._parse_csv(self._parse_bitwise)
4263                this.set("start", seq_get(args, 0))
4264                this.set("increment", seq_get(args, 1))
4265
4266            self._match_r_paren()
4267
4268        return this
4269
4270    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4271        self._match_text_seq("LENGTH")
4272        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4273
4274    def _parse_not_constraint(
4275        self,
4276    ) -> t.Optional[exp.Expression]:
4277        if self._match_text_seq("NULL"):
4278            return self.expression(exp.NotNullColumnConstraint)
4279        if self._match_text_seq("CASESPECIFIC"):
4280            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4281        if self._match_text_seq("FOR", "REPLICATION"):
4282            return self.expression(exp.NotForReplicationColumnConstraint)
4283        return None
4284
4285    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4286        if self._match(TokenType.CONSTRAINT):
4287            this = self._parse_id_var()
4288        else:
4289            this = None
4290
4291        if self._match_texts(self.CONSTRAINT_PARSERS):
4292            return self.expression(
4293                exp.ColumnConstraint,
4294                this=this,
4295                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4296            )
4297
4298        return this
4299
4300    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4301        if not self._match(TokenType.CONSTRAINT):
4302            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4303
4304        this = self._parse_id_var()
4305        expressions = []
4306
4307        while True:
4308            constraint = self._parse_unnamed_constraint() or self._parse_function()
4309            if not constraint:
4310                break
4311            expressions.append(constraint)
4312
4313        return self.expression(exp.Constraint, this=this, expressions=expressions)
4314
4315    def _parse_unnamed_constraint(
4316        self, constraints: t.Optional[t.Collection[str]] = None
4317    ) -> t.Optional[exp.Expression]:
4318        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4319            constraints or self.CONSTRAINT_PARSERS
4320        ):
4321            return None
4322
4323        constraint = self._prev.text.upper()
4324        if constraint not in self.CONSTRAINT_PARSERS:
4325            self.raise_error(f"No parser found for schema constraint {constraint}.")
4326
4327        return self.CONSTRAINT_PARSERS[constraint](self)
4328
4329    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4330        self._match_text_seq("KEY")
4331        return self.expression(
4332            exp.UniqueColumnConstraint,
4333            this=self._parse_schema(self._parse_id_var(any_token=False)),
4334            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4335        )
4336
4337    def _parse_key_constraint_options(self) -> t.List[str]:
4338        options = []
4339        while True:
4340            if not self._curr:
4341                break
4342
4343            if self._match(TokenType.ON):
4344                action = None
4345                on = self._advance_any() and self._prev.text
4346
4347                if self._match_text_seq("NO", "ACTION"):
4348                    action = "NO ACTION"
4349                elif self._match_text_seq("CASCADE"):
4350                    action = "CASCADE"
4351                elif self._match_text_seq("RESTRICT"):
4352                    action = "RESTRICT"
4353                elif self._match_pair(TokenType.SET, TokenType.NULL):
4354                    action = "SET NULL"
4355                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4356                    action = "SET DEFAULT"
4357                else:
4358                    self.raise_error("Invalid key constraint")
4359
4360                options.append(f"ON {on} {action}")
4361            elif self._match_text_seq("NOT", "ENFORCED"):
4362                options.append("NOT ENFORCED")
4363            elif self._match_text_seq("DEFERRABLE"):
4364                options.append("DEFERRABLE")
4365            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4366                options.append("INITIALLY DEFERRED")
4367            elif self._match_text_seq("NORELY"):
4368                options.append("NORELY")
4369            elif self._match_text_seq("MATCH", "FULL"):
4370                options.append("MATCH FULL")
4371            else:
4372                break
4373
4374        return options
4375
4376    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4377        if match and not self._match(TokenType.REFERENCES):
4378            return None
4379
4380        expressions = None
4381        this = self._parse_table(schema=True)
4382        options = self._parse_key_constraint_options()
4383        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4384
4385    def _parse_foreign_key(self) -> exp.ForeignKey:
4386        expressions = self._parse_wrapped_id_vars()
4387        reference = self._parse_references()
4388        options = {}
4389
4390        while self._match(TokenType.ON):
4391            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4392                self.raise_error("Expected DELETE or UPDATE")
4393
4394            kind = self._prev.text.lower()
4395
4396            if self._match_text_seq("NO", "ACTION"):
4397                action = "NO ACTION"
4398            elif self._match(TokenType.SET):
4399                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4400                action = "SET " + self._prev.text.upper()
4401            else:
4402                self._advance()
4403                action = self._prev.text.upper()
4404
4405            options[kind] = action
4406
4407        return self.expression(
4408            exp.ForeignKey,
4409            expressions=expressions,
4410            reference=reference,
4411            **options,  # type: ignore
4412        )
4413
4414    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4415        return self._parse_field()
4416
4417    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4418        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4419            self._retreat(self._index - 1)
4420            return None
4421
4422        id_vars = self._parse_wrapped_id_vars()
4423        return self.expression(
4424            exp.PeriodForSystemTimeConstraint,
4425            this=seq_get(id_vars, 0),
4426            expression=seq_get(id_vars, 1),
4427        )
4428
4429    def _parse_primary_key(
4430        self, wrapped_optional: bool = False, in_props: bool = False
4431    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4432        desc = (
4433            self._match_set((TokenType.ASC, TokenType.DESC))
4434            and self._prev.token_type == TokenType.DESC
4435        )
4436
4437        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4438            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4439
4440        expressions = self._parse_wrapped_csv(
4441            self._parse_primary_key_part, optional=wrapped_optional
4442        )
4443        options = self._parse_key_constraint_options()
4444        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4445
4446    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4447        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4448
4449    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4450        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4451            return this
4452
4453        bracket_kind = self._prev.token_type
4454        expressions = self._parse_csv(
4455            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4456        )
4457
4458        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
4459            self.raise_error("Expected ]")
4460        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
4461            self.raise_error("Expected }")
4462
4463        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4464        if bracket_kind == TokenType.L_BRACE:
4465            this = self.expression(exp.Struct, expressions=expressions)
4466        elif not this or this.name.upper() == "ARRAY":
4467            this = self.expression(exp.Array, expressions=expressions)
4468        else:
4469            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4470            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4471
4472        self._add_comments(this)
4473        return self._parse_bracket(this)
4474
4475    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4476        if self._match(TokenType.COLON):
4477            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4478        return this
4479
4480    def _parse_case(self) -> t.Optional[exp.Expression]:
4481        ifs = []
4482        default = None
4483
4484        comments = self._prev_comments
4485        expression = self._parse_conjunction()
4486
4487        while self._match(TokenType.WHEN):
4488            this = self._parse_conjunction()
4489            self._match(TokenType.THEN)
4490            then = self._parse_conjunction()
4491            ifs.append(self.expression(exp.If, this=this, true=then))
4492
4493        if self._match(TokenType.ELSE):
4494            default = self._parse_conjunction()
4495
4496        if not self._match(TokenType.END):
4497            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4498                default = exp.column("interval")
4499            else:
4500                self.raise_error("Expected END after CASE", self._prev)
4501
4502        return self._parse_window(
4503            self.expression(exp.Case, comments=comments, this=expression, ifs=ifs, default=default)
4504        )
4505
4506    def _parse_if(self) -> t.Optional[exp.Expression]:
4507        if self._match(TokenType.L_PAREN):
4508            args = self._parse_csv(self._parse_conjunction)
4509            this = self.validate_expression(exp.If.from_arg_list(args), args)
4510            self._match_r_paren()
4511        else:
4512            index = self._index - 1
4513
4514            if self.NO_PAREN_IF_COMMANDS and index == 0:
4515                return self._parse_as_command(self._prev)
4516
4517            condition = self._parse_conjunction()
4518
4519            if not condition:
4520                self._retreat(index)
4521                return None
4522
4523            self._match(TokenType.THEN)
4524            true = self._parse_conjunction()
4525            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4526            self._match(TokenType.END)
4527            this = self.expression(exp.If, this=condition, true=true, false=false)
4528
4529        return self._parse_window(this)
4530
4531    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4532        if not self._match_text_seq("VALUE", "FOR"):
4533            self._retreat(self._index - 1)
4534            return None
4535
4536        return self.expression(
4537            exp.NextValueFor,
4538            this=self._parse_column(),
4539            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4540        )
4541
4542    def _parse_extract(self) -> exp.Extract:
4543        this = self._parse_function() or self._parse_var() or self._parse_type()
4544
4545        if self._match(TokenType.FROM):
4546            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4547
4548        if not self._match(TokenType.COMMA):
4549            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4550
4551        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4552
4553    def _parse_any_value(self) -> exp.AnyValue:
4554        this = self._parse_lambda()
4555        is_max = None
4556        having = None
4557
4558        if self._match(TokenType.HAVING):
4559            self._match_texts(("MAX", "MIN"))
4560            is_max = self._prev.text == "MAX"
4561            having = self._parse_column()
4562
4563        return self.expression(exp.AnyValue, this=this, having=having, max=is_max)
4564
4565    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4566        this = self._parse_conjunction()
4567
4568        if not self._match(TokenType.ALIAS):
4569            if self._match(TokenType.COMMA):
4570                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
4571
4572            self.raise_error("Expected AS after CAST")
4573
4574        fmt = None
4575        to = self._parse_types()
4576
4577        if self._match(TokenType.FORMAT):
4578            fmt_string = self._parse_string()
4579            fmt = self._parse_at_time_zone(fmt_string)
4580
4581            if not to:
4582                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
4583            if to.this in exp.DataType.TEMPORAL_TYPES:
4584                this = self.expression(
4585                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
4586                    this=this,
4587                    format=exp.Literal.string(
4588                        format_time(
4589                            fmt_string.this if fmt_string else "",
4590                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
4591                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
4592                        )
4593                    ),
4594                )
4595
4596                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
4597                    this.set("zone", fmt.args["zone"])
4598                return this
4599        elif not to:
4600            self.raise_error("Expected TYPE after CAST")
4601        elif isinstance(to, exp.Identifier):
4602            to = exp.DataType.build(to.name, udt=True)
4603        elif to.this == exp.DataType.Type.CHAR:
4604            if self._match(TokenType.CHARACTER_SET):
4605                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
4606
4607        return self.expression(
4608            exp.Cast if strict else exp.TryCast, this=this, to=to, format=fmt, safe=safe
4609        )
4610
4611    def _parse_string_agg(self) -> exp.Expression:
4612        if self._match(TokenType.DISTINCT):
4613            args: t.List[t.Optional[exp.Expression]] = [
4614                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
4615            ]
4616            if self._match(TokenType.COMMA):
4617                args.extend(self._parse_csv(self._parse_conjunction))
4618        else:
4619            args = self._parse_csv(self._parse_conjunction)  # type: ignore
4620
4621        index = self._index
4622        if not self._match(TokenType.R_PAREN) and args:
4623            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
4624            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
4625            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
4626            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
4627
4628        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
4629        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
4630        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
4631        if not self._match_text_seq("WITHIN", "GROUP"):
4632            self._retreat(index)
4633            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
4634
4635        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
4636        order = self._parse_order(this=seq_get(args, 0))
4637        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
4638
4639    def _parse_convert(
4640        self, strict: bool, safe: t.Optional[bool] = None
4641    ) -> t.Optional[exp.Expression]:
4642        this = self._parse_bitwise()
4643
4644        if self._match(TokenType.USING):
4645            to: t.Optional[exp.Expression] = self.expression(
4646                exp.CharacterSet, this=self._parse_var()
4647            )
4648        elif self._match(TokenType.COMMA):
4649            to = self._parse_types()
4650        else:
4651            to = None
4652
4653        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
4654
4655    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
4656        """
4657        There are generally two variants of the DECODE function:
4658
4659        - DECODE(bin, charset)
4660        - DECODE(expression, search, result [, search, result] ... [, default])
4661
4662        The second variant will always be parsed into a CASE expression. Note that NULL
4663        needs special treatment, since we need to explicitly check for it with `IS NULL`,
4664        instead of relying on pattern matching.
4665        """
4666        args = self._parse_csv(self._parse_conjunction)
4667
4668        if len(args) < 3:
4669            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
4670
4671        expression, *expressions = args
4672        if not expression:
4673            return None
4674
4675        ifs = []
4676        for search, result in zip(expressions[::2], expressions[1::2]):
4677            if not search or not result:
4678                return None
4679
4680            if isinstance(search, exp.Literal):
4681                ifs.append(
4682                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
4683                )
4684            elif isinstance(search, exp.Null):
4685                ifs.append(
4686                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
4687                )
4688            else:
4689                cond = exp.or_(
4690                    exp.EQ(this=expression.copy(), expression=search),
4691                    exp.and_(
4692                        exp.Is(this=expression.copy(), expression=exp.Null()),
4693                        exp.Is(this=search.copy(), expression=exp.Null()),
4694                        copy=False,
4695                    ),
4696                    copy=False,
4697                )
4698                ifs.append(exp.If(this=cond, true=result))
4699
4700        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
4701
4702    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
4703        self._match_text_seq("KEY")
4704        key = self._parse_column()
4705        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
4706        self._match_text_seq("VALUE")
4707        value = self._parse_bitwise()
4708
4709        if not key and not value:
4710            return None
4711        return self.expression(exp.JSONKeyValue, this=key, expression=value)
4712
4713    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4714        if not this or not self._match_text_seq("FORMAT", "JSON"):
4715            return this
4716
4717        return self.expression(exp.FormatJson, this=this)
4718
4719    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
4720        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
4721        for value in values:
4722            if self._match_text_seq(value, "ON", on):
4723                return f"{value} ON {on}"
4724
4725        return None
4726
4727    @t.overload
4728    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject:
4729        ...
4730
4731    @t.overload
4732    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg:
4733        ...
4734
4735    def _parse_json_object(self, agg=False):
4736        star = self._parse_star()
4737        expressions = (
4738            [star]
4739            if star
4740            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
4741        )
4742        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
4743
4744        unique_keys = None
4745        if self._match_text_seq("WITH", "UNIQUE"):
4746            unique_keys = True
4747        elif self._match_text_seq("WITHOUT", "UNIQUE"):
4748            unique_keys = False
4749
4750        self._match_text_seq("KEYS")
4751
4752        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
4753            self._parse_type()
4754        )
4755        encoding = self._match_text_seq("ENCODING") and self._parse_var()
4756
4757        return self.expression(
4758            exp.JSONObjectAgg if agg else exp.JSONObject,
4759            expressions=expressions,
4760            null_handling=null_handling,
4761            unique_keys=unique_keys,
4762            return_type=return_type,
4763            encoding=encoding,
4764        )
4765
4766    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
4767    def _parse_json_column_def(self) -> exp.JSONColumnDef:
4768        if not self._match_text_seq("NESTED"):
4769            this = self._parse_id_var()
4770            kind = self._parse_types(allow_identifiers=False)
4771            nested = None
4772        else:
4773            this = None
4774            kind = None
4775            nested = True
4776
4777        path = self._match_text_seq("PATH") and self._parse_string()
4778        nested_schema = nested and self._parse_json_schema()
4779
4780        return self.expression(
4781            exp.JSONColumnDef,
4782            this=this,
4783            kind=kind,
4784            path=path,
4785            nested_schema=nested_schema,
4786        )
4787
4788    def _parse_json_schema(self) -> exp.JSONSchema:
4789        self._match_text_seq("COLUMNS")
4790        return self.expression(
4791            exp.JSONSchema,
4792            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
4793        )
4794
4795    def _parse_json_table(self) -> exp.JSONTable:
4796        this = self._parse_format_json(self._parse_bitwise())
4797        path = self._match(TokenType.COMMA) and self._parse_string()
4798        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
4799        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
4800        schema = self._parse_json_schema()
4801
4802        return exp.JSONTable(
4803            this=this,
4804            schema=schema,
4805            path=path,
4806            error_handling=error_handling,
4807            empty_handling=empty_handling,
4808        )
4809
4810    def _parse_match_against(self) -> exp.MatchAgainst:
4811        expressions = self._parse_csv(self._parse_column)
4812
4813        self._match_text_seq(")", "AGAINST", "(")
4814
4815        this = self._parse_string()
4816
4817        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
4818            modifier = "IN NATURAL LANGUAGE MODE"
4819            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4820                modifier = f"{modifier} WITH QUERY EXPANSION"
4821        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
4822            modifier = "IN BOOLEAN MODE"
4823        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4824            modifier = "WITH QUERY EXPANSION"
4825        else:
4826            modifier = None
4827
4828        return self.expression(
4829            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
4830        )
4831
4832    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
4833    def _parse_open_json(self) -> exp.OpenJSON:
4834        this = self._parse_bitwise()
4835        path = self._match(TokenType.COMMA) and self._parse_string()
4836
4837        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
4838            this = self._parse_field(any_token=True)
4839            kind = self._parse_types()
4840            path = self._parse_string()
4841            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
4842
4843            return self.expression(
4844                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
4845            )
4846
4847        expressions = None
4848        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
4849            self._match_l_paren()
4850            expressions = self._parse_csv(_parse_open_json_column_def)
4851
4852        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
4853
4854    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
4855        args = self._parse_csv(self._parse_bitwise)
4856
4857        if self._match(TokenType.IN):
4858            return self.expression(
4859                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
4860            )
4861
4862        if haystack_first:
4863            haystack = seq_get(args, 0)
4864            needle = seq_get(args, 1)
4865        else:
4866            needle = seq_get(args, 0)
4867            haystack = seq_get(args, 1)
4868
4869        return self.expression(
4870            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
4871        )
4872
4873    def _parse_predict(self) -> exp.Predict:
4874        self._match_text_seq("MODEL")
4875        this = self._parse_table()
4876
4877        self._match(TokenType.COMMA)
4878        self._match_text_seq("TABLE")
4879
4880        return self.expression(
4881            exp.Predict,
4882            this=this,
4883            expression=self._parse_table(),
4884            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
4885        )
4886
4887    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
4888        args = self._parse_csv(self._parse_table)
4889        return exp.JoinHint(this=func_name.upper(), expressions=args)
4890
4891    def _parse_substring(self) -> exp.Substring:
4892        # Postgres supports the form: substring(string [from int] [for int])
4893        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
4894
4895        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
4896
4897        if self._match(TokenType.FROM):
4898            args.append(self._parse_bitwise())
4899            if self._match(TokenType.FOR):
4900                args.append(self._parse_bitwise())
4901
4902        return self.validate_expression(exp.Substring.from_arg_list(args), args)
4903
4904    def _parse_trim(self) -> exp.Trim:
4905        # https://www.w3resource.com/sql/character-functions/trim.php
4906        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
4907
4908        position = None
4909        collation = None
4910        expression = None
4911
4912        if self._match_texts(self.TRIM_TYPES):
4913            position = self._prev.text.upper()
4914
4915        this = self._parse_bitwise()
4916        if self._match_set((TokenType.FROM, TokenType.COMMA)):
4917            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
4918            expression = self._parse_bitwise()
4919
4920            if invert_order:
4921                this, expression = expression, this
4922
4923        if self._match(TokenType.COLLATE):
4924            collation = self._parse_bitwise()
4925
4926        return self.expression(
4927            exp.Trim, this=this, position=position, expression=expression, collation=collation
4928        )
4929
4930    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
4931        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
4932
4933    def _parse_named_window(self) -> t.Optional[exp.Expression]:
4934        return self._parse_window(self._parse_id_var(), alias=True)
4935
4936    def _parse_respect_or_ignore_nulls(
4937        self, this: t.Optional[exp.Expression]
4938    ) -> t.Optional[exp.Expression]:
4939        if self._match_text_seq("IGNORE", "NULLS"):
4940            return self.expression(exp.IgnoreNulls, this=this)
4941        if self._match_text_seq("RESPECT", "NULLS"):
4942            return self.expression(exp.RespectNulls, this=this)
4943        return this
4944
4945    def _parse_window(
4946        self, this: t.Optional[exp.Expression], alias: bool = False
4947    ) -> t.Optional[exp.Expression]:
4948        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
4949            self._match(TokenType.WHERE)
4950            this = self.expression(
4951                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
4952            )
4953            self._match_r_paren()
4954
4955        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
4956        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
4957        if self._match_text_seq("WITHIN", "GROUP"):
4958            order = self._parse_wrapped(self._parse_order)
4959            this = self.expression(exp.WithinGroup, this=this, expression=order)
4960
4961        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
4962        # Some dialects choose to implement and some do not.
4963        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
4964
4965        # There is some code above in _parse_lambda that handles
4966        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
4967
4968        # The below changes handle
4969        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
4970
4971        # Oracle allows both formats
4972        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
4973        #   and Snowflake chose to do the same for familiarity
4974        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
4975        if isinstance(this, exp.AggFunc):
4976            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
4977
4978            if ignore_respect and ignore_respect is not this:
4979                ignore_respect.replace(ignore_respect.this)
4980                this = self.expression(ignore_respect.__class__, this=this)
4981
4982        this = self._parse_respect_or_ignore_nulls(this)
4983
4984        # bigquery select from window x AS (partition by ...)
4985        if alias:
4986            over = None
4987            self._match(TokenType.ALIAS)
4988        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
4989            return this
4990        else:
4991            over = self._prev.text.upper()
4992
4993        if not self._match(TokenType.L_PAREN):
4994            return self.expression(
4995                exp.Window, this=this, alias=self._parse_id_var(False), over=over
4996            )
4997
4998        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
4999
5000        first = self._match(TokenType.FIRST)
5001        if self._match_text_seq("LAST"):
5002            first = False
5003
5004        partition, order = self._parse_partition_and_order()
5005        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5006
5007        if kind:
5008            self._match(TokenType.BETWEEN)
5009            start = self._parse_window_spec()
5010            self._match(TokenType.AND)
5011            end = self._parse_window_spec()
5012
5013            spec = self.expression(
5014                exp.WindowSpec,
5015                kind=kind,
5016                start=start["value"],
5017                start_side=start["side"],
5018                end=end["value"],
5019                end_side=end["side"],
5020            )
5021        else:
5022            spec = None
5023
5024        self._match_r_paren()
5025
5026        window = self.expression(
5027            exp.Window,
5028            this=this,
5029            partition_by=partition,
5030            order=order,
5031            spec=spec,
5032            alias=window_alias,
5033            over=over,
5034            first=first,
5035        )
5036
5037        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5038        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5039            return self._parse_window(window, alias=alias)
5040
5041        return window
5042
5043    def _parse_partition_and_order(
5044        self,
5045    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5046        return self._parse_partition_by(), self._parse_order()
5047
5048    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5049        self._match(TokenType.BETWEEN)
5050
5051        return {
5052            "value": (
5053                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5054                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5055                or self._parse_bitwise()
5056            ),
5057            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5058        }
5059
5060    def _parse_alias(
5061        self, this: t.Optional[exp.Expression], explicit: bool = False
5062    ) -> t.Optional[exp.Expression]:
5063        any_token = self._match(TokenType.ALIAS)
5064        comments = self._prev_comments
5065
5066        if explicit and not any_token:
5067            return this
5068
5069        if self._match(TokenType.L_PAREN):
5070            aliases = self.expression(
5071                exp.Aliases,
5072                comments=comments,
5073                this=this,
5074                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5075            )
5076            self._match_r_paren(aliases)
5077            return aliases
5078
5079        alias = self._parse_id_var(any_token) or (
5080            self.STRING_ALIASES and self._parse_string_as_identifier()
5081        )
5082
5083        if alias:
5084            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5085            column = this.this
5086
5087            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5088            if not this.comments and column and column.comments:
5089                this.comments = column.comments
5090                column.comments = None
5091
5092        return this
5093
5094    def _parse_id_var(
5095        self,
5096        any_token: bool = True,
5097        tokens: t.Optional[t.Collection[TokenType]] = None,
5098    ) -> t.Optional[exp.Expression]:
5099        identifier = self._parse_identifier()
5100
5101        if identifier:
5102            return identifier
5103
5104        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
5105            quoted = self._prev.token_type == TokenType.STRING
5106            return exp.Identifier(this=self._prev.text, quoted=quoted)
5107
5108        return None
5109
5110    def _parse_string(self) -> t.Optional[exp.Expression]:
5111        if self._match_set((TokenType.STRING, TokenType.RAW_STRING)):
5112            return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
5113        return self._parse_placeholder()
5114
5115    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5116        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5117
5118    def _parse_number(self) -> t.Optional[exp.Expression]:
5119        if self._match(TokenType.NUMBER):
5120            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
5121        return self._parse_placeholder()
5122
5123    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5124        if self._match(TokenType.IDENTIFIER):
5125            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5126        return self._parse_placeholder()
5127
5128    def _parse_var(
5129        self,
5130        any_token: bool = False,
5131        tokens: t.Optional[t.Collection[TokenType]] = None,
5132        upper: bool = False,
5133    ) -> t.Optional[exp.Expression]:
5134        if (
5135            (any_token and self._advance_any())
5136            or self._match(TokenType.VAR)
5137            or (self._match_set(tokens) if tokens else False)
5138        ):
5139            return self.expression(
5140                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5141            )
5142        return self._parse_placeholder()
5143
5144    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5145        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5146            self._advance()
5147            return self._prev
5148        return None
5149
5150    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5151        return self._parse_var() or self._parse_string()
5152
5153    def _parse_null(self) -> t.Optional[exp.Expression]:
5154        if self._match_set(self.NULL_TOKENS):
5155            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5156        return self._parse_placeholder()
5157
5158    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5159        if self._match(TokenType.TRUE):
5160            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5161        if self._match(TokenType.FALSE):
5162            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5163        return self._parse_placeholder()
5164
5165    def _parse_star(self) -> t.Optional[exp.Expression]:
5166        if self._match(TokenType.STAR):
5167            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5168        return self._parse_placeholder()
5169
5170    def _parse_parameter(self) -> exp.Parameter:
5171        def _parse_parameter_part() -> t.Optional[exp.Expression]:
5172            return (
5173                self._parse_identifier() or self._parse_primary() or self._parse_var(any_token=True)
5174            )
5175
5176        self._match(TokenType.L_BRACE)
5177        this = _parse_parameter_part()
5178        expression = self._match(TokenType.COLON) and _parse_parameter_part()
5179        self._match(TokenType.R_BRACE)
5180
5181        return self.expression(exp.Parameter, this=this, expression=expression)
5182
5183    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5184        if self._match_set(self.PLACEHOLDER_PARSERS):
5185            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5186            if placeholder:
5187                return placeholder
5188            self._advance(-1)
5189        return None
5190
5191    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5192        if not self._match(TokenType.EXCEPT):
5193            return None
5194        if self._match(TokenType.L_PAREN, advance=False):
5195            return self._parse_wrapped_csv(self._parse_column)
5196
5197        except_column = self._parse_column()
5198        return [except_column] if except_column else None
5199
5200    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5201        if not self._match(TokenType.REPLACE):
5202            return None
5203        if self._match(TokenType.L_PAREN, advance=False):
5204            return self._parse_wrapped_csv(self._parse_expression)
5205
5206        replace_expression = self._parse_expression()
5207        return [replace_expression] if replace_expression else None
5208
5209    def _parse_csv(
5210        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5211    ) -> t.List[exp.Expression]:
5212        parse_result = parse_method()
5213        items = [parse_result] if parse_result is not None else []
5214
5215        while self._match(sep):
5216            self._add_comments(parse_result)
5217            parse_result = parse_method()
5218            if parse_result is not None:
5219                items.append(parse_result)
5220
5221        return items
5222
5223    def _parse_tokens(
5224        self, parse_method: t.Callable, expressions: t.Dict
5225    ) -> t.Optional[exp.Expression]:
5226        this = parse_method()
5227
5228        while self._match_set(expressions):
5229            this = self.expression(
5230                expressions[self._prev.token_type],
5231                this=this,
5232                comments=self._prev_comments,
5233                expression=parse_method(),
5234            )
5235
5236        return this
5237
5238    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5239        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5240
5241    def _parse_wrapped_csv(
5242        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5243    ) -> t.List[exp.Expression]:
5244        return self._parse_wrapped(
5245            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5246        )
5247
5248    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5249        wrapped = self._match(TokenType.L_PAREN)
5250        if not wrapped and not optional:
5251            self.raise_error("Expecting (")
5252        parse_result = parse_method()
5253        if wrapped:
5254            self._match_r_paren()
5255        return parse_result
5256
5257    def _parse_expressions(self) -> t.List[exp.Expression]:
5258        return self._parse_csv(self._parse_expression)
5259
5260    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5261        return self._parse_select() or self._parse_set_operations(
5262            self._parse_expression() if alias else self._parse_conjunction()
5263        )
5264
5265    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5266        return self._parse_query_modifiers(
5267            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5268        )
5269
5270    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5271        this = None
5272        if self._match_texts(self.TRANSACTION_KIND):
5273            this = self._prev.text
5274
5275        self._match_texts(("TRANSACTION", "WORK"))
5276
5277        modes = []
5278        while True:
5279            mode = []
5280            while self._match(TokenType.VAR):
5281                mode.append(self._prev.text)
5282
5283            if mode:
5284                modes.append(" ".join(mode))
5285            if not self._match(TokenType.COMMA):
5286                break
5287
5288        return self.expression(exp.Transaction, this=this, modes=modes)
5289
5290    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5291        chain = None
5292        savepoint = None
5293        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5294
5295        self._match_texts(("TRANSACTION", "WORK"))
5296
5297        if self._match_text_seq("TO"):
5298            self._match_text_seq("SAVEPOINT")
5299            savepoint = self._parse_id_var()
5300
5301        if self._match(TokenType.AND):
5302            chain = not self._match_text_seq("NO")
5303            self._match_text_seq("CHAIN")
5304
5305        if is_rollback:
5306            return self.expression(exp.Rollback, savepoint=savepoint)
5307
5308        return self.expression(exp.Commit, chain=chain)
5309
5310    def _parse_refresh(self) -> exp.Refresh:
5311        self._match(TokenType.TABLE)
5312        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5313
5314    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5315        if not self._match_text_seq("ADD"):
5316            return None
5317
5318        self._match(TokenType.COLUMN)
5319        exists_column = self._parse_exists(not_=True)
5320        expression = self._parse_field_def()
5321
5322        if expression:
5323            expression.set("exists", exists_column)
5324
5325            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5326            if self._match_texts(("FIRST", "AFTER")):
5327                position = self._prev.text
5328                column_position = self.expression(
5329                    exp.ColumnPosition, this=self._parse_column(), position=position
5330                )
5331                expression.set("position", column_position)
5332
5333        return expression
5334
5335    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5336        drop = self._match(TokenType.DROP) and self._parse_drop()
5337        if drop and not isinstance(drop, exp.Command):
5338            drop.set("kind", drop.args.get("kind", "COLUMN"))
5339        return drop
5340
5341    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5342    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5343        return self.expression(
5344            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5345        )
5346
5347    def _parse_add_constraint(self) -> exp.AddConstraint:
5348        this = None
5349        kind = self._prev.token_type
5350
5351        if kind == TokenType.CONSTRAINT:
5352            this = self._parse_id_var()
5353
5354            if self._match_text_seq("CHECK"):
5355                expression = self._parse_wrapped(self._parse_conjunction)
5356                enforced = self._match_text_seq("ENFORCED") or False
5357
5358                return self.expression(
5359                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
5360                )
5361
5362        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
5363            expression = self._parse_foreign_key()
5364        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
5365            expression = self._parse_primary_key()
5366        else:
5367            expression = None
5368
5369        return self.expression(exp.AddConstraint, this=this, expression=expression)
5370
5371    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5372        index = self._index - 1
5373
5374        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
5375            return self._parse_csv(self._parse_add_constraint)
5376
5377        self._retreat(index)
5378        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5379            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5380        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5381
5382    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5383        self._match(TokenType.COLUMN)
5384        column = self._parse_field(any_token=True)
5385
5386        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5387            return self.expression(exp.AlterColumn, this=column, drop=True)
5388        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5389            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5390        if self._match(TokenType.COMMENT):
5391            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
5392
5393        self._match_text_seq("SET", "DATA")
5394        return self.expression(
5395            exp.AlterColumn,
5396            this=column,
5397            dtype=self._match_text_seq("TYPE") and self._parse_types(),
5398            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5399            using=self._match(TokenType.USING) and self._parse_conjunction(),
5400        )
5401
5402    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5403        index = self._index - 1
5404
5405        partition_exists = self._parse_exists()
5406        if self._match(TokenType.PARTITION, advance=False):
5407            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5408
5409        self._retreat(index)
5410        return self._parse_csv(self._parse_drop_column)
5411
5412    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
5413        if self._match(TokenType.COLUMN):
5414            exists = self._parse_exists()
5415            old_column = self._parse_column()
5416            to = self._match_text_seq("TO")
5417            new_column = self._parse_column()
5418
5419            if old_column is None or to is None or new_column is None:
5420                return None
5421
5422            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
5423
5424        self._match_text_seq("TO")
5425        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5426
5427    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5428        start = self._prev
5429
5430        if not self._match(TokenType.TABLE):
5431            return self._parse_as_command(start)
5432
5433        exists = self._parse_exists()
5434        only = self._match_text_seq("ONLY")
5435        this = self._parse_table(schema=True)
5436
5437        if self._next:
5438            self._advance()
5439
5440        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5441        if parser:
5442            actions = ensure_list(parser(self))
5443
5444            if not self._curr and actions:
5445                return self.expression(
5446                    exp.AlterTable,
5447                    this=this,
5448                    exists=exists,
5449                    actions=actions,
5450                    only=only,
5451                )
5452
5453        return self._parse_as_command(start)
5454
5455    def _parse_merge(self) -> exp.Merge:
5456        self._match(TokenType.INTO)
5457        target = self._parse_table()
5458
5459        if target and self._match(TokenType.ALIAS, advance=False):
5460            target.set("alias", self._parse_table_alias())
5461
5462        self._match(TokenType.USING)
5463        using = self._parse_table()
5464
5465        self._match(TokenType.ON)
5466        on = self._parse_conjunction()
5467
5468        return self.expression(
5469            exp.Merge,
5470            this=target,
5471            using=using,
5472            on=on,
5473            expressions=self._parse_when_matched(),
5474        )
5475
5476    def _parse_when_matched(self) -> t.List[exp.When]:
5477        whens = []
5478
5479        while self._match(TokenType.WHEN):
5480            matched = not self._match(TokenType.NOT)
5481            self._match_text_seq("MATCHED")
5482            source = (
5483                False
5484                if self._match_text_seq("BY", "TARGET")
5485                else self._match_text_seq("BY", "SOURCE")
5486            )
5487            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5488
5489            self._match(TokenType.THEN)
5490
5491            if self._match(TokenType.INSERT):
5492                _this = self._parse_star()
5493                if _this:
5494                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5495                else:
5496                    then = self.expression(
5497                        exp.Insert,
5498                        this=self._parse_value(),
5499                        expression=self._match(TokenType.VALUES) and self._parse_value(),
5500                    )
5501            elif self._match(TokenType.UPDATE):
5502                expressions = self._parse_star()
5503                if expressions:
5504                    then = self.expression(exp.Update, expressions=expressions)
5505                else:
5506                    then = self.expression(
5507                        exp.Update,
5508                        expressions=self._match(TokenType.SET)
5509                        and self._parse_csv(self._parse_equality),
5510                    )
5511            elif self._match(TokenType.DELETE):
5512                then = self.expression(exp.Var, this=self._prev.text)
5513            else:
5514                then = None
5515
5516            whens.append(
5517                self.expression(
5518                    exp.When,
5519                    matched=matched,
5520                    source=source,
5521                    condition=condition,
5522                    then=then,
5523                )
5524            )
5525        return whens
5526
5527    def _parse_show(self) -> t.Optional[exp.Expression]:
5528        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5529        if parser:
5530            return parser(self)
5531        return self._parse_as_command(self._prev)
5532
5533    def _parse_set_item_assignment(
5534        self, kind: t.Optional[str] = None
5535    ) -> t.Optional[exp.Expression]:
5536        index = self._index
5537
5538        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5539            return self._parse_set_transaction(global_=kind == "GLOBAL")
5540
5541        left = self._parse_primary() or self._parse_id_var()
5542        assignment_delimiter = self._match_texts(("=", "TO"))
5543
5544        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5545            self._retreat(index)
5546            return None
5547
5548        right = self._parse_statement() or self._parse_id_var()
5549        this = self.expression(exp.EQ, this=left, expression=right)
5550
5551        return self.expression(exp.SetItem, this=this, kind=kind)
5552
5553    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5554        self._match_text_seq("TRANSACTION")
5555        characteristics = self._parse_csv(
5556            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5557        )
5558        return self.expression(
5559            exp.SetItem,
5560            expressions=characteristics,
5561            kind="TRANSACTION",
5562            **{"global": global_},  # type: ignore
5563        )
5564
5565    def _parse_set_item(self) -> t.Optional[exp.Expression]:
5566        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
5567        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
5568
5569    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
5570        index = self._index
5571        set_ = self.expression(
5572            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
5573        )
5574
5575        if self._curr:
5576            self._retreat(index)
5577            return self._parse_as_command(self._prev)
5578
5579        return set_
5580
5581    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
5582        for option in options:
5583            if self._match_text_seq(*option.split(" ")):
5584                return exp.var(option)
5585        return None
5586
5587    def _parse_as_command(self, start: Token) -> exp.Command:
5588        while self._curr:
5589            self._advance()
5590        text = self._find_sql(start, self._prev)
5591        size = len(start.text)
5592        self._warn_unsupported()
5593        return exp.Command(this=text[:size], expression=text[size:])
5594
5595    def _parse_dict_property(self, this: str) -> exp.DictProperty:
5596        settings = []
5597
5598        self._match_l_paren()
5599        kind = self._parse_id_var()
5600
5601        if self._match(TokenType.L_PAREN):
5602            while True:
5603                key = self._parse_id_var()
5604                value = self._parse_primary()
5605
5606                if not key and value is None:
5607                    break
5608                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
5609            self._match(TokenType.R_PAREN)
5610
5611        self._match_r_paren()
5612
5613        return self.expression(
5614            exp.DictProperty,
5615            this=this,
5616            kind=kind.this if kind else None,
5617            settings=settings,
5618        )
5619
5620    def _parse_dict_range(self, this: str) -> exp.DictRange:
5621        self._match_l_paren()
5622        has_min = self._match_text_seq("MIN")
5623        if has_min:
5624            min = self._parse_var() or self._parse_primary()
5625            self._match_text_seq("MAX")
5626            max = self._parse_var() or self._parse_primary()
5627        else:
5628            max = self._parse_var() or self._parse_primary()
5629            min = exp.Literal.number(0)
5630        self._match_r_paren()
5631        return self.expression(exp.DictRange, this=this, min=min, max=max)
5632
5633    def _parse_comprehension(
5634        self, this: t.Optional[exp.Expression]
5635    ) -> t.Optional[exp.Comprehension]:
5636        index = self._index
5637        expression = self._parse_column()
5638        if not self._match(TokenType.IN):
5639            self._retreat(index - 1)
5640            return None
5641        iterator = self._parse_column()
5642        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
5643        return self.expression(
5644            exp.Comprehension,
5645            this=this,
5646            expression=expression,
5647            iterator=iterator,
5648            condition=condition,
5649        )
5650
5651    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
5652        if self._match(TokenType.HEREDOC_STRING):
5653            return self.expression(exp.Heredoc, this=self._prev.text)
5654
5655        if not self._match_text_seq("$"):
5656            return None
5657
5658        tags = ["$"]
5659        tag_text = None
5660
5661        if self._is_connected():
5662            self._advance()
5663            tags.append(self._prev.text.upper())
5664        else:
5665            self.raise_error("No closing $ found")
5666
5667        if tags[-1] != "$":
5668            if self._is_connected() and self._match_text_seq("$"):
5669                tag_text = tags[-1]
5670                tags.append("$")
5671            else:
5672                self.raise_error("No closing $ found")
5673
5674        heredoc_start = self._curr
5675
5676        while self._curr:
5677            if self._match_text_seq(*tags, advance=False):
5678                this = self._find_sql(heredoc_start, self._prev)
5679                self._advance(len(tags))
5680                return self.expression(exp.Heredoc, this=this, tag=tag_text)
5681
5682            self._advance()
5683
5684        self.raise_error(f"No closing {''.join(tags)} found")
5685        return None
5686
5687    def _find_parser(
5688        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
5689    ) -> t.Optional[t.Callable]:
5690        if not self._curr:
5691            return None
5692
5693        index = self._index
5694        this = []
5695        while True:
5696            # The current token might be multiple words
5697            curr = self._curr.text.upper()
5698            key = curr.split(" ")
5699            this.append(curr)
5700
5701            self._advance()
5702            result, trie = in_trie(trie, key)
5703            if result == TrieResult.FAILED:
5704                break
5705
5706            if result == TrieResult.EXISTS:
5707                subparser = parsers[" ".join(this)]
5708                return subparser
5709
5710        self._retreat(index)
5711        return None
5712
5713    def _match(self, token_type, advance=True, expression=None):
5714        if not self._curr:
5715            return None
5716
5717        if self._curr.token_type == token_type:
5718            if advance:
5719                self._advance()
5720            self._add_comments(expression)
5721            return True
5722
5723        return None
5724
5725    def _match_set(self, types, advance=True):
5726        if not self._curr:
5727            return None
5728
5729        if self._curr.token_type in types:
5730            if advance:
5731                self._advance()
5732            return True
5733
5734        return None
5735
5736    def _match_pair(self, token_type_a, token_type_b, advance=True):
5737        if not self._curr or not self._next:
5738            return None
5739
5740        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
5741            if advance:
5742                self._advance(2)
5743            return True
5744
5745        return None
5746
5747    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5748        if not self._match(TokenType.L_PAREN, expression=expression):
5749            self.raise_error("Expecting (")
5750
5751    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5752        if not self._match(TokenType.R_PAREN, expression=expression):
5753            self.raise_error("Expecting )")
5754
5755    def _match_texts(self, texts, advance=True):
5756        if self._curr and self._curr.text.upper() in texts:
5757            if advance:
5758                self._advance()
5759            return True
5760        return None
5761
5762    def _match_text_seq(self, *texts, advance=True):
5763        index = self._index
5764        for text in texts:
5765            if self._curr and self._curr.text.upper() == text:
5766                self._advance()
5767            else:
5768                self._retreat(index)
5769                return None
5770
5771        if not advance:
5772            self._retreat(index)
5773
5774        return True
5775
5776    @t.overload
5777    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
5778        ...
5779
5780    @t.overload
5781    def _replace_columns_with_dots(
5782        self, this: t.Optional[exp.Expression]
5783    ) -> t.Optional[exp.Expression]:
5784        ...
5785
5786    def _replace_columns_with_dots(self, this):
5787        if isinstance(this, exp.Dot):
5788            exp.replace_children(this, self._replace_columns_with_dots)
5789        elif isinstance(this, exp.Column):
5790            exp.replace_children(this, self._replace_columns_with_dots)
5791            table = this.args.get("table")
5792            this = (
5793                self.expression(exp.Dot, this=table, expression=this.this) if table else this.this
5794            )
5795
5796        return this
5797
5798    def _replace_lambda(
5799        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
5800    ) -> t.Optional[exp.Expression]:
5801        if not node:
5802            return node
5803
5804        for column in node.find_all(exp.Column):
5805            if column.parts[0].name in lambda_variables:
5806                dot_or_id = column.to_dot() if column.table else column.this
5807                parent = column.parent
5808
5809                while isinstance(parent, exp.Dot):
5810                    if not isinstance(parent.parent, exp.Dot):
5811                        parent.replace(dot_or_id)
5812                        break
5813                    parent = parent.parent
5814                else:
5815                    if column is node:
5816                        node = dot_or_id
5817                    else:
5818                        column.replace(dot_or_id)
5819        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)
1027    def __init__(
1028        self,
1029        error_level: t.Optional[ErrorLevel] = None,
1030        error_message_context: int = 100,
1031        max_errors: int = 3,
1032        dialect: DialectType = None,
1033    ):
1034        from sqlglot.dialects import Dialect
1035
1036        self.error_level = error_level or ErrorLevel.IMMEDIATE
1037        self.error_message_context = error_message_context
1038        self.max_errors = max_errors
1039        self.dialect = Dialect.get_or_raise(dialect)
1040        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_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_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'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <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': <function parse_extract_json_with_path.<locals>._parser>, 'JSON_EXTRACT_SCALAR': <function parse_extract_json_with_path.<locals>._parser>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, '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'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, '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'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, '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>>, 'JSON_EXTRACT_PATH_TEXT': <function parse_extract_json_with_path.<locals>._parser>, '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.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NULLABLE: 'NULLABLE'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
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.MOD: 'MOD'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.CARET: 'CARET'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STAR: 'STAR'>, <TokenType.TILDA: 'TILDA'>, <TokenType.HASH: 'HASH'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.AMP: 'AMP'>, <TokenType.COMMA: 'COMMA'>, <TokenType.DOT: 'DOT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.EQ: 'EQ'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.GT: 'GT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PIPE: 'PIPE'>, <TokenType.SLASH: 'SLASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.NOT: 'NOT'>, <TokenType.DASH: 'DASH'>, <TokenType.LT: 'LT'>, <TokenType.COLON: 'COLON'>}
DB_CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.COLUMN: 'COLUMN'>}
ID_VAR_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.FULL: 'FULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
INTERVAL_VARS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.FULL: 'FULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
TABLE_ALIAS_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
UPDATE_ALIAS_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UUID: 'UUID'>, <TokenType.FIRST: 'FIRST'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.XOR: 'XOR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.LIKE: 'LIKE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.GLOB: 'GLOB'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INSERT: 'INSERT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
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.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.SEMI: 'SEMI'>}
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>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, '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>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PERIOD', 'CHECK', 'LIKE', 'FOREIGN KEY', 'UNIQUE', 'PRIMARY 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.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
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.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL READ COMMITTED', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ ONLY', 'READ WRITE'}
INSERT_ALTERNATIVES = {'ROLLBACK', 'IGNORE', 'FAIL', 'ABORT', 'REPLACE'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'TIMESTAMP', 'STREAM', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'NULLS'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.FULL: 'FULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COLON: 'COLON'>, <TokenType.COMMA: 'COMMA'>}
FETCH_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.FULL: 'FULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT: 'INT'>, <TokenType.FULL: 'FULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.USE: 'USE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DESC: 'DESC'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.XML: 'XML'>, <TokenType.IS: 'IS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DIV: 'DIV'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROW: 'ROW'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UUID: 'UUID'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SET: 'SET'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UINT: 'UINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ASC: 'ASC'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.END: 'END'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INT256: 'INT256'>, <TokenType.DATE: 'DATE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IPV4: 'IPV4'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NULL: 'NULL'>}
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 = {'offset', 'limit', 'order'}
NO_PAREN_IF_COMMANDS = True
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1042    def reset(self):
1043        self.sql = ""
1044        self.errors = []
1045        self._tokens = []
1046        self._index = 0
1047        self._curr = None
1048        self._next = None
1049        self._prev = None
1050        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1052    def parse(
1053        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1054    ) -> t.List[t.Optional[exp.Expression]]:
1055        """
1056        Parses a list of tokens and returns a list of syntax trees, one tree
1057        per parsed SQL statement.
1058
1059        Args:
1060            raw_tokens: The list of tokens.
1061            sql: The original SQL string, used to produce helpful debug messages.
1062
1063        Returns:
1064            The list of the produced syntax trees.
1065        """
1066        return self._parse(
1067            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1068        )

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]]:
1070    def parse_into(
1071        self,
1072        expression_types: exp.IntoType,
1073        raw_tokens: t.List[Token],
1074        sql: t.Optional[str] = None,
1075    ) -> t.List[t.Optional[exp.Expression]]:
1076        """
1077        Parses a list of tokens into a given Expression type. If a collection of Expression
1078        types is given instead, this method will try to parse the token list into each one
1079        of them, stopping at the first for which the parsing succeeds.
1080
1081        Args:
1082            expression_types: The expression type(s) to try and parse the token list into.
1083            raw_tokens: The list of tokens.
1084            sql: The original SQL string, used to produce helpful debug messages.
1085
1086        Returns:
1087            The target Expression.
1088        """
1089        errors = []
1090        for expression_type in ensure_list(expression_types):
1091            parser = self.EXPRESSION_PARSERS.get(expression_type)
1092            if not parser:
1093                raise TypeError(f"No parser registered for {expression_type}")
1094
1095            try:
1096                return self._parse(parser, raw_tokens, sql)
1097            except ParseError as e:
1098                e.errors[0]["into_expression"] = expression_type
1099                errors.append(e)
1100
1101        raise ParseError(
1102            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1103            errors=merge_errors(errors),
1104        ) 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:
1141    def check_errors(self) -> None:
1142        """Logs or raises any found errors, depending on the chosen error level setting."""
1143        if self.error_level == ErrorLevel.WARN:
1144            for error in self.errors:
1145                logger.error(str(error))
1146        elif self.error_level == ErrorLevel.RAISE and self.errors:
1147            raise ParseError(
1148                concat_messages(self.errors, self.max_errors),
1149                errors=merge_errors(self.errors),
1150            )

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:
1152    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1153        """
1154        Appends an error in the list of recorded errors or raises it, depending on the chosen
1155        error level setting.
1156        """
1157        token = token or self._curr or self._prev or Token.string("")
1158        start = token.start
1159        end = token.end + 1
1160        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1161        highlight = self.sql[start:end]
1162        end_context = self.sql[end : end + self.error_message_context]
1163
1164        error = ParseError.new(
1165            f"{message}. Line {token.line}, Col: {token.col}.\n"
1166            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1167            description=message,
1168            line=token.line,
1169            col=token.col,
1170            start_context=start_context,
1171            highlight=highlight,
1172            end_context=end_context,
1173        )
1174
1175        if self.error_level == ErrorLevel.IMMEDIATE:
1176            raise error
1177
1178        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:
1180    def expression(
1181        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1182    ) -> E:
1183        """
1184        Creates a new, validated Expression.
1185
1186        Args:
1187            exp_class: The expression class to instantiate.
1188            comments: An optional list of comments to attach to the expression.
1189            kwargs: The arguments to set for the expression along with their respective values.
1190
1191        Returns:
1192            The target expression.
1193        """
1194        instance = exp_class(**kwargs)
1195        instance.add_comments(comments) if comments else self._add_comments(instance)
1196        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:
1203    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1204        """
1205        Validates an Expression, making sure that all its mandatory arguments are set.
1206
1207        Args:
1208            expression: The expression to validate.
1209            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1210
1211        Returns:
1212            The validated expression.
1213        """
1214        if self.error_level != ErrorLevel.IGNORE:
1215            for error_message in expression.error_messages(args):
1216                self.raise_error(error_message)
1217
1218        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