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

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]]:
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]

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:
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            )

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:
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)

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:
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)

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:
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

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