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

Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.

Arguments:
  • error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
  • error_message_context: The amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
  • max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3
Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None)
1090    def __init__(
1091        self,
1092        error_level: t.Optional[ErrorLevel] = None,
1093        error_message_context: int = 100,
1094        max_errors: int = 3,
1095        dialect: DialectType = None,
1096    ):
1097        from sqlglot.dialects import Dialect
1098
1099        self.error_level = error_level or ErrorLevel.IMMEDIATE
1100        self.error_message_context = error_message_context
1101        self.max_errors = max_errors
1102        self.dialect = Dialect.get_or_raise(dialect)
1103        self.reset()
FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_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_TO_STRING': <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_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, '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'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_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'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, '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 build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MAP: 'MAP'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSON: 'JSON'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.INT: 'INT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.SUPER: 'SUPER'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.GT: 'GT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CARET: 'CARET'>, <TokenType.HASH: 'HASH'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.LT: 'LT'>, <TokenType.MOD: 'MOD'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.AMP: 'AMP'>, <TokenType.TILDA: 'TILDA'>, <TokenType.COLON: 'COLON'>, <TokenType.PLUS: 'PLUS'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.EQ: 'EQ'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.NOT: 'NOT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.DASH: 'DASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.STAR: 'STAR'>, <TokenType.DOT: 'DOT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.SELECT: 'SELECT'>}
DB_CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MODEL: 'MODEL'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MODEL: 'MODEL'>}
ID_VAR_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ASC: 'ASC'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
INTERVAL_VARS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ASC: 'ASC'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
TABLE_ALIAS_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ASC: 'ASC'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ASC: 'ASC'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MODEL: 'MODEL'>}
UPDATE_ALIAS_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ASC: 'ASC'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MODEL: 'MODEL'>}
TRIM_TYPES = {'BOTH', 'TRAILING', 'LEADING'}
FUNC_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSON: 'JSON'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.LIKE: 'LIKE'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.BIT: 'BIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.XOR: 'XOR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.INT: 'INT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.GLOB: 'GLOB'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.SUPER: 'SUPER'>}
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.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <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>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<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>>, 'GLOBAL': <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>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PERIOD', 'UNIQUE', 'LIKE', 'FOREIGN KEY', 'PRIMARY KEY', 'CHECK'}
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'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
INSERT_ALTERNATIVES = {'ABORT', 'REPLACE', 'IGNORE', 'ROLLBACK', 'FAIL'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'STREAM', 'OFFSET', 'TIMESTAMP'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'NULLS'}
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.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ASC: 'ASC'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>}
FETCH_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ASC: 'ASC'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.DATE: 'DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.END: 'END'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ALL: 'ALL'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MAP: 'MAP'>, <TokenType.ROW: 'ROW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MERGE: 'MERGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.JSON: 'JSON'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CASE: 'CASE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SUPER: 'SUPER'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SET: 'SET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VAR: 'VAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INT128: 'INT128'>, <TokenType.DIV: 'DIV'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESC: 'DESC'>, <TokenType.USE: 'USE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.ENUM: 'ENUM'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ASC: 'ASC'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT: 'INT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATE32: 'DATE32'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.XML: 'XML'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.MODEL: 'MODEL'>}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'offset', 'limit', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1105    def reset(self):
1106        self.sql = ""
1107        self.errors = []
1108        self._tokens = []
1109        self._index = 0
1110        self._curr = None
1111        self._next = None
1112        self._prev = None
1113        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1115    def parse(
1116        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1117    ) -> t.List[t.Optional[exp.Expression]]:
1118        """
1119        Parses a list of tokens and returns a list of syntax trees, one tree
1120        per parsed SQL statement.
1121
1122        Args:
1123            raw_tokens: The list of tokens.
1124            sql: The original SQL string, used to produce helpful debug messages.
1125
1126        Returns:
1127            The list of the produced syntax trees.
1128        """
1129        return self._parse(
1130            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1131        )

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]]:
1133    def parse_into(
1134        self,
1135        expression_types: exp.IntoType,
1136        raw_tokens: t.List[Token],
1137        sql: t.Optional[str] = None,
1138    ) -> t.List[t.Optional[exp.Expression]]:
1139        """
1140        Parses a list of tokens into a given Expression type. If a collection of Expression
1141        types is given instead, this method will try to parse the token list into each one
1142        of them, stopping at the first for which the parsing succeeds.
1143
1144        Args:
1145            expression_types: The expression type(s) to try and parse the token list into.
1146            raw_tokens: The list of tokens.
1147            sql: The original SQL string, used to produce helpful debug messages.
1148
1149        Returns:
1150            The target Expression.
1151        """
1152        errors = []
1153        for expression_type in ensure_list(expression_types):
1154            parser = self.EXPRESSION_PARSERS.get(expression_type)
1155            if not parser:
1156                raise TypeError(f"No parser registered for {expression_type}")
1157
1158            try:
1159                return self._parse(parser, raw_tokens, sql)
1160            except ParseError as e:
1161                e.errors[0]["into_expression"] = expression_type
1162                errors.append(e)
1163
1164        raise ParseError(
1165            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1166            errors=merge_errors(errors),
1167        ) 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:
1204    def check_errors(self) -> None:
1205        """Logs or raises any found errors, depending on the chosen error level setting."""
1206        if self.error_level == ErrorLevel.WARN:
1207            for error in self.errors:
1208                logger.error(str(error))
1209        elif self.error_level == ErrorLevel.RAISE and self.errors:
1210            raise ParseError(
1211                concat_messages(self.errors, self.max_errors),
1212                errors=merge_errors(self.errors),
1213            )

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:
1215    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1216        """
1217        Appends an error in the list of recorded errors or raises it, depending on the chosen
1218        error level setting.
1219        """
1220        token = token or self._curr or self._prev or Token.string("")
1221        start = token.start
1222        end = token.end + 1
1223        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1224        highlight = self.sql[start:end]
1225        end_context = self.sql[end : end + self.error_message_context]
1226
1227        error = ParseError.new(
1228            f"{message}. Line {token.line}, Col: {token.col}.\n"
1229            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1230            description=message,
1231            line=token.line,
1232            col=token.col,
1233            start_context=start_context,
1234            highlight=highlight,
1235            end_context=end_context,
1236        )
1237
1238        if self.error_level == ErrorLevel.IMMEDIATE:
1239            raise error
1240
1241        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:
1243    def expression(
1244        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1245    ) -> E:
1246        """
1247        Creates a new, validated Expression.
1248
1249        Args:
1250            exp_class: The expression class to instantiate.
1251            comments: An optional list of comments to attach to the expression.
1252            kwargs: The arguments to set for the expression along with their respective values.
1253
1254        Returns:
1255            The target expression.
1256        """
1257        instance = exp_class(**kwargs)
1258        instance.add_comments(comments) if comments else self._add_comments(instance)
1259        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:
1266    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1267        """
1268        Validates an Expression, making sure that all its mandatory arguments are set.
1269
1270        Args:
1271            expression: The expression to validate.
1272            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1273
1274        Returns:
1275            The validated expression.
1276        """
1277        if self.error_level != ErrorLevel.IGNORE:
1278            for error_message in expression.error_messages(args):
1279                self.raise_error(error_message)
1280
1281        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