Edit on GitHub

sqlglot.parser

   1from __future__ import annotations
   2
   3import logging
   4import typing as t
   5from collections import defaultdict
   6
   7from sqlglot import exp
   8from sqlglot.errors import ErrorLevel, ParseError, concat_messages, merge_errors
   9from sqlglot.helper import apply_index_offset, ensure_list, seq_get
  10from sqlglot.time import format_time
  11from sqlglot.tokens import Token, Tokenizer, TokenType
  12from sqlglot.trie import TrieResult, in_trie, new_trie
  13
  14if t.TYPE_CHECKING:
  15    from sqlglot._typing import E, Lit
  16    from sqlglot.dialects.dialect import Dialect, DialectType
  17
  18    T = t.TypeVar("T")
  19
  20logger = logging.getLogger("sqlglot")
  21
  22OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
  23
  24
  25def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  26    if len(args) == 1 and args[0].is_star:
  27        return exp.StarMap(this=args[0])
  28
  29    keys = []
  30    values = []
  31    for i in range(0, len(args), 2):
  32        keys.append(args[i])
  33        values.append(args[i + 1])
  34
  35    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
  36
  37
  38def build_like(args: t.List) -> exp.Escape | exp.Like:
  39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  41
  42
  43def binary_range_parser(
  44    expr_type: t.Type[exp.Expression],
  45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  46    return lambda self, this: self._parse_escape(
  47        self.expression(expr_type, this=this, expression=self._parse_bitwise())
  48    )
  49
  50
  51def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  52    # Default argument order is base, expression
  53    this = seq_get(args, 0)
  54    expression = seq_get(args, 1)
  55
  56    if expression:
  57        if not dialect.LOG_BASE_FIRST:
  58            this, expression = expression, this
  59        return exp.Log(this=this, expression=expression)
  60
  61    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  62
  63
  64def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
  65    def _builder(args: t.List, dialect: Dialect) -> E:
  66        expression = expr_type(
  67            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
  68        )
  69        if len(args) > 2 and expr_type is exp.JSONExtract:
  70            expression.set("expressions", args[2:])
  71
  72        return expression
  73
  74    return _builder
  75
  76
  77class _Parser(type):
  78    def __new__(cls, clsname, bases, attrs):
  79        klass = super().__new__(cls, clsname, bases, attrs)
  80
  81        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
  82        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
  83
  84        return klass
  85
  86
  87class Parser(metaclass=_Parser):
  88    """
  89    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  90
  91    Args:
  92        error_level: The desired error level.
  93            Default: ErrorLevel.IMMEDIATE
  94        error_message_context: The amount of context to capture from a query string when displaying
  95            the error message (in number of characters).
  96            Default: 100
  97        max_errors: Maximum number of error messages to include in a raised ParseError.
  98            This is only relevant if error_level is ErrorLevel.RAISE.
  99            Default: 3
 100    """
 101
 102    FUNCTIONS: t.Dict[str, t.Callable] = {
 103        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 104        "CONCAT": lambda args, dialect: exp.Concat(
 105            expressions=args,
 106            safe=not dialect.STRICT_STRING_CONCAT,
 107            coalesce=dialect.CONCAT_COALESCE,
 108        ),
 109        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 110            expressions=args,
 111            safe=not dialect.STRICT_STRING_CONCAT,
 112            coalesce=dialect.CONCAT_COALESCE,
 113        ),
 114        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 115            this=seq_get(args, 0),
 116            to=exp.DataType(this=exp.DataType.Type.TEXT),
 117        ),
 118        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 119        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 120        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 121        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 122        "LIKE": build_like,
 123        "LOG": build_logarithm,
 124        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 125        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 126        "MOD": lambda args: exp.Mod(this=seq_get(args, 0), expression=seq_get(args, 1)),
 127        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 128            this=seq_get(args, 0),
 129            to=exp.DataType(this=exp.DataType.Type.TEXT),
 130        ),
 131        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 132            this=exp.Cast(
 133                this=seq_get(args, 0),
 134                to=exp.DataType(this=exp.DataType.Type.TEXT),
 135            ),
 136            start=exp.Literal.number(1),
 137            length=exp.Literal.number(10),
 138        ),
 139        "VAR_MAP": build_var_map,
 140    }
 141
 142    NO_PAREN_FUNCTIONS = {
 143        TokenType.CURRENT_DATE: exp.CurrentDate,
 144        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 145        TokenType.CURRENT_TIME: exp.CurrentTime,
 146        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 147        TokenType.CURRENT_USER: exp.CurrentUser,
 148    }
 149
 150    STRUCT_TYPE_TOKENS = {
 151        TokenType.NESTED,
 152        TokenType.OBJECT,
 153        TokenType.STRUCT,
 154    }
 155
 156    NESTED_TYPE_TOKENS = {
 157        TokenType.ARRAY,
 158        TokenType.LOWCARDINALITY,
 159        TokenType.MAP,
 160        TokenType.NULLABLE,
 161        *STRUCT_TYPE_TOKENS,
 162    }
 163
 164    ENUM_TYPE_TOKENS = {
 165        TokenType.ENUM,
 166        TokenType.ENUM8,
 167        TokenType.ENUM16,
 168    }
 169
 170    AGGREGATE_TYPE_TOKENS = {
 171        TokenType.AGGREGATEFUNCTION,
 172        TokenType.SIMPLEAGGREGATEFUNCTION,
 173    }
 174
 175    TYPE_TOKENS = {
 176        TokenType.BIT,
 177        TokenType.BOOLEAN,
 178        TokenType.TINYINT,
 179        TokenType.UTINYINT,
 180        TokenType.SMALLINT,
 181        TokenType.USMALLINT,
 182        TokenType.INT,
 183        TokenType.UINT,
 184        TokenType.BIGINT,
 185        TokenType.UBIGINT,
 186        TokenType.INT128,
 187        TokenType.UINT128,
 188        TokenType.INT256,
 189        TokenType.UINT256,
 190        TokenType.MEDIUMINT,
 191        TokenType.UMEDIUMINT,
 192        TokenType.FIXEDSTRING,
 193        TokenType.FLOAT,
 194        TokenType.DOUBLE,
 195        TokenType.CHAR,
 196        TokenType.NCHAR,
 197        TokenType.VARCHAR,
 198        TokenType.NVARCHAR,
 199        TokenType.BPCHAR,
 200        TokenType.TEXT,
 201        TokenType.MEDIUMTEXT,
 202        TokenType.LONGTEXT,
 203        TokenType.MEDIUMBLOB,
 204        TokenType.LONGBLOB,
 205        TokenType.BINARY,
 206        TokenType.VARBINARY,
 207        TokenType.JSON,
 208        TokenType.JSONB,
 209        TokenType.INTERVAL,
 210        TokenType.TINYBLOB,
 211        TokenType.TINYTEXT,
 212        TokenType.TIME,
 213        TokenType.TIMETZ,
 214        TokenType.TIMESTAMP,
 215        TokenType.TIMESTAMP_S,
 216        TokenType.TIMESTAMP_MS,
 217        TokenType.TIMESTAMP_NS,
 218        TokenType.TIMESTAMPTZ,
 219        TokenType.TIMESTAMPLTZ,
 220        TokenType.TIMESTAMPNTZ,
 221        TokenType.DATETIME,
 222        TokenType.DATETIME64,
 223        TokenType.DATE,
 224        TokenType.DATE32,
 225        TokenType.INT4RANGE,
 226        TokenType.INT4MULTIRANGE,
 227        TokenType.INT8RANGE,
 228        TokenType.INT8MULTIRANGE,
 229        TokenType.NUMRANGE,
 230        TokenType.NUMMULTIRANGE,
 231        TokenType.TSRANGE,
 232        TokenType.TSMULTIRANGE,
 233        TokenType.TSTZRANGE,
 234        TokenType.TSTZMULTIRANGE,
 235        TokenType.DATERANGE,
 236        TokenType.DATEMULTIRANGE,
 237        TokenType.DECIMAL,
 238        TokenType.UDECIMAL,
 239        TokenType.BIGDECIMAL,
 240        TokenType.UUID,
 241        TokenType.GEOGRAPHY,
 242        TokenType.GEOMETRY,
 243        TokenType.HLLSKETCH,
 244        TokenType.HSTORE,
 245        TokenType.PSEUDO_TYPE,
 246        TokenType.SUPER,
 247        TokenType.SERIAL,
 248        TokenType.SMALLSERIAL,
 249        TokenType.BIGSERIAL,
 250        TokenType.XML,
 251        TokenType.YEAR,
 252        TokenType.UNIQUEIDENTIFIER,
 253        TokenType.USERDEFINED,
 254        TokenType.MONEY,
 255        TokenType.SMALLMONEY,
 256        TokenType.ROWVERSION,
 257        TokenType.IMAGE,
 258        TokenType.VARIANT,
 259        TokenType.OBJECT,
 260        TokenType.OBJECT_IDENTIFIER,
 261        TokenType.INET,
 262        TokenType.IPADDRESS,
 263        TokenType.IPPREFIX,
 264        TokenType.IPV4,
 265        TokenType.IPV6,
 266        TokenType.UNKNOWN,
 267        TokenType.NULL,
 268        TokenType.NAME,
 269        TokenType.TDIGEST,
 270        *ENUM_TYPE_TOKENS,
 271        *NESTED_TYPE_TOKENS,
 272        *AGGREGATE_TYPE_TOKENS,
 273    }
 274
 275    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 276        TokenType.BIGINT: TokenType.UBIGINT,
 277        TokenType.INT: TokenType.UINT,
 278        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 279        TokenType.SMALLINT: TokenType.USMALLINT,
 280        TokenType.TINYINT: TokenType.UTINYINT,
 281        TokenType.DECIMAL: TokenType.UDECIMAL,
 282    }
 283
 284    SUBQUERY_PREDICATES = {
 285        TokenType.ANY: exp.Any,
 286        TokenType.ALL: exp.All,
 287        TokenType.EXISTS: exp.Exists,
 288        TokenType.SOME: exp.Any,
 289    }
 290
 291    RESERVED_TOKENS = {
 292        *Tokenizer.SINGLE_TOKENS.values(),
 293        TokenType.SELECT,
 294    } - {TokenType.IDENTIFIER}
 295
 296    DB_CREATABLES = {
 297        TokenType.DATABASE,
 298        TokenType.SCHEMA,
 299        TokenType.TABLE,
 300        TokenType.VIEW,
 301        TokenType.MODEL,
 302        TokenType.DICTIONARY,
 303        TokenType.SEQUENCE,
 304        TokenType.STORAGE_INTEGRATION,
 305    }
 306
 307    CREATABLES = {
 308        TokenType.COLUMN,
 309        TokenType.CONSTRAINT,
 310        TokenType.FUNCTION,
 311        TokenType.INDEX,
 312        TokenType.PROCEDURE,
 313        TokenType.FOREIGN_KEY,
 314        *DB_CREATABLES,
 315    }
 316
 317    # Tokens that can represent identifiers
 318    ID_VAR_TOKENS = {
 319        TokenType.VAR,
 320        TokenType.ANTI,
 321        TokenType.APPLY,
 322        TokenType.ASC,
 323        TokenType.ASOF,
 324        TokenType.AUTO_INCREMENT,
 325        TokenType.BEGIN,
 326        TokenType.BPCHAR,
 327        TokenType.CACHE,
 328        TokenType.CASE,
 329        TokenType.COLLATE,
 330        TokenType.COMMAND,
 331        TokenType.COMMENT,
 332        TokenType.COMMIT,
 333        TokenType.CONSTRAINT,
 334        TokenType.COPY,
 335        TokenType.DEFAULT,
 336        TokenType.DELETE,
 337        TokenType.DESC,
 338        TokenType.DESCRIBE,
 339        TokenType.DICTIONARY,
 340        TokenType.DIV,
 341        TokenType.END,
 342        TokenType.EXECUTE,
 343        TokenType.ESCAPE,
 344        TokenType.FALSE,
 345        TokenType.FIRST,
 346        TokenType.FILTER,
 347        TokenType.FINAL,
 348        TokenType.FORMAT,
 349        TokenType.FULL,
 350        TokenType.IDENTIFIER,
 351        TokenType.IS,
 352        TokenType.ISNULL,
 353        TokenType.INTERVAL,
 354        TokenType.KEEP,
 355        TokenType.KILL,
 356        TokenType.LEFT,
 357        TokenType.LOAD,
 358        TokenType.MERGE,
 359        TokenType.NATURAL,
 360        TokenType.NEXT,
 361        TokenType.OFFSET,
 362        TokenType.OPERATOR,
 363        TokenType.ORDINALITY,
 364        TokenType.OVERLAPS,
 365        TokenType.OVERWRITE,
 366        TokenType.PARTITION,
 367        TokenType.PERCENT,
 368        TokenType.PIVOT,
 369        TokenType.PRAGMA,
 370        TokenType.RANGE,
 371        TokenType.RECURSIVE,
 372        TokenType.REFERENCES,
 373        TokenType.REFRESH,
 374        TokenType.REPLACE,
 375        TokenType.RIGHT,
 376        TokenType.ROW,
 377        TokenType.ROWS,
 378        TokenType.SEMI,
 379        TokenType.SET,
 380        TokenType.SETTINGS,
 381        TokenType.SHOW,
 382        TokenType.TEMPORARY,
 383        TokenType.TOP,
 384        TokenType.TRUE,
 385        TokenType.TRUNCATE,
 386        TokenType.UNIQUE,
 387        TokenType.UNPIVOT,
 388        TokenType.UPDATE,
 389        TokenType.USE,
 390        TokenType.VOLATILE,
 391        TokenType.WINDOW,
 392        *CREATABLES,
 393        *SUBQUERY_PREDICATES,
 394        *TYPE_TOKENS,
 395        *NO_PAREN_FUNCTIONS,
 396    }
 397
 398    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 399
 400    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 401        TokenType.ANTI,
 402        TokenType.APPLY,
 403        TokenType.ASOF,
 404        TokenType.FULL,
 405        TokenType.LEFT,
 406        TokenType.LOCK,
 407        TokenType.NATURAL,
 408        TokenType.OFFSET,
 409        TokenType.RIGHT,
 410        TokenType.SEMI,
 411        TokenType.WINDOW,
 412    }
 413
 414    ALIAS_TOKENS = ID_VAR_TOKENS
 415
 416    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 417
 418    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 419
 420    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 421
 422    FUNC_TOKENS = {
 423        TokenType.COLLATE,
 424        TokenType.COMMAND,
 425        TokenType.CURRENT_DATE,
 426        TokenType.CURRENT_DATETIME,
 427        TokenType.CURRENT_TIMESTAMP,
 428        TokenType.CURRENT_TIME,
 429        TokenType.CURRENT_USER,
 430        TokenType.FILTER,
 431        TokenType.FIRST,
 432        TokenType.FORMAT,
 433        TokenType.GLOB,
 434        TokenType.IDENTIFIER,
 435        TokenType.INDEX,
 436        TokenType.ISNULL,
 437        TokenType.ILIKE,
 438        TokenType.INSERT,
 439        TokenType.LIKE,
 440        TokenType.MERGE,
 441        TokenType.OFFSET,
 442        TokenType.PRIMARY_KEY,
 443        TokenType.RANGE,
 444        TokenType.REPLACE,
 445        TokenType.RLIKE,
 446        TokenType.ROW,
 447        TokenType.UNNEST,
 448        TokenType.VAR,
 449        TokenType.LEFT,
 450        TokenType.RIGHT,
 451        TokenType.SEQUENCE,
 452        TokenType.DATE,
 453        TokenType.DATETIME,
 454        TokenType.TABLE,
 455        TokenType.TIMESTAMP,
 456        TokenType.TIMESTAMPTZ,
 457        TokenType.TRUNCATE,
 458        TokenType.WINDOW,
 459        TokenType.XOR,
 460        *TYPE_TOKENS,
 461        *SUBQUERY_PREDICATES,
 462    }
 463
 464    CONJUNCTION = {
 465        TokenType.AND: exp.And,
 466        TokenType.OR: exp.Or,
 467    }
 468
 469    EQUALITY = {
 470        TokenType.COLON_EQ: exp.PropertyEQ,
 471        TokenType.EQ: exp.EQ,
 472        TokenType.NEQ: exp.NEQ,
 473        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 474    }
 475
 476    COMPARISON = {
 477        TokenType.GT: exp.GT,
 478        TokenType.GTE: exp.GTE,
 479        TokenType.LT: exp.LT,
 480        TokenType.LTE: exp.LTE,
 481    }
 482
 483    BITWISE = {
 484        TokenType.AMP: exp.BitwiseAnd,
 485        TokenType.CARET: exp.BitwiseXor,
 486        TokenType.PIPE: exp.BitwiseOr,
 487    }
 488
 489    TERM = {
 490        TokenType.DASH: exp.Sub,
 491        TokenType.PLUS: exp.Add,
 492        TokenType.MOD: exp.Mod,
 493        TokenType.COLLATE: exp.Collate,
 494    }
 495
 496    FACTOR = {
 497        TokenType.DIV: exp.IntDiv,
 498        TokenType.LR_ARROW: exp.Distance,
 499        TokenType.SLASH: exp.Div,
 500        TokenType.STAR: exp.Mul,
 501    }
 502
 503    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 504
 505    TIMES = {
 506        TokenType.TIME,
 507        TokenType.TIMETZ,
 508    }
 509
 510    TIMESTAMPS = {
 511        TokenType.TIMESTAMP,
 512        TokenType.TIMESTAMPTZ,
 513        TokenType.TIMESTAMPLTZ,
 514        *TIMES,
 515    }
 516
 517    SET_OPERATIONS = {
 518        TokenType.UNION,
 519        TokenType.INTERSECT,
 520        TokenType.EXCEPT,
 521    }
 522
 523    JOIN_METHODS = {
 524        TokenType.ASOF,
 525        TokenType.NATURAL,
 526        TokenType.POSITIONAL,
 527    }
 528
 529    JOIN_SIDES = {
 530        TokenType.LEFT,
 531        TokenType.RIGHT,
 532        TokenType.FULL,
 533    }
 534
 535    JOIN_KINDS = {
 536        TokenType.INNER,
 537        TokenType.OUTER,
 538        TokenType.CROSS,
 539        TokenType.SEMI,
 540        TokenType.ANTI,
 541    }
 542
 543    JOIN_HINTS: t.Set[str] = set()
 544
 545    LAMBDAS = {
 546        TokenType.ARROW: lambda self, expressions: self.expression(
 547            exp.Lambda,
 548            this=self._replace_lambda(
 549                self._parse_conjunction(),
 550                {node.name for node in expressions},
 551            ),
 552            expressions=expressions,
 553        ),
 554        TokenType.FARROW: lambda self, expressions: self.expression(
 555            exp.Kwarg,
 556            this=exp.var(expressions[0].name),
 557            expression=self._parse_conjunction(),
 558        ),
 559    }
 560
 561    COLUMN_OPERATORS = {
 562        TokenType.DOT: None,
 563        TokenType.DCOLON: lambda self, this, to: self.expression(
 564            exp.Cast if self.STRICT_CAST else exp.TryCast,
 565            this=this,
 566            to=to,
 567        ),
 568        TokenType.ARROW: lambda self, this, path: self.expression(
 569            exp.JSONExtract,
 570            this=this,
 571            expression=self.dialect.to_json_path(path),
 572            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 573        ),
 574        TokenType.DARROW: lambda self, this, path: self.expression(
 575            exp.JSONExtractScalar,
 576            this=this,
 577            expression=self.dialect.to_json_path(path),
 578            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 579        ),
 580        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 581            exp.JSONBExtract,
 582            this=this,
 583            expression=path,
 584        ),
 585        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 586            exp.JSONBExtractScalar,
 587            this=this,
 588            expression=path,
 589        ),
 590        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 591            exp.JSONBContains,
 592            this=this,
 593            expression=key,
 594        ),
 595    }
 596
 597    EXPRESSION_PARSERS = {
 598        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 599        exp.Column: lambda self: self._parse_column(),
 600        exp.Condition: lambda self: self._parse_conjunction(),
 601        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 602        exp.Expression: lambda self: self._parse_expression(),
 603        exp.From: lambda self: self._parse_from(joins=True),
 604        exp.Group: lambda self: self._parse_group(),
 605        exp.Having: lambda self: self._parse_having(),
 606        exp.Identifier: lambda self: self._parse_id_var(),
 607        exp.Join: lambda self: self._parse_join(),
 608        exp.Lambda: lambda self: self._parse_lambda(),
 609        exp.Lateral: lambda self: self._parse_lateral(),
 610        exp.Limit: lambda self: self._parse_limit(),
 611        exp.Offset: lambda self: self._parse_offset(),
 612        exp.Order: lambda self: self._parse_order(),
 613        exp.Ordered: lambda self: self._parse_ordered(),
 614        exp.Properties: lambda self: self._parse_properties(),
 615        exp.Qualify: lambda self: self._parse_qualify(),
 616        exp.Returning: lambda self: self._parse_returning(),
 617        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 618        exp.Table: lambda self: self._parse_table_parts(),
 619        exp.TableAlias: lambda self: self._parse_table_alias(),
 620        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 621        exp.Where: lambda self: self._parse_where(),
 622        exp.Window: lambda self: self._parse_named_window(),
 623        exp.With: lambda self: self._parse_with(),
 624        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 625    }
 626
 627    STATEMENT_PARSERS = {
 628        TokenType.ALTER: lambda self: self._parse_alter(),
 629        TokenType.BEGIN: lambda self: self._parse_transaction(),
 630        TokenType.CACHE: lambda self: self._parse_cache(),
 631        TokenType.COMMENT: lambda self: self._parse_comment(),
 632        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 633        TokenType.COPY: lambda self: self._parse_copy(),
 634        TokenType.CREATE: lambda self: self._parse_create(),
 635        TokenType.DELETE: lambda self: self._parse_delete(),
 636        TokenType.DESC: lambda self: self._parse_describe(),
 637        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 638        TokenType.DROP: lambda self: self._parse_drop(),
 639        TokenType.INSERT: lambda self: self._parse_insert(),
 640        TokenType.KILL: lambda self: self._parse_kill(),
 641        TokenType.LOAD: lambda self: self._parse_load(),
 642        TokenType.MERGE: lambda self: self._parse_merge(),
 643        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 644        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 645        TokenType.REFRESH: lambda self: self._parse_refresh(),
 646        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 647        TokenType.SET: lambda self: self._parse_set(),
 648        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 649        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 650        TokenType.UPDATE: lambda self: self._parse_update(),
 651        TokenType.USE: lambda self: self.expression(
 652            exp.Use,
 653            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 654            this=self._parse_table(schema=False),
 655        ),
 656    }
 657
 658    UNARY_PARSERS = {
 659        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 660        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 661        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 662        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 663        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 664        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 665    }
 666
 667    STRING_PARSERS = {
 668        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 669            exp.RawString, this=token.text
 670        ),
 671        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 672            exp.National, this=token.text
 673        ),
 674        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 675        TokenType.STRING: lambda self, token: self.expression(
 676            exp.Literal, this=token.text, is_string=True
 677        ),
 678        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 679            exp.UnicodeString,
 680            this=token.text,
 681            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 682        ),
 683    }
 684
 685    NUMERIC_PARSERS = {
 686        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 687        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 688        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 689        TokenType.NUMBER: lambda self, token: self.expression(
 690            exp.Literal, this=token.text, is_string=False
 691        ),
 692    }
 693
 694    PRIMARY_PARSERS = {
 695        **STRING_PARSERS,
 696        **NUMERIC_PARSERS,
 697        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 698        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 699        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 700        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 701        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 702        TokenType.STAR: lambda self, _: self.expression(
 703            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 704        ),
 705    }
 706
 707    PLACEHOLDER_PARSERS = {
 708        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 709        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 710        TokenType.COLON: lambda self: (
 711            self.expression(exp.Placeholder, this=self._prev.text)
 712            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 713            else None
 714        ),
 715    }
 716
 717    RANGE_PARSERS = {
 718        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 719        TokenType.GLOB: binary_range_parser(exp.Glob),
 720        TokenType.ILIKE: binary_range_parser(exp.ILike),
 721        TokenType.IN: lambda self, this: self._parse_in(this),
 722        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 723        TokenType.IS: lambda self, this: self._parse_is(this),
 724        TokenType.LIKE: binary_range_parser(exp.Like),
 725        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 726        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 727        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 728        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 729    }
 730
 731    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 732        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 733        "AUTO": lambda self: self._parse_auto_property(),
 734        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 735        "BACKUP": lambda self: self.expression(
 736            exp.BackupProperty, this=self._parse_var(any_token=True)
 737        ),
 738        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 739        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 740        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 741        "CHECKSUM": lambda self: self._parse_checksum(),
 742        "CLUSTER BY": lambda self: self._parse_cluster(),
 743        "CLUSTERED": lambda self: self._parse_clustered_by(),
 744        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 745            exp.CollateProperty, **kwargs
 746        ),
 747        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 748        "CONTAINS": lambda self: self._parse_contains_property(),
 749        "COPY": lambda self: self._parse_copy_property(),
 750        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 751        "DEFINER": lambda self: self._parse_definer(),
 752        "DETERMINISTIC": lambda self: self.expression(
 753            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 754        ),
 755        "DISTKEY": lambda self: self._parse_distkey(),
 756        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 757        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 758        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 759        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 760        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 761        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 762        "FREESPACE": lambda self: self._parse_freespace(),
 763        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 764        "HEAP": lambda self: self.expression(exp.HeapProperty),
 765        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 766        "IMMUTABLE": lambda self: self.expression(
 767            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 768        ),
 769        "INHERITS": lambda self: self.expression(
 770            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 771        ),
 772        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 773        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 774        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 775        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 776        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 777        "LIKE": lambda self: self._parse_create_like(),
 778        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 779        "LOCK": lambda self: self._parse_locking(),
 780        "LOCKING": lambda self: self._parse_locking(),
 781        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 782        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 783        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 784        "MODIFIES": lambda self: self._parse_modifies_property(),
 785        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 786        "NO": lambda self: self._parse_no_property(),
 787        "ON": lambda self: self._parse_on_property(),
 788        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 789        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 790        "PARTITION": lambda self: self._parse_partitioned_of(),
 791        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 792        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 793        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 794        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 795        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 796        "READS": lambda self: self._parse_reads_property(),
 797        "REMOTE": lambda self: self._parse_remote_with_connection(),
 798        "RETURNS": lambda self: self._parse_returns(),
 799        "ROW": lambda self: self._parse_row(),
 800        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 801        "SAMPLE": lambda self: self.expression(
 802            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 803        ),
 804        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 805        "SETTINGS": lambda self: self.expression(
 806            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 807        ),
 808        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 809        "SORTKEY": lambda self: self._parse_sortkey(),
 810        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 811        "STABLE": lambda self: self.expression(
 812            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 813        ),
 814        "STORED": lambda self: self._parse_stored(),
 815        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 816        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 817        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 818        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 819        "TO": lambda self: self._parse_to_table(),
 820        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 821        "TRANSFORM": lambda self: self.expression(
 822            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 823        ),
 824        "TTL": lambda self: self._parse_ttl(),
 825        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 826        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 827        "VOLATILE": lambda self: self._parse_volatile_property(),
 828        "WITH": lambda self: self._parse_with_property(),
 829    }
 830
 831    CONSTRAINT_PARSERS = {
 832        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 833        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 834        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 835        "CHARACTER SET": lambda self: self.expression(
 836            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 837        ),
 838        "CHECK": lambda self: self.expression(
 839            exp.CheckColumnConstraint,
 840            this=self._parse_wrapped(self._parse_conjunction),
 841            enforced=self._match_text_seq("ENFORCED"),
 842        ),
 843        "COLLATE": lambda self: self.expression(
 844            exp.CollateColumnConstraint, this=self._parse_var()
 845        ),
 846        "COMMENT": lambda self: self.expression(
 847            exp.CommentColumnConstraint, this=self._parse_string()
 848        ),
 849        "COMPRESS": lambda self: self._parse_compress(),
 850        "CLUSTERED": lambda self: self.expression(
 851            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 852        ),
 853        "NONCLUSTERED": lambda self: self.expression(
 854            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 855        ),
 856        "DEFAULT": lambda self: self.expression(
 857            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 858        ),
 859        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 860        "EPHEMERAL": lambda self: self.expression(
 861            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 862        ),
 863        "EXCLUDE": lambda self: self.expression(
 864            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 865        ),
 866        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 867        "FORMAT": lambda self: self.expression(
 868            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 869        ),
 870        "GENERATED": lambda self: self._parse_generated_as_identity(),
 871        "IDENTITY": lambda self: self._parse_auto_increment(),
 872        "INLINE": lambda self: self._parse_inline(),
 873        "LIKE": lambda self: self._parse_create_like(),
 874        "NOT": lambda self: self._parse_not_constraint(),
 875        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 876        "ON": lambda self: (
 877            self._match(TokenType.UPDATE)
 878            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 879        )
 880        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 881        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 882        "PERIOD": lambda self: self._parse_period_for_system_time(),
 883        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 884        "REFERENCES": lambda self: self._parse_references(match=False),
 885        "TITLE": lambda self: self.expression(
 886            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 887        ),
 888        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 889        "UNIQUE": lambda self: self._parse_unique(),
 890        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 891        "WITH": lambda self: self.expression(
 892            exp.Properties, expressions=self._parse_wrapped_properties()
 893        ),
 894    }
 895
 896    ALTER_PARSERS = {
 897        "ADD": lambda self: self._parse_alter_table_add(),
 898        "ALTER": lambda self: self._parse_alter_table_alter(),
 899        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 900        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 901        "DROP": lambda self: self._parse_alter_table_drop(),
 902        "RENAME": lambda self: self._parse_alter_table_rename(),
 903    }
 904
 905    SCHEMA_UNNAMED_CONSTRAINTS = {
 906        "CHECK",
 907        "EXCLUDE",
 908        "FOREIGN KEY",
 909        "LIKE",
 910        "PERIOD",
 911        "PRIMARY KEY",
 912        "UNIQUE",
 913    }
 914
 915    NO_PAREN_FUNCTION_PARSERS = {
 916        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 917        "CASE": lambda self: self._parse_case(),
 918        "IF": lambda self: self._parse_if(),
 919        "NEXT": lambda self: self._parse_next_value_for(),
 920    }
 921
 922    INVALID_FUNC_NAME_TOKENS = {
 923        TokenType.IDENTIFIER,
 924        TokenType.STRING,
 925    }
 926
 927    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 928
 929    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
 930
 931    FUNCTION_PARSERS = {
 932        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 933        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 934        "DECODE": lambda self: self._parse_decode(),
 935        "EXTRACT": lambda self: self._parse_extract(),
 936        "JSON_OBJECT": lambda self: self._parse_json_object(),
 937        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 938        "JSON_TABLE": lambda self: self._parse_json_table(),
 939        "MATCH": lambda self: self._parse_match_against(),
 940        "OPENJSON": lambda self: self._parse_open_json(),
 941        "POSITION": lambda self: self._parse_position(),
 942        "PREDICT": lambda self: self._parse_predict(),
 943        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 944        "STRING_AGG": lambda self: self._parse_string_agg(),
 945        "SUBSTRING": lambda self: self._parse_substring(),
 946        "TRIM": lambda self: self._parse_trim(),
 947        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 948        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 949    }
 950
 951    QUERY_MODIFIER_PARSERS = {
 952        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 953        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
 954        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 955        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 956        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 957        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 958        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 959        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 960        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 961        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 962        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 963        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 964        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 965        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 966        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 967        TokenType.CLUSTER_BY: lambda self: (
 968            "cluster",
 969            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 970        ),
 971        TokenType.DISTRIBUTE_BY: lambda self: (
 972            "distribute",
 973            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 974        ),
 975        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 976        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 977        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 978    }
 979
 980    SET_PARSERS = {
 981        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 982        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 983        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 984        "TRANSACTION": lambda self: self._parse_set_transaction(),
 985    }
 986
 987    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 988
 989    TYPE_LITERAL_PARSERS = {
 990        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 991    }
 992
 993    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 994
 995    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 996
 997    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 998    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
 999        "ISOLATION": (
1000            ("LEVEL", "REPEATABLE", "READ"),
1001            ("LEVEL", "READ", "COMMITTED"),
1002            ("LEVEL", "READ", "UNCOMITTED"),
1003            ("LEVEL", "SERIALIZABLE"),
1004        ),
1005        "READ": ("WRITE", "ONLY"),
1006    }
1007
1008    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1009        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1010    )
1011    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1012
1013    CREATE_SEQUENCE: OPTIONS_TYPE = {
1014        "SCALE": ("EXTEND", "NOEXTEND"),
1015        "SHARD": ("EXTEND", "NOEXTEND"),
1016        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1017        **dict.fromkeys(
1018            (
1019                "SESSION",
1020                "GLOBAL",
1021                "KEEP",
1022                "NOKEEP",
1023                "ORDER",
1024                "NOORDER",
1025                "NOCACHE",
1026                "CYCLE",
1027                "NOCYCLE",
1028                "NOMINVALUE",
1029                "NOMAXVALUE",
1030                "NOSCALE",
1031                "NOSHARD",
1032            ),
1033            tuple(),
1034        ),
1035    }
1036
1037    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1038
1039    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
1040
1041    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1042
1043    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1044
1045    CLONE_KEYWORDS = {"CLONE", "COPY"}
1046    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1047
1048    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1049
1050    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1051
1052    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1053
1054    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1055
1056    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1057    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1058    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1059
1060    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1061
1062    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1063
1064    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
1065
1066    DISTINCT_TOKENS = {TokenType.DISTINCT}
1067
1068    NULL_TOKENS = {TokenType.NULL}
1069
1070    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1071
1072    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1073
1074    STRICT_CAST = True
1075
1076    PREFIXED_PIVOT_COLUMNS = False
1077    IDENTIFY_PIVOT_STRINGS = False
1078
1079    LOG_DEFAULTS_TO_LN = False
1080
1081    # Whether ADD is present for each column added by ALTER TABLE
1082    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1083
1084    # Whether the table sample clause expects CSV syntax
1085    TABLESAMPLE_CSV = False
1086
1087    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1088    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1089
1090    # Whether the TRIM function expects the characters to trim as its first argument
1091    TRIM_PATTERN_FIRST = False
1092
1093    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1094    STRING_ALIASES = False
1095
1096    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1097    MODIFIERS_ATTACHED_TO_UNION = True
1098    UNION_MODIFIERS = {"order", "limit", "offset"}
1099
1100    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1101    NO_PAREN_IF_COMMANDS = True
1102
1103    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1104    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1105
1106    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1107    # If this is True and '(' is not found, the keyword will be treated as an identifier
1108    VALUES_FOLLOWED_BY_PAREN = True
1109
1110    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1111    SUPPORTS_IMPLICIT_UNNEST = False
1112
1113    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1114    INTERVAL_SPANS = True
1115
1116    # Whether a PARTITION clause can follow a table reference
1117    SUPPORTS_PARTITION_SELECTION = False
1118
1119    __slots__ = (
1120        "error_level",
1121        "error_message_context",
1122        "max_errors",
1123        "dialect",
1124        "sql",
1125        "errors",
1126        "_tokens",
1127        "_index",
1128        "_curr",
1129        "_next",
1130        "_prev",
1131        "_prev_comments",
1132    )
1133
1134    # Autofilled
1135    SHOW_TRIE: t.Dict = {}
1136    SET_TRIE: t.Dict = {}
1137
1138    def __init__(
1139        self,
1140        error_level: t.Optional[ErrorLevel] = None,
1141        error_message_context: int = 100,
1142        max_errors: int = 3,
1143        dialect: DialectType = None,
1144    ):
1145        from sqlglot.dialects import Dialect
1146
1147        self.error_level = error_level or ErrorLevel.IMMEDIATE
1148        self.error_message_context = error_message_context
1149        self.max_errors = max_errors
1150        self.dialect = Dialect.get_or_raise(dialect)
1151        self.reset()
1152
1153    def reset(self):
1154        self.sql = ""
1155        self.errors = []
1156        self._tokens = []
1157        self._index = 0
1158        self._curr = None
1159        self._next = None
1160        self._prev = None
1161        self._prev_comments = None
1162
1163    def parse(
1164        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1165    ) -> t.List[t.Optional[exp.Expression]]:
1166        """
1167        Parses a list of tokens and returns a list of syntax trees, one tree
1168        per parsed SQL statement.
1169
1170        Args:
1171            raw_tokens: The list of tokens.
1172            sql: The original SQL string, used to produce helpful debug messages.
1173
1174        Returns:
1175            The list of the produced syntax trees.
1176        """
1177        return self._parse(
1178            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1179        )
1180
1181    def parse_into(
1182        self,
1183        expression_types: exp.IntoType,
1184        raw_tokens: t.List[Token],
1185        sql: t.Optional[str] = None,
1186    ) -> t.List[t.Optional[exp.Expression]]:
1187        """
1188        Parses a list of tokens into a given Expression type. If a collection of Expression
1189        types is given instead, this method will try to parse the token list into each one
1190        of them, stopping at the first for which the parsing succeeds.
1191
1192        Args:
1193            expression_types: The expression type(s) to try and parse the token list into.
1194            raw_tokens: The list of tokens.
1195            sql: The original SQL string, used to produce helpful debug messages.
1196
1197        Returns:
1198            The target Expression.
1199        """
1200        errors = []
1201        for expression_type in ensure_list(expression_types):
1202            parser = self.EXPRESSION_PARSERS.get(expression_type)
1203            if not parser:
1204                raise TypeError(f"No parser registered for {expression_type}")
1205
1206            try:
1207                return self._parse(parser, raw_tokens, sql)
1208            except ParseError as e:
1209                e.errors[0]["into_expression"] = expression_type
1210                errors.append(e)
1211
1212        raise ParseError(
1213            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1214            errors=merge_errors(errors),
1215        ) from errors[-1]
1216
1217    def _parse(
1218        self,
1219        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1220        raw_tokens: t.List[Token],
1221        sql: t.Optional[str] = None,
1222    ) -> t.List[t.Optional[exp.Expression]]:
1223        self.reset()
1224        self.sql = sql or ""
1225
1226        total = len(raw_tokens)
1227        chunks: t.List[t.List[Token]] = [[]]
1228
1229        for i, token in enumerate(raw_tokens):
1230            if token.token_type == TokenType.SEMICOLON:
1231                if i < total - 1:
1232                    chunks.append([])
1233            else:
1234                chunks[-1].append(token)
1235
1236        expressions = []
1237
1238        for tokens in chunks:
1239            self._index = -1
1240            self._tokens = tokens
1241            self._advance()
1242
1243            expressions.append(parse_method(self))
1244
1245            if self._index < len(self._tokens):
1246                self.raise_error("Invalid expression / Unexpected token")
1247
1248            self.check_errors()
1249
1250        return expressions
1251
1252    def check_errors(self) -> None:
1253        """Logs or raises any found errors, depending on the chosen error level setting."""
1254        if self.error_level == ErrorLevel.WARN:
1255            for error in self.errors:
1256                logger.error(str(error))
1257        elif self.error_level == ErrorLevel.RAISE and self.errors:
1258            raise ParseError(
1259                concat_messages(self.errors, self.max_errors),
1260                errors=merge_errors(self.errors),
1261            )
1262
1263    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1264        """
1265        Appends an error in the list of recorded errors or raises it, depending on the chosen
1266        error level setting.
1267        """
1268        token = token or self._curr or self._prev or Token.string("")
1269        start = token.start
1270        end = token.end + 1
1271        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1272        highlight = self.sql[start:end]
1273        end_context = self.sql[end : end + self.error_message_context]
1274
1275        error = ParseError.new(
1276            f"{message}. Line {token.line}, Col: {token.col}.\n"
1277            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1278            description=message,
1279            line=token.line,
1280            col=token.col,
1281            start_context=start_context,
1282            highlight=highlight,
1283            end_context=end_context,
1284        )
1285
1286        if self.error_level == ErrorLevel.IMMEDIATE:
1287            raise error
1288
1289        self.errors.append(error)
1290
1291    def expression(
1292        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1293    ) -> E:
1294        """
1295        Creates a new, validated Expression.
1296
1297        Args:
1298            exp_class: The expression class to instantiate.
1299            comments: An optional list of comments to attach to the expression.
1300            kwargs: The arguments to set for the expression along with their respective values.
1301
1302        Returns:
1303            The target expression.
1304        """
1305        instance = exp_class(**kwargs)
1306        instance.add_comments(comments) if comments else self._add_comments(instance)
1307        return self.validate_expression(instance)
1308
1309    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1310        if expression and self._prev_comments:
1311            expression.add_comments(self._prev_comments)
1312            self._prev_comments = None
1313
1314    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1315        """
1316        Validates an Expression, making sure that all its mandatory arguments are set.
1317
1318        Args:
1319            expression: The expression to validate.
1320            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1321
1322        Returns:
1323            The validated expression.
1324        """
1325        if self.error_level != ErrorLevel.IGNORE:
1326            for error_message in expression.error_messages(args):
1327                self.raise_error(error_message)
1328
1329        return expression
1330
1331    def _find_sql(self, start: Token, end: Token) -> str:
1332        return self.sql[start.start : end.end + 1]
1333
1334    def _is_connected(self) -> bool:
1335        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1336
1337    def _advance(self, times: int = 1) -> None:
1338        self._index += times
1339        self._curr = seq_get(self._tokens, self._index)
1340        self._next = seq_get(self._tokens, self._index + 1)
1341
1342        if self._index > 0:
1343            self._prev = self._tokens[self._index - 1]
1344            self._prev_comments = self._prev.comments
1345        else:
1346            self._prev = None
1347            self._prev_comments = None
1348
1349    def _retreat(self, index: int) -> None:
1350        if index != self._index:
1351            self._advance(index - self._index)
1352
1353    def _warn_unsupported(self) -> None:
1354        if len(self._tokens) <= 1:
1355            return
1356
1357        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1358        # interested in emitting a warning for the one being currently processed.
1359        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1360
1361        logger.warning(
1362            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1363        )
1364
1365    def _parse_command(self) -> exp.Command:
1366        self._warn_unsupported()
1367        return self.expression(
1368            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1369        )
1370
1371    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1372        """
1373        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
1374        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
1375        the parser state accordingly
1376        """
1377        index = self._index
1378        error_level = self.error_level
1379
1380        self.error_level = ErrorLevel.IMMEDIATE
1381        try:
1382            this = parse_method()
1383        except ParseError:
1384            this = None
1385        finally:
1386            if not this or retreat:
1387                self._retreat(index)
1388            self.error_level = error_level
1389
1390        return this
1391
1392    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1393        start = self._prev
1394        exists = self._parse_exists() if allow_exists else None
1395
1396        self._match(TokenType.ON)
1397
1398        materialized = self._match_text_seq("MATERIALIZED")
1399        kind = self._match_set(self.CREATABLES) and self._prev
1400        if not kind:
1401            return self._parse_as_command(start)
1402
1403        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1404            this = self._parse_user_defined_function(kind=kind.token_type)
1405        elif kind.token_type == TokenType.TABLE:
1406            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1407        elif kind.token_type == TokenType.COLUMN:
1408            this = self._parse_column()
1409        else:
1410            this = self._parse_id_var()
1411
1412        self._match(TokenType.IS)
1413
1414        return self.expression(
1415            exp.Comment,
1416            this=this,
1417            kind=kind.text,
1418            expression=self._parse_string(),
1419            exists=exists,
1420            materialized=materialized,
1421        )
1422
1423    def _parse_to_table(
1424        self,
1425    ) -> exp.ToTableProperty:
1426        table = self._parse_table_parts(schema=True)
1427        return self.expression(exp.ToTableProperty, this=table)
1428
1429    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1430    def _parse_ttl(self) -> exp.Expression:
1431        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1432            this = self._parse_bitwise()
1433
1434            if self._match_text_seq("DELETE"):
1435                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1436            if self._match_text_seq("RECOMPRESS"):
1437                return self.expression(
1438                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1439                )
1440            if self._match_text_seq("TO", "DISK"):
1441                return self.expression(
1442                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1443                )
1444            if self._match_text_seq("TO", "VOLUME"):
1445                return self.expression(
1446                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1447                )
1448
1449            return this
1450
1451        expressions = self._parse_csv(_parse_ttl_action)
1452        where = self._parse_where()
1453        group = self._parse_group()
1454
1455        aggregates = None
1456        if group and self._match(TokenType.SET):
1457            aggregates = self._parse_csv(self._parse_set_item)
1458
1459        return self.expression(
1460            exp.MergeTreeTTL,
1461            expressions=expressions,
1462            where=where,
1463            group=group,
1464            aggregates=aggregates,
1465        )
1466
1467    def _parse_statement(self) -> t.Optional[exp.Expression]:
1468        if self._curr is None:
1469            return None
1470
1471        if self._match_set(self.STATEMENT_PARSERS):
1472            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1473
1474        if self._match_set(Tokenizer.COMMANDS):
1475            return self._parse_command()
1476
1477        expression = self._parse_expression()
1478        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1479        return self._parse_query_modifiers(expression)
1480
1481    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1482        start = self._prev
1483        temporary = self._match(TokenType.TEMPORARY)
1484        materialized = self._match_text_seq("MATERIALIZED")
1485
1486        kind = self._match_set(self.CREATABLES) and self._prev.text
1487        if not kind:
1488            return self._parse_as_command(start)
1489
1490        if_exists = exists or self._parse_exists()
1491        table = self._parse_table_parts(
1492            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1493        )
1494
1495        if self._match(TokenType.L_PAREN, advance=False):
1496            expressions = self._parse_wrapped_csv(self._parse_types)
1497        else:
1498            expressions = None
1499
1500        return self.expression(
1501            exp.Drop,
1502            comments=start.comments,
1503            exists=if_exists,
1504            this=table,
1505            expressions=expressions,
1506            kind=kind,
1507            temporary=temporary,
1508            materialized=materialized,
1509            cascade=self._match_text_seq("CASCADE"),
1510            constraints=self._match_text_seq("CONSTRAINTS"),
1511            purge=self._match_text_seq("PURGE"),
1512        )
1513
1514    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1515        return (
1516            self._match_text_seq("IF")
1517            and (not not_ or self._match(TokenType.NOT))
1518            and self._match(TokenType.EXISTS)
1519        )
1520
1521    def _parse_create(self) -> exp.Create | exp.Command:
1522        # Note: this can't be None because we've matched a statement parser
1523        start = self._prev
1524        comments = self._prev_comments
1525
1526        replace = (
1527            start.token_type == TokenType.REPLACE
1528            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1529            or self._match_pair(TokenType.OR, TokenType.ALTER)
1530        )
1531
1532        unique = self._match(TokenType.UNIQUE)
1533
1534        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1535            self._advance()
1536
1537        properties = None
1538        create_token = self._match_set(self.CREATABLES) and self._prev
1539
1540        if not create_token:
1541            # exp.Properties.Location.POST_CREATE
1542            properties = self._parse_properties()
1543            create_token = self._match_set(self.CREATABLES) and self._prev
1544
1545            if not properties or not create_token:
1546                return self._parse_as_command(start)
1547
1548        exists = self._parse_exists(not_=True)
1549        this = None
1550        expression: t.Optional[exp.Expression] = None
1551        indexes = None
1552        no_schema_binding = None
1553        begin = None
1554        end = None
1555        clone = None
1556
1557        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1558            nonlocal properties
1559            if properties and temp_props:
1560                properties.expressions.extend(temp_props.expressions)
1561            elif temp_props:
1562                properties = temp_props
1563
1564        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1565            this = self._parse_user_defined_function(kind=create_token.token_type)
1566
1567            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1568            extend_props(self._parse_properties())
1569
1570            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1571
1572            if not expression:
1573                if self._match(TokenType.COMMAND):
1574                    expression = self._parse_as_command(self._prev)
1575                else:
1576                    begin = self._match(TokenType.BEGIN)
1577                    return_ = self._match_text_seq("RETURN")
1578
1579                    if self._match(TokenType.STRING, advance=False):
1580                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1581                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1582                        expression = self._parse_string()
1583                        extend_props(self._parse_properties())
1584                    else:
1585                        expression = self._parse_statement()
1586
1587                    end = self._match_text_seq("END")
1588
1589                    if return_:
1590                        expression = self.expression(exp.Return, this=expression)
1591        elif create_token.token_type == TokenType.INDEX:
1592            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1593            if not self._match(TokenType.ON):
1594                index = self._parse_id_var()
1595                anonymous = False
1596            else:
1597                index = None
1598                anonymous = True
1599
1600            this = self._parse_index(index=index, anonymous=anonymous)
1601        elif create_token.token_type in self.DB_CREATABLES:
1602            table_parts = self._parse_table_parts(
1603                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1604            )
1605
1606            # exp.Properties.Location.POST_NAME
1607            self._match(TokenType.COMMA)
1608            extend_props(self._parse_properties(before=True))
1609
1610            this = self._parse_schema(this=table_parts)
1611
1612            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1613            extend_props(self._parse_properties())
1614
1615            self._match(TokenType.ALIAS)
1616            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1617                # exp.Properties.Location.POST_ALIAS
1618                extend_props(self._parse_properties())
1619
1620            if create_token.token_type == TokenType.SEQUENCE:
1621                expression = self._parse_types()
1622                extend_props(self._parse_properties())
1623            else:
1624                expression = self._parse_ddl_select()
1625
1626            if create_token.token_type == TokenType.TABLE:
1627                # exp.Properties.Location.POST_EXPRESSION
1628                extend_props(self._parse_properties())
1629
1630                indexes = []
1631                while True:
1632                    index = self._parse_index()
1633
1634                    # exp.Properties.Location.POST_INDEX
1635                    extend_props(self._parse_properties())
1636
1637                    if not index:
1638                        break
1639                    else:
1640                        self._match(TokenType.COMMA)
1641                        indexes.append(index)
1642            elif create_token.token_type == TokenType.VIEW:
1643                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1644                    no_schema_binding = True
1645
1646            shallow = self._match_text_seq("SHALLOW")
1647
1648            if self._match_texts(self.CLONE_KEYWORDS):
1649                copy = self._prev.text.lower() == "copy"
1650                clone = self.expression(
1651                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1652                )
1653
1654        if self._curr:
1655            return self._parse_as_command(start)
1656
1657        return self.expression(
1658            exp.Create,
1659            comments=comments,
1660            this=this,
1661            kind=create_token.text.upper(),
1662            replace=replace,
1663            unique=unique,
1664            expression=expression,
1665            exists=exists,
1666            properties=properties,
1667            indexes=indexes,
1668            no_schema_binding=no_schema_binding,
1669            begin=begin,
1670            end=end,
1671            clone=clone,
1672        )
1673
1674    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1675        seq = exp.SequenceProperties()
1676
1677        options = []
1678        index = self._index
1679
1680        while self._curr:
1681            if self._match_text_seq("INCREMENT"):
1682                self._match_text_seq("BY")
1683                self._match_text_seq("=")
1684                seq.set("increment", self._parse_term())
1685            elif self._match_text_seq("MINVALUE"):
1686                seq.set("minvalue", self._parse_term())
1687            elif self._match_text_seq("MAXVALUE"):
1688                seq.set("maxvalue", self._parse_term())
1689            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1690                self._match_text_seq("=")
1691                seq.set("start", self._parse_term())
1692            elif self._match_text_seq("CACHE"):
1693                # T-SQL allows empty CACHE which is initialized dynamically
1694                seq.set("cache", self._parse_number() or True)
1695            elif self._match_text_seq("OWNED", "BY"):
1696                # "OWNED BY NONE" is the default
1697                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1698            else:
1699                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1700                if opt:
1701                    options.append(opt)
1702                else:
1703                    break
1704
1705        seq.set("options", options if options else None)
1706        return None if self._index == index else seq
1707
1708    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1709        # only used for teradata currently
1710        self._match(TokenType.COMMA)
1711
1712        kwargs = {
1713            "no": self._match_text_seq("NO"),
1714            "dual": self._match_text_seq("DUAL"),
1715            "before": self._match_text_seq("BEFORE"),
1716            "default": self._match_text_seq("DEFAULT"),
1717            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1718            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1719            "after": self._match_text_seq("AFTER"),
1720            "minimum": self._match_texts(("MIN", "MINIMUM")),
1721            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1722        }
1723
1724        if self._match_texts(self.PROPERTY_PARSERS):
1725            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1726            try:
1727                return parser(self, **{k: v for k, v in kwargs.items() if v})
1728            except TypeError:
1729                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1730
1731        return None
1732
1733    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1734        return self._parse_wrapped_csv(self._parse_property)
1735
1736    def _parse_property(self) -> t.Optional[exp.Expression]:
1737        if self._match_texts(self.PROPERTY_PARSERS):
1738            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1739
1740        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1741            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1742
1743        if self._match_text_seq("COMPOUND", "SORTKEY"):
1744            return self._parse_sortkey(compound=True)
1745
1746        if self._match_text_seq("SQL", "SECURITY"):
1747            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1748
1749        index = self._index
1750        key = self._parse_column()
1751
1752        if not self._match(TokenType.EQ):
1753            self._retreat(index)
1754            return self._parse_sequence_properties()
1755
1756        return self.expression(
1757            exp.Property,
1758            this=key.to_dot() if isinstance(key, exp.Column) else key,
1759            value=self._parse_bitwise() or self._parse_var(any_token=True),
1760        )
1761
1762    def _parse_stored(self) -> exp.FileFormatProperty:
1763        self._match(TokenType.ALIAS)
1764
1765        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1766        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1767
1768        return self.expression(
1769            exp.FileFormatProperty,
1770            this=(
1771                self.expression(
1772                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1773                )
1774                if input_format or output_format
1775                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1776            ),
1777        )
1778
1779    def _parse_unquoted_field(self):
1780        field = self._parse_field()
1781        if isinstance(field, exp.Identifier) and not field.quoted:
1782            field = exp.var(field)
1783
1784        return field
1785
1786    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1787        self._match(TokenType.EQ)
1788        self._match(TokenType.ALIAS)
1789
1790        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1791
1792    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1793        properties = []
1794        while True:
1795            if before:
1796                prop = self._parse_property_before()
1797            else:
1798                prop = self._parse_property()
1799            if not prop:
1800                break
1801            for p in ensure_list(prop):
1802                properties.append(p)
1803
1804        if properties:
1805            return self.expression(exp.Properties, expressions=properties)
1806
1807        return None
1808
1809    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1810        return self.expression(
1811            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1812        )
1813
1814    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1815        if self._index >= 2:
1816            pre_volatile_token = self._tokens[self._index - 2]
1817        else:
1818            pre_volatile_token = None
1819
1820        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1821            return exp.VolatileProperty()
1822
1823        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1824
1825    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1826        self._match_pair(TokenType.EQ, TokenType.ON)
1827
1828        prop = self.expression(exp.WithSystemVersioningProperty)
1829        if self._match(TokenType.L_PAREN):
1830            self._match_text_seq("HISTORY_TABLE", "=")
1831            prop.set("this", self._parse_table_parts())
1832
1833            if self._match(TokenType.COMMA):
1834                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1835                prop.set("expression", self._advance_any() and self._prev.text.upper())
1836
1837            self._match_r_paren()
1838
1839        return prop
1840
1841    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1842        if self._match(TokenType.L_PAREN, advance=False):
1843            return self._parse_wrapped_properties()
1844
1845        if self._match_text_seq("JOURNAL"):
1846            return self._parse_withjournaltable()
1847
1848        if self._match_texts(self.VIEW_ATTRIBUTES):
1849            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
1850
1851        if self._match_text_seq("DATA"):
1852            return self._parse_withdata(no=False)
1853        elif self._match_text_seq("NO", "DATA"):
1854            return self._parse_withdata(no=True)
1855
1856        if not self._next:
1857            return None
1858
1859        return self._parse_withisolatedloading()
1860
1861    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1862    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1863        self._match(TokenType.EQ)
1864
1865        user = self._parse_id_var()
1866        self._match(TokenType.PARAMETER)
1867        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1868
1869        if not user or not host:
1870            return None
1871
1872        return exp.DefinerProperty(this=f"{user}@{host}")
1873
1874    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1875        self._match(TokenType.TABLE)
1876        self._match(TokenType.EQ)
1877        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1878
1879    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1880        return self.expression(exp.LogProperty, no=no)
1881
1882    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1883        return self.expression(exp.JournalProperty, **kwargs)
1884
1885    def _parse_checksum(self) -> exp.ChecksumProperty:
1886        self._match(TokenType.EQ)
1887
1888        on = None
1889        if self._match(TokenType.ON):
1890            on = True
1891        elif self._match_text_seq("OFF"):
1892            on = False
1893
1894        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1895
1896    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
1897        return self.expression(
1898            exp.Cluster,
1899            expressions=(
1900                self._parse_wrapped_csv(self._parse_ordered)
1901                if wrapped
1902                else self._parse_csv(self._parse_ordered)
1903            ),
1904        )
1905
1906    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1907        self._match_text_seq("BY")
1908
1909        self._match_l_paren()
1910        expressions = self._parse_csv(self._parse_column)
1911        self._match_r_paren()
1912
1913        if self._match_text_seq("SORTED", "BY"):
1914            self._match_l_paren()
1915            sorted_by = self._parse_csv(self._parse_ordered)
1916            self._match_r_paren()
1917        else:
1918            sorted_by = None
1919
1920        self._match(TokenType.INTO)
1921        buckets = self._parse_number()
1922        self._match_text_seq("BUCKETS")
1923
1924        return self.expression(
1925            exp.ClusteredByProperty,
1926            expressions=expressions,
1927            sorted_by=sorted_by,
1928            buckets=buckets,
1929        )
1930
1931    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1932        if not self._match_text_seq("GRANTS"):
1933            self._retreat(self._index - 1)
1934            return None
1935
1936        return self.expression(exp.CopyGrantsProperty)
1937
1938    def _parse_freespace(self) -> exp.FreespaceProperty:
1939        self._match(TokenType.EQ)
1940        return self.expression(
1941            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1942        )
1943
1944    def _parse_mergeblockratio(
1945        self, no: bool = False, default: bool = False
1946    ) -> exp.MergeBlockRatioProperty:
1947        if self._match(TokenType.EQ):
1948            return self.expression(
1949                exp.MergeBlockRatioProperty,
1950                this=self._parse_number(),
1951                percent=self._match(TokenType.PERCENT),
1952            )
1953
1954        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1955
1956    def _parse_datablocksize(
1957        self,
1958        default: t.Optional[bool] = None,
1959        minimum: t.Optional[bool] = None,
1960        maximum: t.Optional[bool] = None,
1961    ) -> exp.DataBlocksizeProperty:
1962        self._match(TokenType.EQ)
1963        size = self._parse_number()
1964
1965        units = None
1966        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1967            units = self._prev.text
1968
1969        return self.expression(
1970            exp.DataBlocksizeProperty,
1971            size=size,
1972            units=units,
1973            default=default,
1974            minimum=minimum,
1975            maximum=maximum,
1976        )
1977
1978    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1979        self._match(TokenType.EQ)
1980        always = self._match_text_seq("ALWAYS")
1981        manual = self._match_text_seq("MANUAL")
1982        never = self._match_text_seq("NEVER")
1983        default = self._match_text_seq("DEFAULT")
1984
1985        autotemp = None
1986        if self._match_text_seq("AUTOTEMP"):
1987            autotemp = self._parse_schema()
1988
1989        return self.expression(
1990            exp.BlockCompressionProperty,
1991            always=always,
1992            manual=manual,
1993            never=never,
1994            default=default,
1995            autotemp=autotemp,
1996        )
1997
1998    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
1999        index = self._index
2000        no = self._match_text_seq("NO")
2001        concurrent = self._match_text_seq("CONCURRENT")
2002
2003        if not self._match_text_seq("ISOLATED", "LOADING"):
2004            self._retreat(index)
2005            return None
2006
2007        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2008        return self.expression(
2009            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2010        )
2011
2012    def _parse_locking(self) -> exp.LockingProperty:
2013        if self._match(TokenType.TABLE):
2014            kind = "TABLE"
2015        elif self._match(TokenType.VIEW):
2016            kind = "VIEW"
2017        elif self._match(TokenType.ROW):
2018            kind = "ROW"
2019        elif self._match_text_seq("DATABASE"):
2020            kind = "DATABASE"
2021        else:
2022            kind = None
2023
2024        if kind in ("DATABASE", "TABLE", "VIEW"):
2025            this = self._parse_table_parts()
2026        else:
2027            this = None
2028
2029        if self._match(TokenType.FOR):
2030            for_or_in = "FOR"
2031        elif self._match(TokenType.IN):
2032            for_or_in = "IN"
2033        else:
2034            for_or_in = None
2035
2036        if self._match_text_seq("ACCESS"):
2037            lock_type = "ACCESS"
2038        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2039            lock_type = "EXCLUSIVE"
2040        elif self._match_text_seq("SHARE"):
2041            lock_type = "SHARE"
2042        elif self._match_text_seq("READ"):
2043            lock_type = "READ"
2044        elif self._match_text_seq("WRITE"):
2045            lock_type = "WRITE"
2046        elif self._match_text_seq("CHECKSUM"):
2047            lock_type = "CHECKSUM"
2048        else:
2049            lock_type = None
2050
2051        override = self._match_text_seq("OVERRIDE")
2052
2053        return self.expression(
2054            exp.LockingProperty,
2055            this=this,
2056            kind=kind,
2057            for_or_in=for_or_in,
2058            lock_type=lock_type,
2059            override=override,
2060        )
2061
2062    def _parse_partition_by(self) -> t.List[exp.Expression]:
2063        if self._match(TokenType.PARTITION_BY):
2064            return self._parse_csv(self._parse_conjunction)
2065        return []
2066
2067    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2068        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2069            if self._match_text_seq("MINVALUE"):
2070                return exp.var("MINVALUE")
2071            if self._match_text_seq("MAXVALUE"):
2072                return exp.var("MAXVALUE")
2073            return self._parse_bitwise()
2074
2075        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2076        expression = None
2077        from_expressions = None
2078        to_expressions = None
2079
2080        if self._match(TokenType.IN):
2081            this = self._parse_wrapped_csv(self._parse_bitwise)
2082        elif self._match(TokenType.FROM):
2083            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2084            self._match_text_seq("TO")
2085            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2086        elif self._match_text_seq("WITH", "(", "MODULUS"):
2087            this = self._parse_number()
2088            self._match_text_seq(",", "REMAINDER")
2089            expression = self._parse_number()
2090            self._match_r_paren()
2091        else:
2092            self.raise_error("Failed to parse partition bound spec.")
2093
2094        return self.expression(
2095            exp.PartitionBoundSpec,
2096            this=this,
2097            expression=expression,
2098            from_expressions=from_expressions,
2099            to_expressions=to_expressions,
2100        )
2101
2102    # https://www.postgresql.org/docs/current/sql-createtable.html
2103    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2104        if not self._match_text_seq("OF"):
2105            self._retreat(self._index - 1)
2106            return None
2107
2108        this = self._parse_table(schema=True)
2109
2110        if self._match(TokenType.DEFAULT):
2111            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2112        elif self._match_text_seq("FOR", "VALUES"):
2113            expression = self._parse_partition_bound_spec()
2114        else:
2115            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2116
2117        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2118
2119    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2120        self._match(TokenType.EQ)
2121        return self.expression(
2122            exp.PartitionedByProperty,
2123            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2124        )
2125
2126    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2127        if self._match_text_seq("AND", "STATISTICS"):
2128            statistics = True
2129        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2130            statistics = False
2131        else:
2132            statistics = None
2133
2134        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2135
2136    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2137        if self._match_text_seq("SQL"):
2138            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2139        return None
2140
2141    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2142        if self._match_text_seq("SQL", "DATA"):
2143            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2144        return None
2145
2146    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2147        if self._match_text_seq("PRIMARY", "INDEX"):
2148            return exp.NoPrimaryIndexProperty()
2149        if self._match_text_seq("SQL"):
2150            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2151        return None
2152
2153    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2154        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2155            return exp.OnCommitProperty()
2156        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2157            return exp.OnCommitProperty(delete=True)
2158        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2159
2160    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2161        if self._match_text_seq("SQL", "DATA"):
2162            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2163        return None
2164
2165    def _parse_distkey(self) -> exp.DistKeyProperty:
2166        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2167
2168    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2169        table = self._parse_table(schema=True)
2170
2171        options = []
2172        while self._match_texts(("INCLUDING", "EXCLUDING")):
2173            this = self._prev.text.upper()
2174
2175            id_var = self._parse_id_var()
2176            if not id_var:
2177                return None
2178
2179            options.append(
2180                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2181            )
2182
2183        return self.expression(exp.LikeProperty, this=table, expressions=options)
2184
2185    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2186        return self.expression(
2187            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2188        )
2189
2190    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2191        self._match(TokenType.EQ)
2192        return self.expression(
2193            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2194        )
2195
2196    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2197        self._match_text_seq("WITH", "CONNECTION")
2198        return self.expression(
2199            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2200        )
2201
2202    def _parse_returns(self) -> exp.ReturnsProperty:
2203        value: t.Optional[exp.Expression]
2204        is_table = self._match(TokenType.TABLE)
2205
2206        if is_table:
2207            if self._match(TokenType.LT):
2208                value = self.expression(
2209                    exp.Schema,
2210                    this="TABLE",
2211                    expressions=self._parse_csv(self._parse_struct_types),
2212                )
2213                if not self._match(TokenType.GT):
2214                    self.raise_error("Expecting >")
2215            else:
2216                value = self._parse_schema(exp.var("TABLE"))
2217        else:
2218            value = self._parse_types()
2219
2220        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
2221
2222    def _parse_describe(self) -> exp.Describe:
2223        kind = self._match_set(self.CREATABLES) and self._prev.text
2224        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2225        if self._match(TokenType.DOT):
2226            style = None
2227            self._retreat(self._index - 2)
2228        this = self._parse_table(schema=True)
2229        properties = self._parse_properties()
2230        expressions = properties.expressions if properties else None
2231        return self.expression(
2232            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2233        )
2234
2235    def _parse_insert(self) -> exp.Insert:
2236        comments = ensure_list(self._prev_comments)
2237        hint = self._parse_hint()
2238        overwrite = self._match(TokenType.OVERWRITE)
2239        ignore = self._match(TokenType.IGNORE)
2240        local = self._match_text_seq("LOCAL")
2241        alternative = None
2242        is_function = None
2243
2244        if self._match_text_seq("DIRECTORY"):
2245            this: t.Optional[exp.Expression] = self.expression(
2246                exp.Directory,
2247                this=self._parse_var_or_string(),
2248                local=local,
2249                row_format=self._parse_row_format(match_row=True),
2250            )
2251        else:
2252            if self._match(TokenType.OR):
2253                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2254
2255            self._match(TokenType.INTO)
2256            comments += ensure_list(self._prev_comments)
2257            self._match(TokenType.TABLE)
2258            is_function = self._match(TokenType.FUNCTION)
2259
2260            this = (
2261                self._parse_table(schema=True, parse_partition=True)
2262                if not is_function
2263                else self._parse_function()
2264            )
2265
2266        returning = self._parse_returning()
2267
2268        return self.expression(
2269            exp.Insert,
2270            comments=comments,
2271            hint=hint,
2272            is_function=is_function,
2273            this=this,
2274            stored=self._match_text_seq("STORED") and self._parse_stored(),
2275            by_name=self._match_text_seq("BY", "NAME"),
2276            exists=self._parse_exists(),
2277            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
2278            and self._parse_conjunction(),
2279            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2280            conflict=self._parse_on_conflict(),
2281            returning=returning or self._parse_returning(),
2282            overwrite=overwrite,
2283            alternative=alternative,
2284            ignore=ignore,
2285        )
2286
2287    def _parse_kill(self) -> exp.Kill:
2288        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2289
2290        return self.expression(
2291            exp.Kill,
2292            this=self._parse_primary(),
2293            kind=kind,
2294        )
2295
2296    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2297        conflict = self._match_text_seq("ON", "CONFLICT")
2298        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2299
2300        if not conflict and not duplicate:
2301            return None
2302
2303        conflict_keys = None
2304        constraint = None
2305
2306        if conflict:
2307            if self._match_text_seq("ON", "CONSTRAINT"):
2308                constraint = self._parse_id_var()
2309            elif self._match(TokenType.L_PAREN):
2310                conflict_keys = self._parse_csv(self._parse_id_var)
2311                self._match_r_paren()
2312
2313        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2314        if self._prev.token_type == TokenType.UPDATE:
2315            self._match(TokenType.SET)
2316            expressions = self._parse_csv(self._parse_equality)
2317        else:
2318            expressions = None
2319
2320        return self.expression(
2321            exp.OnConflict,
2322            duplicate=duplicate,
2323            expressions=expressions,
2324            action=action,
2325            conflict_keys=conflict_keys,
2326            constraint=constraint,
2327        )
2328
2329    def _parse_returning(self) -> t.Optional[exp.Returning]:
2330        if not self._match(TokenType.RETURNING):
2331            return None
2332        return self.expression(
2333            exp.Returning,
2334            expressions=self._parse_csv(self._parse_expression),
2335            into=self._match(TokenType.INTO) and self._parse_table_part(),
2336        )
2337
2338    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2339        if not self._match(TokenType.FORMAT):
2340            return None
2341        return self._parse_row_format()
2342
2343    def _parse_row_format(
2344        self, match_row: bool = False
2345    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2346        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2347            return None
2348
2349        if self._match_text_seq("SERDE"):
2350            this = self._parse_string()
2351
2352            serde_properties = None
2353            if self._match(TokenType.SERDE_PROPERTIES):
2354                serde_properties = self.expression(
2355                    exp.SerdeProperties, expressions=self._parse_wrapped_properties()
2356                )
2357
2358            return self.expression(
2359                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2360            )
2361
2362        self._match_text_seq("DELIMITED")
2363
2364        kwargs = {}
2365
2366        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2367            kwargs["fields"] = self._parse_string()
2368            if self._match_text_seq("ESCAPED", "BY"):
2369                kwargs["escaped"] = self._parse_string()
2370        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2371            kwargs["collection_items"] = self._parse_string()
2372        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2373            kwargs["map_keys"] = self._parse_string()
2374        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2375            kwargs["lines"] = self._parse_string()
2376        if self._match_text_seq("NULL", "DEFINED", "AS"):
2377            kwargs["null"] = self._parse_string()
2378
2379        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2380
2381    def _parse_load(self) -> exp.LoadData | exp.Command:
2382        if self._match_text_seq("DATA"):
2383            local = self._match_text_seq("LOCAL")
2384            self._match_text_seq("INPATH")
2385            inpath = self._parse_string()
2386            overwrite = self._match(TokenType.OVERWRITE)
2387            self._match_pair(TokenType.INTO, TokenType.TABLE)
2388
2389            return self.expression(
2390                exp.LoadData,
2391                this=self._parse_table(schema=True),
2392                local=local,
2393                overwrite=overwrite,
2394                inpath=inpath,
2395                partition=self._parse_partition(),
2396                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2397                serde=self._match_text_seq("SERDE") and self._parse_string(),
2398            )
2399        return self._parse_as_command(self._prev)
2400
2401    def _parse_delete(self) -> exp.Delete:
2402        # This handles MySQL's "Multiple-Table Syntax"
2403        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2404        tables = None
2405        comments = self._prev_comments
2406        if not self._match(TokenType.FROM, advance=False):
2407            tables = self._parse_csv(self._parse_table) or None
2408
2409        returning = self._parse_returning()
2410
2411        return self.expression(
2412            exp.Delete,
2413            comments=comments,
2414            tables=tables,
2415            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2416            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2417            where=self._parse_where(),
2418            returning=returning or self._parse_returning(),
2419            limit=self._parse_limit(),
2420        )
2421
2422    def _parse_update(self) -> exp.Update:
2423        comments = self._prev_comments
2424        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2425        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2426        returning = self._parse_returning()
2427        return self.expression(
2428            exp.Update,
2429            comments=comments,
2430            **{  # type: ignore
2431                "this": this,
2432                "expressions": expressions,
2433                "from": self._parse_from(joins=True),
2434                "where": self._parse_where(),
2435                "returning": returning or self._parse_returning(),
2436                "order": self._parse_order(),
2437                "limit": self._parse_limit(),
2438            },
2439        )
2440
2441    def _parse_uncache(self) -> exp.Uncache:
2442        if not self._match(TokenType.TABLE):
2443            self.raise_error("Expecting TABLE after UNCACHE")
2444
2445        return self.expression(
2446            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2447        )
2448
2449    def _parse_cache(self) -> exp.Cache:
2450        lazy = self._match_text_seq("LAZY")
2451        self._match(TokenType.TABLE)
2452        table = self._parse_table(schema=True)
2453
2454        options = []
2455        if self._match_text_seq("OPTIONS"):
2456            self._match_l_paren()
2457            k = self._parse_string()
2458            self._match(TokenType.EQ)
2459            v = self._parse_string()
2460            options = [k, v]
2461            self._match_r_paren()
2462
2463        self._match(TokenType.ALIAS)
2464        return self.expression(
2465            exp.Cache,
2466            this=table,
2467            lazy=lazy,
2468            options=options,
2469            expression=self._parse_select(nested=True),
2470        )
2471
2472    def _parse_partition(self) -> t.Optional[exp.Partition]:
2473        if not self._match(TokenType.PARTITION):
2474            return None
2475
2476        return self.expression(
2477            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2478        )
2479
2480    def _parse_value(self) -> t.Optional[exp.Tuple]:
2481        if self._match(TokenType.L_PAREN):
2482            expressions = self._parse_csv(self._parse_expression)
2483            self._match_r_paren()
2484            return self.expression(exp.Tuple, expressions=expressions)
2485
2486        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2487        expression = self._parse_expression()
2488        if expression:
2489            return self.expression(exp.Tuple, expressions=[expression])
2490        return None
2491
2492    def _parse_projections(self) -> t.List[exp.Expression]:
2493        return self._parse_expressions()
2494
2495    def _parse_select(
2496        self,
2497        nested: bool = False,
2498        table: bool = False,
2499        parse_subquery_alias: bool = True,
2500        parse_set_operation: bool = True,
2501    ) -> t.Optional[exp.Expression]:
2502        cte = self._parse_with()
2503
2504        if cte:
2505            this = self._parse_statement()
2506
2507            if not this:
2508                self.raise_error("Failed to parse any statement following CTE")
2509                return cte
2510
2511            if "with" in this.arg_types:
2512                this.set("with", cte)
2513            else:
2514                self.raise_error(f"{this.key} does not support CTE")
2515                this = cte
2516
2517            return this
2518
2519        # duckdb supports leading with FROM x
2520        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2521
2522        if self._match(TokenType.SELECT):
2523            comments = self._prev_comments
2524
2525            hint = self._parse_hint()
2526            all_ = self._match(TokenType.ALL)
2527            distinct = self._match_set(self.DISTINCT_TOKENS)
2528
2529            kind = (
2530                self._match(TokenType.ALIAS)
2531                and self._match_texts(("STRUCT", "VALUE"))
2532                and self._prev.text.upper()
2533            )
2534
2535            if distinct:
2536                distinct = self.expression(
2537                    exp.Distinct,
2538                    on=self._parse_value() if self._match(TokenType.ON) else None,
2539                )
2540
2541            if all_ and distinct:
2542                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2543
2544            limit = self._parse_limit(top=True)
2545            projections = self._parse_projections()
2546
2547            this = self.expression(
2548                exp.Select,
2549                kind=kind,
2550                hint=hint,
2551                distinct=distinct,
2552                expressions=projections,
2553                limit=limit,
2554            )
2555            this.comments = comments
2556
2557            into = self._parse_into()
2558            if into:
2559                this.set("into", into)
2560
2561            if not from_:
2562                from_ = self._parse_from()
2563
2564            if from_:
2565                this.set("from", from_)
2566
2567            this = self._parse_query_modifiers(this)
2568        elif (table or nested) and self._match(TokenType.L_PAREN):
2569            if self._match(TokenType.PIVOT):
2570                this = self._parse_simplified_pivot()
2571            elif self._match(TokenType.FROM):
2572                this = exp.select("*").from_(
2573                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2574                )
2575            else:
2576                this = (
2577                    self._parse_table()
2578                    if table
2579                    else self._parse_select(nested=True, parse_set_operation=False)
2580                )
2581                this = self._parse_query_modifiers(self._parse_set_operations(this))
2582
2583            self._match_r_paren()
2584
2585            # We return early here so that the UNION isn't attached to the subquery by the
2586            # following call to _parse_set_operations, but instead becomes the parent node
2587            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2588        elif self._match(TokenType.VALUES, advance=False):
2589            this = self._parse_derived_table_values()
2590        elif from_:
2591            this = exp.select("*").from_(from_.this, copy=False)
2592        else:
2593            this = None
2594
2595        if parse_set_operation:
2596            return self._parse_set_operations(this)
2597        return this
2598
2599    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2600        if not skip_with_token and not self._match(TokenType.WITH):
2601            return None
2602
2603        comments = self._prev_comments
2604        recursive = self._match(TokenType.RECURSIVE)
2605
2606        expressions = []
2607        while True:
2608            expressions.append(self._parse_cte())
2609
2610            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2611                break
2612            else:
2613                self._match(TokenType.WITH)
2614
2615        return self.expression(
2616            exp.With, comments=comments, expressions=expressions, recursive=recursive
2617        )
2618
2619    def _parse_cte(self) -> exp.CTE:
2620        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2621        if not alias or not alias.this:
2622            self.raise_error("Expected CTE to have alias")
2623
2624        self._match(TokenType.ALIAS)
2625
2626        if self._match_text_seq("NOT", "MATERIALIZED"):
2627            materialized = False
2628        elif self._match_text_seq("MATERIALIZED"):
2629            materialized = True
2630        else:
2631            materialized = None
2632
2633        return self.expression(
2634            exp.CTE,
2635            this=self._parse_wrapped(self._parse_statement),
2636            alias=alias,
2637            materialized=materialized,
2638        )
2639
2640    def _parse_table_alias(
2641        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2642    ) -> t.Optional[exp.TableAlias]:
2643        any_token = self._match(TokenType.ALIAS)
2644        alias = (
2645            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2646            or self._parse_string_as_identifier()
2647        )
2648
2649        index = self._index
2650        if self._match(TokenType.L_PAREN):
2651            columns = self._parse_csv(self._parse_function_parameter)
2652            self._match_r_paren() if columns else self._retreat(index)
2653        else:
2654            columns = None
2655
2656        if not alias and not columns:
2657            return None
2658
2659        return self.expression(exp.TableAlias, this=alias, columns=columns)
2660
2661    def _parse_subquery(
2662        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2663    ) -> t.Optional[exp.Subquery]:
2664        if not this:
2665            return None
2666
2667        return self.expression(
2668            exp.Subquery,
2669            this=this,
2670            pivots=self._parse_pivots(),
2671            alias=self._parse_table_alias() if parse_alias else None,
2672        )
2673
2674    def _implicit_unnests_to_explicit(self, this: E) -> E:
2675        from sqlglot.optimizer.normalize_identifiers import (
2676            normalize_identifiers as _norm,
2677        )
2678
2679        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2680        for i, join in enumerate(this.args.get("joins") or []):
2681            table = join.this
2682            normalized_table = table.copy()
2683            normalized_table.meta["maybe_column"] = True
2684            normalized_table = _norm(normalized_table, dialect=self.dialect)
2685
2686            if isinstance(table, exp.Table) and not join.args.get("on"):
2687                if normalized_table.parts[0].name in refs:
2688                    table_as_column = table.to_column()
2689                    unnest = exp.Unnest(expressions=[table_as_column])
2690
2691                    # Table.to_column creates a parent Alias node that we want to convert to
2692                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2693                    if isinstance(table.args.get("alias"), exp.TableAlias):
2694                        table_as_column.replace(table_as_column.this)
2695                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2696
2697                    table.replace(unnest)
2698
2699            refs.add(normalized_table.alias_or_name)
2700
2701        return this
2702
2703    def _parse_query_modifiers(
2704        self, this: t.Optional[exp.Expression]
2705    ) -> t.Optional[exp.Expression]:
2706        if isinstance(this, (exp.Query, exp.Table)):
2707            for join in self._parse_joins():
2708                this.append("joins", join)
2709            for lateral in iter(self._parse_lateral, None):
2710                this.append("laterals", lateral)
2711
2712            while True:
2713                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2714                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2715                    key, expression = parser(self)
2716
2717                    if expression:
2718                        this.set(key, expression)
2719                        if key == "limit":
2720                            offset = expression.args.pop("offset", None)
2721
2722                            if offset:
2723                                offset = exp.Offset(expression=offset)
2724                                this.set("offset", offset)
2725
2726                                limit_by_expressions = expression.expressions
2727                                expression.set("expressions", None)
2728                                offset.set("expressions", limit_by_expressions)
2729                        continue
2730                break
2731
2732        if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
2733            this = self._implicit_unnests_to_explicit(this)
2734
2735        return this
2736
2737    def _parse_hint(self) -> t.Optional[exp.Hint]:
2738        if self._match(TokenType.HINT):
2739            hints = []
2740            for hint in iter(
2741                lambda: self._parse_csv(
2742                    lambda: self._parse_function() or self._parse_var(upper=True)
2743                ),
2744                [],
2745            ):
2746                hints.extend(hint)
2747
2748            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2749                self.raise_error("Expected */ after HINT")
2750
2751            return self.expression(exp.Hint, expressions=hints)
2752
2753        return None
2754
2755    def _parse_into(self) -> t.Optional[exp.Into]:
2756        if not self._match(TokenType.INTO):
2757            return None
2758
2759        temp = self._match(TokenType.TEMPORARY)
2760        unlogged = self._match_text_seq("UNLOGGED")
2761        self._match(TokenType.TABLE)
2762
2763        return self.expression(
2764            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2765        )
2766
2767    def _parse_from(
2768        self, joins: bool = False, skip_from_token: bool = False
2769    ) -> t.Optional[exp.From]:
2770        if not skip_from_token and not self._match(TokenType.FROM):
2771            return None
2772
2773        return self.expression(
2774            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2775        )
2776
2777    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
2778        return self.expression(
2779            exp.MatchRecognizeMeasure,
2780            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
2781            this=self._parse_expression(),
2782        )
2783
2784    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2785        if not self._match(TokenType.MATCH_RECOGNIZE):
2786            return None
2787
2788        self._match_l_paren()
2789
2790        partition = self._parse_partition_by()
2791        order = self._parse_order()
2792
2793        measures = (
2794            self._parse_csv(self._parse_match_recognize_measure)
2795            if self._match_text_seq("MEASURES")
2796            else None
2797        )
2798
2799        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2800            rows = exp.var("ONE ROW PER MATCH")
2801        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2802            text = "ALL ROWS PER MATCH"
2803            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2804                text += " SHOW EMPTY MATCHES"
2805            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2806                text += " OMIT EMPTY MATCHES"
2807            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2808                text += " WITH UNMATCHED ROWS"
2809            rows = exp.var(text)
2810        else:
2811            rows = None
2812
2813        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2814            text = "AFTER MATCH SKIP"
2815            if self._match_text_seq("PAST", "LAST", "ROW"):
2816                text += " PAST LAST ROW"
2817            elif self._match_text_seq("TO", "NEXT", "ROW"):
2818                text += " TO NEXT ROW"
2819            elif self._match_text_seq("TO", "FIRST"):
2820                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2821            elif self._match_text_seq("TO", "LAST"):
2822                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2823            after = exp.var(text)
2824        else:
2825            after = None
2826
2827        if self._match_text_seq("PATTERN"):
2828            self._match_l_paren()
2829
2830            if not self._curr:
2831                self.raise_error("Expecting )", self._curr)
2832
2833            paren = 1
2834            start = self._curr
2835
2836            while self._curr and paren > 0:
2837                if self._curr.token_type == TokenType.L_PAREN:
2838                    paren += 1
2839                if self._curr.token_type == TokenType.R_PAREN:
2840                    paren -= 1
2841
2842                end = self._prev
2843                self._advance()
2844
2845            if paren > 0:
2846                self.raise_error("Expecting )", self._curr)
2847
2848            pattern = exp.var(self._find_sql(start, end))
2849        else:
2850            pattern = None
2851
2852        define = (
2853            self._parse_csv(self._parse_name_as_expression)
2854            if self._match_text_seq("DEFINE")
2855            else None
2856        )
2857
2858        self._match_r_paren()
2859
2860        return self.expression(
2861            exp.MatchRecognize,
2862            partition_by=partition,
2863            order=order,
2864            measures=measures,
2865            rows=rows,
2866            after=after,
2867            pattern=pattern,
2868            define=define,
2869            alias=self._parse_table_alias(),
2870        )
2871
2872    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2873        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2874        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2875            cross_apply = False
2876
2877        if cross_apply is not None:
2878            this = self._parse_select(table=True)
2879            view = None
2880            outer = None
2881        elif self._match(TokenType.LATERAL):
2882            this = self._parse_select(table=True)
2883            view = self._match(TokenType.VIEW)
2884            outer = self._match(TokenType.OUTER)
2885        else:
2886            return None
2887
2888        if not this:
2889            this = (
2890                self._parse_unnest()
2891                or self._parse_function()
2892                or self._parse_id_var(any_token=False)
2893            )
2894
2895            while self._match(TokenType.DOT):
2896                this = exp.Dot(
2897                    this=this,
2898                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2899                )
2900
2901        if view:
2902            table = self._parse_id_var(any_token=False)
2903            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2904            table_alias: t.Optional[exp.TableAlias] = self.expression(
2905                exp.TableAlias, this=table, columns=columns
2906            )
2907        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2908            # We move the alias from the lateral's child node to the lateral itself
2909            table_alias = this.args["alias"].pop()
2910        else:
2911            table_alias = self._parse_table_alias()
2912
2913        return self.expression(
2914            exp.Lateral,
2915            this=this,
2916            view=view,
2917            outer=outer,
2918            alias=table_alias,
2919            cross_apply=cross_apply,
2920        )
2921
2922    def _parse_join_parts(
2923        self,
2924    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2925        return (
2926            self._match_set(self.JOIN_METHODS) and self._prev,
2927            self._match_set(self.JOIN_SIDES) and self._prev,
2928            self._match_set(self.JOIN_KINDS) and self._prev,
2929        )
2930
2931    def _parse_join(
2932        self, skip_join_token: bool = False, parse_bracket: bool = False
2933    ) -> t.Optional[exp.Join]:
2934        if self._match(TokenType.COMMA):
2935            return self.expression(exp.Join, this=self._parse_table())
2936
2937        index = self._index
2938        method, side, kind = self._parse_join_parts()
2939        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2940        join = self._match(TokenType.JOIN)
2941
2942        if not skip_join_token and not join:
2943            self._retreat(index)
2944            kind = None
2945            method = None
2946            side = None
2947
2948        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2949        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2950
2951        if not skip_join_token and not join and not outer_apply and not cross_apply:
2952            return None
2953
2954        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2955
2956        if method:
2957            kwargs["method"] = method.text
2958        if side:
2959            kwargs["side"] = side.text
2960        if kind:
2961            kwargs["kind"] = kind.text
2962        if hint:
2963            kwargs["hint"] = hint
2964
2965        if self._match(TokenType.MATCH_CONDITION):
2966            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
2967
2968        if self._match(TokenType.ON):
2969            kwargs["on"] = self._parse_conjunction()
2970        elif self._match(TokenType.USING):
2971            kwargs["using"] = self._parse_wrapped_id_vars()
2972        elif not isinstance(kwargs["this"], exp.Unnest) and not (
2973            kind and kind.token_type == TokenType.CROSS
2974        ):
2975            index = self._index
2976            joins: t.Optional[list] = list(self._parse_joins())
2977
2978            if joins and self._match(TokenType.ON):
2979                kwargs["on"] = self._parse_conjunction()
2980            elif joins and self._match(TokenType.USING):
2981                kwargs["using"] = self._parse_wrapped_id_vars()
2982            else:
2983                joins = None
2984                self._retreat(index)
2985
2986            kwargs["this"].set("joins", joins if joins else None)
2987
2988        comments = [c for token in (method, side, kind) if token for c in token.comments]
2989        return self.expression(exp.Join, comments=comments, **kwargs)
2990
2991    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2992        this = self._parse_conjunction()
2993
2994        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2995            return this
2996
2997        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2998            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
2999
3000        return this
3001
3002    def _parse_index_params(self) -> exp.IndexParameters:
3003        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3004
3005        if self._match(TokenType.L_PAREN, advance=False):
3006            columns = self._parse_wrapped_csv(self._parse_with_operator)
3007        else:
3008            columns = None
3009
3010        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3011        partition_by = self._parse_partition_by()
3012        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3013        tablespace = (
3014            self._parse_var(any_token=True)
3015            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3016            else None
3017        )
3018        where = self._parse_where()
3019
3020        return self.expression(
3021            exp.IndexParameters,
3022            using=using,
3023            columns=columns,
3024            include=include,
3025            partition_by=partition_by,
3026            where=where,
3027            with_storage=with_storage,
3028            tablespace=tablespace,
3029        )
3030
3031    def _parse_index(
3032        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3033    ) -> t.Optional[exp.Index]:
3034        if index or anonymous:
3035            unique = None
3036            primary = None
3037            amp = None
3038
3039            self._match(TokenType.ON)
3040            self._match(TokenType.TABLE)  # hive
3041            table = self._parse_table_parts(schema=True)
3042        else:
3043            unique = self._match(TokenType.UNIQUE)
3044            primary = self._match_text_seq("PRIMARY")
3045            amp = self._match_text_seq("AMP")
3046
3047            if not self._match(TokenType.INDEX):
3048                return None
3049
3050            index = self._parse_id_var()
3051            table = None
3052
3053        params = self._parse_index_params()
3054
3055        return self.expression(
3056            exp.Index,
3057            this=index,
3058            table=table,
3059            unique=unique,
3060            primary=primary,
3061            amp=amp,
3062            params=params,
3063        )
3064
3065    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3066        hints: t.List[exp.Expression] = []
3067        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3068            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3069            hints.append(
3070                self.expression(
3071                    exp.WithTableHint,
3072                    expressions=self._parse_csv(
3073                        lambda: self._parse_function() or self._parse_var(any_token=True)
3074                    ),
3075                )
3076            )
3077            self._match_r_paren()
3078        else:
3079            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3080            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3081                hint = exp.IndexTableHint(this=self._prev.text.upper())
3082
3083                self._match_texts(("INDEX", "KEY"))
3084                if self._match(TokenType.FOR):
3085                    hint.set("target", self._advance_any() and self._prev.text.upper())
3086
3087                hint.set("expressions", self._parse_wrapped_id_vars())
3088                hints.append(hint)
3089
3090        return hints or None
3091
3092    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3093        return (
3094            (not schema and self._parse_function(optional_parens=False))
3095            or self._parse_id_var(any_token=False)
3096            or self._parse_string_as_identifier()
3097            or self._parse_placeholder()
3098        )
3099
3100    def _parse_table_parts(
3101        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3102    ) -> exp.Table:
3103        catalog = None
3104        db = None
3105        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3106
3107        while self._match(TokenType.DOT):
3108            if catalog:
3109                # This allows nesting the table in arbitrarily many dot expressions if needed
3110                table = self.expression(
3111                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3112                )
3113            else:
3114                catalog = db
3115                db = table
3116                # "" used for tsql FROM a..b case
3117                table = self._parse_table_part(schema=schema) or ""
3118
3119        if (
3120            wildcard
3121            and self._is_connected()
3122            and (isinstance(table, exp.Identifier) or not table)
3123            and self._match(TokenType.STAR)
3124        ):
3125            if isinstance(table, exp.Identifier):
3126                table.args["this"] += "*"
3127            else:
3128                table = exp.Identifier(this="*")
3129
3130        # We bubble up comments from the Identifier to the Table
3131        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3132
3133        if is_db_reference:
3134            catalog = db
3135            db = table
3136            table = None
3137
3138        if not table and not is_db_reference:
3139            self.raise_error(f"Expected table name but got {self._curr}")
3140        if not db and is_db_reference:
3141            self.raise_error(f"Expected database name but got {self._curr}")
3142
3143        return self.expression(
3144            exp.Table,
3145            comments=comments,
3146            this=table,
3147            db=db,
3148            catalog=catalog,
3149            pivots=self._parse_pivots(),
3150        )
3151
3152    def _parse_table(
3153        self,
3154        schema: bool = False,
3155        joins: bool = False,
3156        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3157        parse_bracket: bool = False,
3158        is_db_reference: bool = False,
3159        parse_partition: bool = False,
3160    ) -> t.Optional[exp.Expression]:
3161        lateral = self._parse_lateral()
3162        if lateral:
3163            return lateral
3164
3165        unnest = self._parse_unnest()
3166        if unnest:
3167            return unnest
3168
3169        values = self._parse_derived_table_values()
3170        if values:
3171            return values
3172
3173        subquery = self._parse_select(table=True)
3174        if subquery:
3175            if not subquery.args.get("pivots"):
3176                subquery.set("pivots", self._parse_pivots())
3177            return subquery
3178
3179        bracket = parse_bracket and self._parse_bracket(None)
3180        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3181
3182        only = self._match(TokenType.ONLY)
3183
3184        this = t.cast(
3185            exp.Expression,
3186            bracket
3187            or self._parse_bracket(
3188                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3189            ),
3190        )
3191
3192        if only:
3193            this.set("only", only)
3194
3195        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3196        self._match_text_seq("*")
3197
3198        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3199        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3200            this.set("partition", self._parse_partition())
3201
3202        if schema:
3203            return self._parse_schema(this=this)
3204
3205        version = self._parse_version()
3206
3207        if version:
3208            this.set("version", version)
3209
3210        if self.dialect.ALIAS_POST_TABLESAMPLE:
3211            table_sample = self._parse_table_sample()
3212
3213        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3214        if alias:
3215            this.set("alias", alias)
3216
3217        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3218            return self.expression(
3219                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3220            )
3221
3222        this.set("hints", self._parse_table_hints())
3223
3224        if not this.args.get("pivots"):
3225            this.set("pivots", self._parse_pivots())
3226
3227        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3228            table_sample = self._parse_table_sample()
3229
3230        if table_sample:
3231            table_sample.set("this", this)
3232            this = table_sample
3233
3234        if joins:
3235            for join in self._parse_joins():
3236                this.append("joins", join)
3237
3238        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3239            this.set("ordinality", True)
3240            this.set("alias", self._parse_table_alias())
3241
3242        return this
3243
3244    def _parse_version(self) -> t.Optional[exp.Version]:
3245        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3246            this = "TIMESTAMP"
3247        elif self._match(TokenType.VERSION_SNAPSHOT):
3248            this = "VERSION"
3249        else:
3250            return None
3251
3252        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3253            kind = self._prev.text.upper()
3254            start = self._parse_bitwise()
3255            self._match_texts(("TO", "AND"))
3256            end = self._parse_bitwise()
3257            expression: t.Optional[exp.Expression] = self.expression(
3258                exp.Tuple, expressions=[start, end]
3259            )
3260        elif self._match_text_seq("CONTAINED", "IN"):
3261            kind = "CONTAINED IN"
3262            expression = self.expression(
3263                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3264            )
3265        elif self._match(TokenType.ALL):
3266            kind = "ALL"
3267            expression = None
3268        else:
3269            self._match_text_seq("AS", "OF")
3270            kind = "AS OF"
3271            expression = self._parse_type()
3272
3273        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3274
3275    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3276        if not self._match(TokenType.UNNEST):
3277            return None
3278
3279        expressions = self._parse_wrapped_csv(self._parse_equality)
3280        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3281
3282        alias = self._parse_table_alias() if with_alias else None
3283
3284        if alias:
3285            if self.dialect.UNNEST_COLUMN_ONLY:
3286                if alias.args.get("columns"):
3287                    self.raise_error("Unexpected extra column alias in unnest.")
3288
3289                alias.set("columns", [alias.this])
3290                alias.set("this", None)
3291
3292            columns = alias.args.get("columns") or []
3293            if offset and len(expressions) < len(columns):
3294                offset = columns.pop()
3295
3296        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3297            self._match(TokenType.ALIAS)
3298            offset = self._parse_id_var(
3299                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3300            ) or exp.to_identifier("offset")
3301
3302        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3303
3304    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3305        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3306        if not is_derived and not self._match_text_seq("VALUES"):
3307            return None
3308
3309        expressions = self._parse_csv(self._parse_value)
3310        alias = self._parse_table_alias()
3311
3312        if is_derived:
3313            self._match_r_paren()
3314
3315        return self.expression(
3316            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3317        )
3318
3319    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3320        if not self._match(TokenType.TABLE_SAMPLE) and not (
3321            as_modifier and self._match_text_seq("USING", "SAMPLE")
3322        ):
3323            return None
3324
3325        bucket_numerator = None
3326        bucket_denominator = None
3327        bucket_field = None
3328        percent = None
3329        size = None
3330        seed = None
3331
3332        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3333        matched_l_paren = self._match(TokenType.L_PAREN)
3334
3335        if self.TABLESAMPLE_CSV:
3336            num = None
3337            expressions = self._parse_csv(self._parse_primary)
3338        else:
3339            expressions = None
3340            num = (
3341                self._parse_factor()
3342                if self._match(TokenType.NUMBER, advance=False)
3343                else self._parse_primary() or self._parse_placeholder()
3344            )
3345
3346        if self._match_text_seq("BUCKET"):
3347            bucket_numerator = self._parse_number()
3348            self._match_text_seq("OUT", "OF")
3349            bucket_denominator = bucket_denominator = self._parse_number()
3350            self._match(TokenType.ON)
3351            bucket_field = self._parse_field()
3352        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3353            percent = num
3354        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3355            size = num
3356        else:
3357            percent = num
3358
3359        if matched_l_paren:
3360            self._match_r_paren()
3361
3362        if self._match(TokenType.L_PAREN):
3363            method = self._parse_var(upper=True)
3364            seed = self._match(TokenType.COMMA) and self._parse_number()
3365            self._match_r_paren()
3366        elif self._match_texts(("SEED", "REPEATABLE")):
3367            seed = self._parse_wrapped(self._parse_number)
3368
3369        return self.expression(
3370            exp.TableSample,
3371            expressions=expressions,
3372            method=method,
3373            bucket_numerator=bucket_numerator,
3374            bucket_denominator=bucket_denominator,
3375            bucket_field=bucket_field,
3376            percent=percent,
3377            size=size,
3378            seed=seed,
3379        )
3380
3381    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3382        return list(iter(self._parse_pivot, None)) or None
3383
3384    def _parse_joins(self) -> t.Iterator[exp.Join]:
3385        return iter(self._parse_join, None)
3386
3387    # https://duckdb.org/docs/sql/statements/pivot
3388    def _parse_simplified_pivot(self) -> exp.Pivot:
3389        def _parse_on() -> t.Optional[exp.Expression]:
3390            this = self._parse_bitwise()
3391            return self._parse_in(this) if self._match(TokenType.IN) else this
3392
3393        this = self._parse_table()
3394        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3395        using = self._match(TokenType.USING) and self._parse_csv(
3396            lambda: self._parse_alias(self._parse_function())
3397        )
3398        group = self._parse_group()
3399        return self.expression(
3400            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3401        )
3402
3403    def _parse_pivot_in(self) -> exp.In:
3404        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3405            this = self._parse_conjunction()
3406
3407            self._match(TokenType.ALIAS)
3408            alias = self._parse_field()
3409            if alias:
3410                return self.expression(exp.PivotAlias, this=this, alias=alias)
3411
3412            return this
3413
3414        value = self._parse_column()
3415
3416        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3417            self.raise_error("Expecting IN (")
3418
3419        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3420
3421        self._match_r_paren()
3422        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3423
3424    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3425        index = self._index
3426        include_nulls = None
3427
3428        if self._match(TokenType.PIVOT):
3429            unpivot = False
3430        elif self._match(TokenType.UNPIVOT):
3431            unpivot = True
3432
3433            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3434            if self._match_text_seq("INCLUDE", "NULLS"):
3435                include_nulls = True
3436            elif self._match_text_seq("EXCLUDE", "NULLS"):
3437                include_nulls = False
3438        else:
3439            return None
3440
3441        expressions = []
3442
3443        if not self._match(TokenType.L_PAREN):
3444            self._retreat(index)
3445            return None
3446
3447        if unpivot:
3448            expressions = self._parse_csv(self._parse_column)
3449        else:
3450            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3451
3452        if not expressions:
3453            self.raise_error("Failed to parse PIVOT's aggregation list")
3454
3455        if not self._match(TokenType.FOR):
3456            self.raise_error("Expecting FOR")
3457
3458        field = self._parse_pivot_in()
3459
3460        self._match_r_paren()
3461
3462        pivot = self.expression(
3463            exp.Pivot,
3464            expressions=expressions,
3465            field=field,
3466            unpivot=unpivot,
3467            include_nulls=include_nulls,
3468        )
3469
3470        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3471            pivot.set("alias", self._parse_table_alias())
3472
3473        if not unpivot:
3474            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3475
3476            columns: t.List[exp.Expression] = []
3477            for fld in pivot.args["field"].expressions:
3478                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3479                for name in names:
3480                    if self.PREFIXED_PIVOT_COLUMNS:
3481                        name = f"{name}_{field_name}" if name else field_name
3482                    else:
3483                        name = f"{field_name}_{name}" if name else field_name
3484
3485                    columns.append(exp.to_identifier(name))
3486
3487            pivot.set("columns", columns)
3488
3489        return pivot
3490
3491    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3492        return [agg.alias for agg in aggregations]
3493
3494    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3495        if not skip_where_token and not self._match(TokenType.PREWHERE):
3496            return None
3497
3498        return self.expression(
3499            exp.PreWhere, comments=self._prev_comments, this=self._parse_conjunction()
3500        )
3501
3502    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3503        if not skip_where_token and not self._match(TokenType.WHERE):
3504            return None
3505
3506        return self.expression(
3507            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3508        )
3509
3510    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3511        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3512            return None
3513
3514        elements: t.Dict[str, t.Any] = defaultdict(list)
3515
3516        if self._match(TokenType.ALL):
3517            elements["all"] = True
3518        elif self._match(TokenType.DISTINCT):
3519            elements["all"] = False
3520
3521        while True:
3522            expressions = self._parse_csv(self._parse_conjunction)
3523            if expressions:
3524                elements["expressions"].extend(expressions)
3525
3526            grouping_sets = self._parse_grouping_sets()
3527            if grouping_sets:
3528                elements["grouping_sets"].extend(grouping_sets)
3529
3530            rollup = None
3531            cube = None
3532            totals = None
3533
3534            index = self._index
3535            with_ = self._match(TokenType.WITH)
3536            if self._match(TokenType.ROLLUP):
3537                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3538                elements["rollup"].extend(ensure_list(rollup))
3539
3540            if self._match(TokenType.CUBE):
3541                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3542                elements["cube"].extend(ensure_list(cube))
3543
3544            if self._match_text_seq("TOTALS"):
3545                totals = True
3546                elements["totals"] = True  # type: ignore
3547
3548            if not (grouping_sets or rollup or cube or totals):
3549                if with_:
3550                    self._retreat(index)
3551                break
3552
3553        return self.expression(exp.Group, **elements)  # type: ignore
3554
3555    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3556        if not self._match(TokenType.GROUPING_SETS):
3557            return None
3558
3559        return self._parse_wrapped_csv(self._parse_grouping_set)
3560
3561    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3562        if self._match(TokenType.L_PAREN):
3563            grouping_set = self._parse_csv(self._parse_column)
3564            self._match_r_paren()
3565            return self.expression(exp.Tuple, expressions=grouping_set)
3566
3567        return self._parse_column()
3568
3569    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3570        if not skip_having_token and not self._match(TokenType.HAVING):
3571            return None
3572        return self.expression(exp.Having, this=self._parse_conjunction())
3573
3574    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3575        if not self._match(TokenType.QUALIFY):
3576            return None
3577        return self.expression(exp.Qualify, this=self._parse_conjunction())
3578
3579    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3580        if skip_start_token:
3581            start = None
3582        elif self._match(TokenType.START_WITH):
3583            start = self._parse_conjunction()
3584        else:
3585            return None
3586
3587        self._match(TokenType.CONNECT_BY)
3588        nocycle = self._match_text_seq("NOCYCLE")
3589        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3590            exp.Prior, this=self._parse_bitwise()
3591        )
3592        connect = self._parse_conjunction()
3593        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3594
3595        if not start and self._match(TokenType.START_WITH):
3596            start = self._parse_conjunction()
3597
3598        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3599
3600    def _parse_name_as_expression(self) -> exp.Alias:
3601        return self.expression(
3602            exp.Alias,
3603            alias=self._parse_id_var(any_token=True),
3604            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3605        )
3606
3607    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3608        if self._match_text_seq("INTERPOLATE"):
3609            return self._parse_wrapped_csv(self._parse_name_as_expression)
3610        return None
3611
3612    def _parse_order(
3613        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3614    ) -> t.Optional[exp.Expression]:
3615        siblings = None
3616        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3617            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3618                return this
3619
3620            siblings = True
3621
3622        return self.expression(
3623            exp.Order,
3624            this=this,
3625            expressions=self._parse_csv(self._parse_ordered),
3626            interpolate=self._parse_interpolate(),
3627            siblings=siblings,
3628        )
3629
3630    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3631        if not self._match(token):
3632            return None
3633        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3634
3635    def _parse_ordered(
3636        self, parse_method: t.Optional[t.Callable] = None
3637    ) -> t.Optional[exp.Ordered]:
3638        this = parse_method() if parse_method else self._parse_conjunction()
3639        if not this:
3640            return None
3641
3642        asc = self._match(TokenType.ASC)
3643        desc = self._match(TokenType.DESC) or (asc and False)
3644
3645        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3646        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3647
3648        nulls_first = is_nulls_first or False
3649        explicitly_null_ordered = is_nulls_first or is_nulls_last
3650
3651        if (
3652            not explicitly_null_ordered
3653            and (
3654                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3655                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3656            )
3657            and self.dialect.NULL_ORDERING != "nulls_are_last"
3658        ):
3659            nulls_first = True
3660
3661        if self._match_text_seq("WITH", "FILL"):
3662            with_fill = self.expression(
3663                exp.WithFill,
3664                **{  # type: ignore
3665                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3666                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3667                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3668                },
3669            )
3670        else:
3671            with_fill = None
3672
3673        return self.expression(
3674            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3675        )
3676
3677    def _parse_limit(
3678        self,
3679        this: t.Optional[exp.Expression] = None,
3680        top: bool = False,
3681        skip_limit_token: bool = False,
3682    ) -> t.Optional[exp.Expression]:
3683        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3684            comments = self._prev_comments
3685            if top:
3686                limit_paren = self._match(TokenType.L_PAREN)
3687                expression = self._parse_term() if limit_paren else self._parse_number()
3688
3689                if limit_paren:
3690                    self._match_r_paren()
3691            else:
3692                expression = self._parse_term()
3693
3694            if self._match(TokenType.COMMA):
3695                offset = expression
3696                expression = self._parse_term()
3697            else:
3698                offset = None
3699
3700            limit_exp = self.expression(
3701                exp.Limit,
3702                this=this,
3703                expression=expression,
3704                offset=offset,
3705                comments=comments,
3706                expressions=self._parse_limit_by(),
3707            )
3708
3709            return limit_exp
3710
3711        if self._match(TokenType.FETCH):
3712            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3713            direction = self._prev.text.upper() if direction else "FIRST"
3714
3715            count = self._parse_field(tokens=self.FETCH_TOKENS)
3716            percent = self._match(TokenType.PERCENT)
3717
3718            self._match_set((TokenType.ROW, TokenType.ROWS))
3719
3720            only = self._match_text_seq("ONLY")
3721            with_ties = self._match_text_seq("WITH", "TIES")
3722
3723            if only and with_ties:
3724                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3725
3726            return self.expression(
3727                exp.Fetch,
3728                direction=direction,
3729                count=count,
3730                percent=percent,
3731                with_ties=with_ties,
3732            )
3733
3734        return this
3735
3736    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3737        if not self._match(TokenType.OFFSET):
3738            return this
3739
3740        count = self._parse_term()
3741        self._match_set((TokenType.ROW, TokenType.ROWS))
3742
3743        return self.expression(
3744            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
3745        )
3746
3747    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
3748        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
3749
3750    def _parse_locks(self) -> t.List[exp.Lock]:
3751        locks = []
3752        while True:
3753            if self._match_text_seq("FOR", "UPDATE"):
3754                update = True
3755            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3756                "LOCK", "IN", "SHARE", "MODE"
3757            ):
3758                update = False
3759            else:
3760                break
3761
3762            expressions = None
3763            if self._match_text_seq("OF"):
3764                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3765
3766            wait: t.Optional[bool | exp.Expression] = None
3767            if self._match_text_seq("NOWAIT"):
3768                wait = True
3769            elif self._match_text_seq("WAIT"):
3770                wait = self._parse_primary()
3771            elif self._match_text_seq("SKIP", "LOCKED"):
3772                wait = False
3773
3774            locks.append(
3775                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3776            )
3777
3778        return locks
3779
3780    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3781        while this and self._match_set(self.SET_OPERATIONS):
3782            token_type = self._prev.token_type
3783
3784            if token_type == TokenType.UNION:
3785                operation = exp.Union
3786            elif token_type == TokenType.EXCEPT:
3787                operation = exp.Except
3788            else:
3789                operation = exp.Intersect
3790
3791            comments = self._prev.comments
3792            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3793            by_name = self._match_text_seq("BY", "NAME")
3794            expression = self._parse_select(nested=True, parse_set_operation=False)
3795
3796            this = self.expression(
3797                operation,
3798                comments=comments,
3799                this=this,
3800                distinct=distinct,
3801                by_name=by_name,
3802                expression=expression,
3803            )
3804
3805        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3806            expression = this.expression
3807
3808            if expression:
3809                for arg in self.UNION_MODIFIERS:
3810                    expr = expression.args.get(arg)
3811                    if expr:
3812                        this.set(arg, expr.pop())
3813
3814        return this
3815
3816    def _parse_expression(self) -> t.Optional[exp.Expression]:
3817        return self._parse_alias(self._parse_conjunction())
3818
3819    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3820        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3821
3822    def _parse_equality(self) -> t.Optional[exp.Expression]:
3823        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3824
3825    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3826        return self._parse_tokens(self._parse_range, self.COMPARISON)
3827
3828    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3829        this = this or self._parse_bitwise()
3830        negate = self._match(TokenType.NOT)
3831
3832        if self._match_set(self.RANGE_PARSERS):
3833            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3834            if not expression:
3835                return this
3836
3837            this = expression
3838        elif self._match(TokenType.ISNULL):
3839            this = self.expression(exp.Is, this=this, expression=exp.Null())
3840
3841        # Postgres supports ISNULL and NOTNULL for conditions.
3842        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3843        if self._match(TokenType.NOTNULL):
3844            this = self.expression(exp.Is, this=this, expression=exp.Null())
3845            this = self.expression(exp.Not, this=this)
3846
3847        if negate:
3848            this = self.expression(exp.Not, this=this)
3849
3850        if self._match(TokenType.IS):
3851            this = self._parse_is(this)
3852
3853        return this
3854
3855    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3856        index = self._index - 1
3857        negate = self._match(TokenType.NOT)
3858
3859        if self._match_text_seq("DISTINCT", "FROM"):
3860            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3861            return self.expression(klass, this=this, expression=self._parse_bitwise())
3862
3863        expression = self._parse_null() or self._parse_boolean()
3864        if not expression:
3865            self._retreat(index)
3866            return None
3867
3868        this = self.expression(exp.Is, this=this, expression=expression)
3869        return self.expression(exp.Not, this=this) if negate else this
3870
3871    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3872        unnest = self._parse_unnest(with_alias=False)
3873        if unnest:
3874            this = self.expression(exp.In, this=this, unnest=unnest)
3875        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3876            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3877            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3878
3879            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
3880                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
3881            else:
3882                this = self.expression(exp.In, this=this, expressions=expressions)
3883
3884            if matched_l_paren:
3885                self._match_r_paren(this)
3886            elif not self._match(TokenType.R_BRACKET, expression=this):
3887                self.raise_error("Expecting ]")
3888        else:
3889            this = self.expression(exp.In, this=this, field=self._parse_field())
3890
3891        return this
3892
3893    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3894        low = self._parse_bitwise()
3895        self._match(TokenType.AND)
3896        high = self._parse_bitwise()
3897        return self.expression(exp.Between, this=this, low=low, high=high)
3898
3899    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3900        if not self._match(TokenType.ESCAPE):
3901            return this
3902        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3903
3904    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3905        index = self._index
3906
3907        if not self._match(TokenType.INTERVAL) and match_interval:
3908            return None
3909
3910        if self._match(TokenType.STRING, advance=False):
3911            this = self._parse_primary()
3912        else:
3913            this = self._parse_term()
3914
3915        if not this or (
3916            isinstance(this, exp.Column)
3917            and not this.table
3918            and not this.this.quoted
3919            and this.name.upper() == "IS"
3920        ):
3921            self._retreat(index)
3922            return None
3923
3924        unit = self._parse_function() or (
3925            not self._match(TokenType.ALIAS, advance=False)
3926            and self._parse_var(any_token=True, upper=True)
3927        )
3928
3929        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3930        # each INTERVAL expression into this canonical form so it's easy to transpile
3931        if this and this.is_number:
3932            this = exp.Literal.string(this.name)
3933        elif this and this.is_string:
3934            parts = this.name.split()
3935
3936            if len(parts) == 2:
3937                if unit:
3938                    # This is not actually a unit, it's something else (e.g. a "window side")
3939                    unit = None
3940                    self._retreat(self._index - 1)
3941
3942                this = exp.Literal.string(parts[0])
3943                unit = self.expression(exp.Var, this=parts[1].upper())
3944
3945        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
3946            unit = self.expression(
3947                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
3948            )
3949
3950        return self.expression(exp.Interval, this=this, unit=unit)
3951
3952    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3953        this = self._parse_term()
3954
3955        while True:
3956            if self._match_set(self.BITWISE):
3957                this = self.expression(
3958                    self.BITWISE[self._prev.token_type],
3959                    this=this,
3960                    expression=self._parse_term(),
3961                )
3962            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3963                this = self.expression(
3964                    exp.DPipe,
3965                    this=this,
3966                    expression=self._parse_term(),
3967                    safe=not self.dialect.STRICT_STRING_CONCAT,
3968                )
3969            elif self._match(TokenType.DQMARK):
3970                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3971            elif self._match_pair(TokenType.LT, TokenType.LT):
3972                this = self.expression(
3973                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3974                )
3975            elif self._match_pair(TokenType.GT, TokenType.GT):
3976                this = self.expression(
3977                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3978                )
3979            else:
3980                break
3981
3982        return this
3983
3984    def _parse_term(self) -> t.Optional[exp.Expression]:
3985        return self._parse_tokens(self._parse_factor, self.TERM)
3986
3987    def _parse_factor(self) -> t.Optional[exp.Expression]:
3988        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
3989        this = parse_method()
3990
3991        while self._match_set(self.FACTOR):
3992            this = self.expression(
3993                self.FACTOR[self._prev.token_type],
3994                this=this,
3995                comments=self._prev_comments,
3996                expression=parse_method(),
3997            )
3998            if isinstance(this, exp.Div):
3999                this.args["typed"] = self.dialect.TYPED_DIVISION
4000                this.args["safe"] = self.dialect.SAFE_DIVISION
4001
4002        return this
4003
4004    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4005        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4006
4007    def _parse_unary(self) -> t.Optional[exp.Expression]:
4008        if self._match_set(self.UNARY_PARSERS):
4009            return self.UNARY_PARSERS[self._prev.token_type](self)
4010        return self._parse_at_time_zone(self._parse_type())
4011
4012    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
4013        interval = parse_interval and self._parse_interval()
4014        if interval:
4015            # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4016            while True:
4017                index = self._index
4018                self._match(TokenType.PLUS)
4019
4020                if not self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4021                    self._retreat(index)
4022                    break
4023
4024                interval = self.expression(  # type: ignore
4025                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4026                )
4027
4028            return interval
4029
4030        index = self._index
4031        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4032        this = self._parse_column()
4033
4034        if data_type:
4035            if isinstance(this, exp.Literal):
4036                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4037                if parser:
4038                    return parser(self, this, data_type)
4039                return self.expression(exp.Cast, this=this, to=data_type)
4040            if not data_type.expressions:
4041                self._retreat(index)
4042                return self._parse_column()
4043            return self._parse_column_ops(data_type)
4044
4045        return this and self._parse_column_ops(this)
4046
4047    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4048        this = self._parse_type()
4049        if not this:
4050            return None
4051
4052        if isinstance(this, exp.Column) and not this.table:
4053            this = exp.var(this.name.upper())
4054
4055        return self.expression(
4056            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4057        )
4058
4059    def _parse_types(
4060        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4061    ) -> t.Optional[exp.Expression]:
4062        index = self._index
4063
4064        prefix = self._match_text_seq("SYSUDTLIB", ".")
4065
4066        if not self._match_set(self.TYPE_TOKENS):
4067            identifier = allow_identifiers and self._parse_id_var(
4068                any_token=False, tokens=(TokenType.VAR,)
4069            )
4070            if identifier:
4071                tokens = self.dialect.tokenize(identifier.name)
4072
4073                if len(tokens) != 1:
4074                    self.raise_error("Unexpected identifier", self._prev)
4075
4076                if tokens[0].token_type in self.TYPE_TOKENS:
4077                    self._prev = tokens[0]
4078                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4079                    type_name = identifier.name
4080
4081                    while self._match(TokenType.DOT):
4082                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4083
4084                    return exp.DataType.build(type_name, udt=True)
4085                else:
4086                    self._retreat(self._index - 1)
4087                    return None
4088            else:
4089                return None
4090
4091        type_token = self._prev.token_type
4092
4093        if type_token == TokenType.PSEUDO_TYPE:
4094            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4095
4096        if type_token == TokenType.OBJECT_IDENTIFIER:
4097            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4098
4099        nested = type_token in self.NESTED_TYPE_TOKENS
4100        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4101        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4102        expressions = None
4103        maybe_func = False
4104
4105        if self._match(TokenType.L_PAREN):
4106            if is_struct:
4107                expressions = self._parse_csv(self._parse_struct_types)
4108            elif nested:
4109                expressions = self._parse_csv(
4110                    lambda: self._parse_types(
4111                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4112                    )
4113                )
4114            elif type_token in self.ENUM_TYPE_TOKENS:
4115                expressions = self._parse_csv(self._parse_equality)
4116            elif is_aggregate:
4117                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4118                    any_token=False, tokens=(TokenType.VAR,)
4119                )
4120                if not func_or_ident or not self._match(TokenType.COMMA):
4121                    return None
4122                expressions = self._parse_csv(
4123                    lambda: self._parse_types(
4124                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4125                    )
4126                )
4127                expressions.insert(0, func_or_ident)
4128            else:
4129                expressions = self._parse_csv(self._parse_type_size)
4130
4131            if not expressions or not self._match(TokenType.R_PAREN):
4132                self._retreat(index)
4133                return None
4134
4135            maybe_func = True
4136
4137        this: t.Optional[exp.Expression] = None
4138        values: t.Optional[t.List[exp.Expression]] = None
4139
4140        if nested and self._match(TokenType.LT):
4141            if is_struct:
4142                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4143            else:
4144                expressions = self._parse_csv(
4145                    lambda: self._parse_types(
4146                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4147                    )
4148                )
4149
4150            if not self._match(TokenType.GT):
4151                self.raise_error("Expecting >")
4152
4153            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4154                values = self._parse_csv(self._parse_conjunction)
4155                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4156
4157        if type_token in self.TIMESTAMPS:
4158            if self._match_text_seq("WITH", "TIME", "ZONE"):
4159                maybe_func = False
4160                tz_type = (
4161                    exp.DataType.Type.TIMETZ
4162                    if type_token in self.TIMES
4163                    else exp.DataType.Type.TIMESTAMPTZ
4164                )
4165                this = exp.DataType(this=tz_type, expressions=expressions)
4166            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4167                maybe_func = False
4168                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4169            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4170                maybe_func = False
4171        elif type_token == TokenType.INTERVAL:
4172            unit = self._parse_var(upper=True)
4173            if unit:
4174                if self._match_text_seq("TO"):
4175                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4176
4177                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4178            else:
4179                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4180
4181        if maybe_func and check_func:
4182            index2 = self._index
4183            peek = self._parse_string()
4184
4185            if not peek:
4186                self._retreat(index)
4187                return None
4188
4189            self._retreat(index2)
4190
4191        if not this:
4192            if self._match_text_seq("UNSIGNED"):
4193                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4194                if not unsigned_type_token:
4195                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4196
4197                type_token = unsigned_type_token or type_token
4198
4199            this = exp.DataType(
4200                this=exp.DataType.Type[type_token.value],
4201                expressions=expressions,
4202                nested=nested,
4203                values=values,
4204                prefix=prefix,
4205            )
4206
4207        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
4208            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
4209
4210        return this
4211
4212    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4213        index = self._index
4214        this = self._parse_type(parse_interval=False) or self._parse_id_var()
4215        self._match(TokenType.COLON)
4216        column_def = self._parse_column_def(this)
4217
4218        if type_required and (
4219            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
4220        ):
4221            self._retreat(index)
4222            return self._parse_types()
4223
4224        return column_def
4225
4226    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4227        if not self._match_text_seq("AT", "TIME", "ZONE"):
4228            return this
4229        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4230
4231    def _parse_column(self) -> t.Optional[exp.Expression]:
4232        this = self._parse_column_reference()
4233        return self._parse_column_ops(this) if this else self._parse_bracket(this)
4234
4235    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4236        this = self._parse_field()
4237        if (
4238            not this
4239            and self._match(TokenType.VALUES, advance=False)
4240            and self.VALUES_FOLLOWED_BY_PAREN
4241            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4242        ):
4243            this = self._parse_id_var()
4244
4245        if isinstance(this, exp.Identifier):
4246            # We bubble up comments from the Identifier to the Column
4247            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4248
4249        return this
4250
4251    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4252        this = self._parse_bracket(this)
4253
4254        while self._match_set(self.COLUMN_OPERATORS):
4255            op_token = self._prev.token_type
4256            op = self.COLUMN_OPERATORS.get(op_token)
4257
4258            if op_token == TokenType.DCOLON:
4259                field = self._parse_types()
4260                if not field:
4261                    self.raise_error("Expected type")
4262            elif op and self._curr:
4263                field = self._parse_column_reference()
4264            else:
4265                field = self._parse_field(any_token=True, anonymous_func=True)
4266
4267            if isinstance(field, exp.Func) and this:
4268                # bigquery allows function calls like x.y.count(...)
4269                # SAFE.SUBSTR(...)
4270                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4271                this = exp.replace_tree(
4272                    this,
4273                    lambda n: (
4274                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4275                        if n.table
4276                        else n.this
4277                    )
4278                    if isinstance(n, exp.Column)
4279                    else n,
4280                )
4281
4282            if op:
4283                this = op(self, this, field)
4284            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4285                this = self.expression(
4286                    exp.Column,
4287                    this=field,
4288                    table=this.this,
4289                    db=this.args.get("table"),
4290                    catalog=this.args.get("db"),
4291                )
4292            else:
4293                this = self.expression(exp.Dot, this=this, expression=field)
4294            this = self._parse_bracket(this)
4295        return this
4296
4297    def _parse_primary(self) -> t.Optional[exp.Expression]:
4298        if self._match_set(self.PRIMARY_PARSERS):
4299            token_type = self._prev.token_type
4300            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4301
4302            if token_type == TokenType.STRING:
4303                expressions = [primary]
4304                while self._match(TokenType.STRING):
4305                    expressions.append(exp.Literal.string(self._prev.text))
4306
4307                if len(expressions) > 1:
4308                    return self.expression(exp.Concat, expressions=expressions)
4309
4310            return primary
4311
4312        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4313            return exp.Literal.number(f"0.{self._prev.text}")
4314
4315        if self._match(TokenType.L_PAREN):
4316            comments = self._prev_comments
4317            query = self._parse_select()
4318
4319            if query:
4320                expressions = [query]
4321            else:
4322                expressions = self._parse_expressions()
4323
4324            this = self._parse_query_modifiers(seq_get(expressions, 0))
4325
4326            if not this and self._match(TokenType.R_PAREN, advance=False):
4327                this = self.expression(exp.Tuple)
4328            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4329                this = self._parse_set_operations(
4330                    self._parse_subquery(this=this, parse_alias=False)
4331                )
4332            elif isinstance(this, exp.Subquery):
4333                this = self._parse_subquery(
4334                    this=self._parse_set_operations(this), parse_alias=False
4335                )
4336            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4337                this = self.expression(exp.Tuple, expressions=expressions)
4338            else:
4339                this = self.expression(exp.Paren, this=this)
4340
4341            if this:
4342                this.add_comments(comments)
4343
4344            self._match_r_paren(expression=this)
4345            return this
4346
4347        return None
4348
4349    def _parse_field(
4350        self,
4351        any_token: bool = False,
4352        tokens: t.Optional[t.Collection[TokenType]] = None,
4353        anonymous_func: bool = False,
4354    ) -> t.Optional[exp.Expression]:
4355        if anonymous_func:
4356            field = (
4357                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4358                or self._parse_primary()
4359            )
4360        else:
4361            field = self._parse_primary() or self._parse_function(
4362                anonymous=anonymous_func, any_token=any_token
4363            )
4364        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4365
4366    def _parse_function(
4367        self,
4368        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4369        anonymous: bool = False,
4370        optional_parens: bool = True,
4371        any_token: bool = False,
4372    ) -> t.Optional[exp.Expression]:
4373        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4374        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4375        fn_syntax = False
4376        if (
4377            self._match(TokenType.L_BRACE, advance=False)
4378            and self._next
4379            and self._next.text.upper() == "FN"
4380        ):
4381            self._advance(2)
4382            fn_syntax = True
4383
4384        func = self._parse_function_call(
4385            functions=functions,
4386            anonymous=anonymous,
4387            optional_parens=optional_parens,
4388            any_token=any_token,
4389        )
4390
4391        if fn_syntax:
4392            self._match(TokenType.R_BRACE)
4393
4394        return func
4395
4396    def _parse_function_call(
4397        self,
4398        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4399        anonymous: bool = False,
4400        optional_parens: bool = True,
4401        any_token: bool = False,
4402    ) -> t.Optional[exp.Expression]:
4403        if not self._curr:
4404            return None
4405
4406        comments = self._curr.comments
4407        token_type = self._curr.token_type
4408        this = self._curr.text
4409        upper = this.upper()
4410
4411        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4412        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4413            self._advance()
4414            return self._parse_window(parser(self))
4415
4416        if not self._next or self._next.token_type != TokenType.L_PAREN:
4417            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4418                self._advance()
4419                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4420
4421            return None
4422
4423        if any_token:
4424            if token_type in self.RESERVED_TOKENS:
4425                return None
4426        elif token_type not in self.FUNC_TOKENS:
4427            return None
4428
4429        self._advance(2)
4430
4431        parser = self.FUNCTION_PARSERS.get(upper)
4432        if parser and not anonymous:
4433            this = parser(self)
4434        else:
4435            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4436
4437            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4438                this = self.expression(subquery_predicate, this=self._parse_select())
4439                self._match_r_paren()
4440                return this
4441
4442            if functions is None:
4443                functions = self.FUNCTIONS
4444
4445            function = functions.get(upper)
4446
4447            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4448            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4449
4450            if alias:
4451                args = self._kv_to_prop_eq(args)
4452
4453            if function and not anonymous:
4454                if "dialect" in function.__code__.co_varnames:
4455                    func = function(args, dialect=self.dialect)
4456                else:
4457                    func = function(args)
4458
4459                func = self.validate_expression(func, args)
4460                if not self.dialect.NORMALIZE_FUNCTIONS:
4461                    func.meta["name"] = this
4462
4463                this = func
4464            else:
4465                if token_type == TokenType.IDENTIFIER:
4466                    this = exp.Identifier(this=this, quoted=True)
4467                this = self.expression(exp.Anonymous, this=this, expressions=args)
4468
4469        if isinstance(this, exp.Expression):
4470            this.add_comments(comments)
4471
4472        self._match_r_paren(this)
4473        return self._parse_window(this)
4474
4475    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4476        transformed = []
4477
4478        for e in expressions:
4479            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4480                if isinstance(e, exp.Alias):
4481                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4482
4483                if not isinstance(e, exp.PropertyEQ):
4484                    e = self.expression(
4485                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4486                    )
4487
4488                if isinstance(e.this, exp.Column):
4489                    e.this.replace(e.this.this)
4490
4491            transformed.append(e)
4492
4493        return transformed
4494
4495    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4496        return self._parse_column_def(self._parse_id_var())
4497
4498    def _parse_user_defined_function(
4499        self, kind: t.Optional[TokenType] = None
4500    ) -> t.Optional[exp.Expression]:
4501        this = self._parse_id_var()
4502
4503        while self._match(TokenType.DOT):
4504            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4505
4506        if not self._match(TokenType.L_PAREN):
4507            return this
4508
4509        expressions = self._parse_csv(self._parse_function_parameter)
4510        self._match_r_paren()
4511        return self.expression(
4512            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4513        )
4514
4515    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4516        literal = self._parse_primary()
4517        if literal:
4518            return self.expression(exp.Introducer, this=token.text, expression=literal)
4519
4520        return self.expression(exp.Identifier, this=token.text)
4521
4522    def _parse_session_parameter(self) -> exp.SessionParameter:
4523        kind = None
4524        this = self._parse_id_var() or self._parse_primary()
4525
4526        if this and self._match(TokenType.DOT):
4527            kind = this.name
4528            this = self._parse_var() or self._parse_primary()
4529
4530        return self.expression(exp.SessionParameter, this=this, kind=kind)
4531
4532    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4533        index = self._index
4534
4535        if self._match(TokenType.L_PAREN):
4536            expressions = t.cast(
4537                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4538            )
4539
4540            if not self._match(TokenType.R_PAREN):
4541                self._retreat(index)
4542        else:
4543            expressions = [self._parse_id_var()]
4544
4545        if self._match_set(self.LAMBDAS):
4546            return self.LAMBDAS[self._prev.token_type](self, expressions)
4547
4548        self._retreat(index)
4549
4550        this: t.Optional[exp.Expression]
4551
4552        if self._match(TokenType.DISTINCT):
4553            this = self.expression(
4554                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4555            )
4556        else:
4557            this = self._parse_select_or_expression(alias=alias)
4558
4559        return self._parse_limit(
4560            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
4561        )
4562
4563    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4564        index = self._index
4565        if not self._match(TokenType.L_PAREN):
4566            return this
4567
4568        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
4569        # expr can be of both types
4570        if self._match_set(self.SELECT_START_TOKENS):
4571            self._retreat(index)
4572            return this
4573        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4574        self._match_r_paren()
4575        return self.expression(exp.Schema, this=this, expressions=args)
4576
4577    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4578        return self._parse_column_def(self._parse_field(any_token=True))
4579
4580    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4581        # column defs are not really columns, they're identifiers
4582        if isinstance(this, exp.Column):
4583            this = this.this
4584
4585        kind = self._parse_types(schema=True)
4586
4587        if self._match_text_seq("FOR", "ORDINALITY"):
4588            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4589
4590        constraints: t.List[exp.Expression] = []
4591
4592        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
4593            ("ALIAS", "MATERIALIZED")
4594        ):
4595            persisted = self._prev.text.upper() == "MATERIALIZED"
4596            constraints.append(
4597                self.expression(
4598                    exp.ComputedColumnConstraint,
4599                    this=self._parse_conjunction(),
4600                    persisted=persisted or self._match_text_seq("PERSISTED"),
4601                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4602                )
4603            )
4604        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4605            self._match(TokenType.ALIAS)
4606            constraints.append(
4607                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4608            )
4609
4610        while True:
4611            constraint = self._parse_column_constraint()
4612            if not constraint:
4613                break
4614            constraints.append(constraint)
4615
4616        if not kind and not constraints:
4617            return this
4618
4619        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4620
4621    def _parse_auto_increment(
4622        self,
4623    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4624        start = None
4625        increment = None
4626
4627        if self._match(TokenType.L_PAREN, advance=False):
4628            args = self._parse_wrapped_csv(self._parse_bitwise)
4629            start = seq_get(args, 0)
4630            increment = seq_get(args, 1)
4631        elif self._match_text_seq("START"):
4632            start = self._parse_bitwise()
4633            self._match_text_seq("INCREMENT")
4634            increment = self._parse_bitwise()
4635
4636        if start and increment:
4637            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4638
4639        return exp.AutoIncrementColumnConstraint()
4640
4641    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4642        if not self._match_text_seq("REFRESH"):
4643            self._retreat(self._index - 1)
4644            return None
4645        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4646
4647    def _parse_compress(self) -> exp.CompressColumnConstraint:
4648        if self._match(TokenType.L_PAREN, advance=False):
4649            return self.expression(
4650                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4651            )
4652
4653        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4654
4655    def _parse_generated_as_identity(
4656        self,
4657    ) -> (
4658        exp.GeneratedAsIdentityColumnConstraint
4659        | exp.ComputedColumnConstraint
4660        | exp.GeneratedAsRowColumnConstraint
4661    ):
4662        if self._match_text_seq("BY", "DEFAULT"):
4663            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4664            this = self.expression(
4665                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4666            )
4667        else:
4668            self._match_text_seq("ALWAYS")
4669            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4670
4671        self._match(TokenType.ALIAS)
4672
4673        if self._match_text_seq("ROW"):
4674            start = self._match_text_seq("START")
4675            if not start:
4676                self._match(TokenType.END)
4677            hidden = self._match_text_seq("HIDDEN")
4678            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4679
4680        identity = self._match_text_seq("IDENTITY")
4681
4682        if self._match(TokenType.L_PAREN):
4683            if self._match(TokenType.START_WITH):
4684                this.set("start", self._parse_bitwise())
4685            if self._match_text_seq("INCREMENT", "BY"):
4686                this.set("increment", self._parse_bitwise())
4687            if self._match_text_seq("MINVALUE"):
4688                this.set("minvalue", self._parse_bitwise())
4689            if self._match_text_seq("MAXVALUE"):
4690                this.set("maxvalue", self._parse_bitwise())
4691
4692            if self._match_text_seq("CYCLE"):
4693                this.set("cycle", True)
4694            elif self._match_text_seq("NO", "CYCLE"):
4695                this.set("cycle", False)
4696
4697            if not identity:
4698                this.set("expression", self._parse_range())
4699            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4700                args = self._parse_csv(self._parse_bitwise)
4701                this.set("start", seq_get(args, 0))
4702                this.set("increment", seq_get(args, 1))
4703
4704            self._match_r_paren()
4705
4706        return this
4707
4708    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4709        self._match_text_seq("LENGTH")
4710        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4711
4712    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
4713        if self._match_text_seq("NULL"):
4714            return self.expression(exp.NotNullColumnConstraint)
4715        if self._match_text_seq("CASESPECIFIC"):
4716            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4717        if self._match_text_seq("FOR", "REPLICATION"):
4718            return self.expression(exp.NotForReplicationColumnConstraint)
4719        return None
4720
4721    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4722        if self._match(TokenType.CONSTRAINT):
4723            this = self._parse_id_var()
4724        else:
4725            this = None
4726
4727        if self._match_texts(self.CONSTRAINT_PARSERS):
4728            return self.expression(
4729                exp.ColumnConstraint,
4730                this=this,
4731                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4732            )
4733
4734        return this
4735
4736    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4737        if not self._match(TokenType.CONSTRAINT):
4738            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4739
4740        return self.expression(
4741            exp.Constraint,
4742            this=self._parse_id_var(),
4743            expressions=self._parse_unnamed_constraints(),
4744        )
4745
4746    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
4747        constraints = []
4748        while True:
4749            constraint = self._parse_unnamed_constraint() or self._parse_function()
4750            if not constraint:
4751                break
4752            constraints.append(constraint)
4753
4754        return constraints
4755
4756    def _parse_unnamed_constraint(
4757        self, constraints: t.Optional[t.Collection[str]] = None
4758    ) -> t.Optional[exp.Expression]:
4759        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4760            constraints or self.CONSTRAINT_PARSERS
4761        ):
4762            return None
4763
4764        constraint = self._prev.text.upper()
4765        if constraint not in self.CONSTRAINT_PARSERS:
4766            self.raise_error(f"No parser found for schema constraint {constraint}.")
4767
4768        return self.CONSTRAINT_PARSERS[constraint](self)
4769
4770    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4771        self._match_text_seq("KEY")
4772        return self.expression(
4773            exp.UniqueColumnConstraint,
4774            this=self._parse_schema(self._parse_id_var(any_token=False)),
4775            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4776            on_conflict=self._parse_on_conflict(),
4777        )
4778
4779    def _parse_key_constraint_options(self) -> t.List[str]:
4780        options = []
4781        while True:
4782            if not self._curr:
4783                break
4784
4785            if self._match(TokenType.ON):
4786                action = None
4787                on = self._advance_any() and self._prev.text
4788
4789                if self._match_text_seq("NO", "ACTION"):
4790                    action = "NO ACTION"
4791                elif self._match_text_seq("CASCADE"):
4792                    action = "CASCADE"
4793                elif self._match_text_seq("RESTRICT"):
4794                    action = "RESTRICT"
4795                elif self._match_pair(TokenType.SET, TokenType.NULL):
4796                    action = "SET NULL"
4797                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4798                    action = "SET DEFAULT"
4799                else:
4800                    self.raise_error("Invalid key constraint")
4801
4802                options.append(f"ON {on} {action}")
4803            elif self._match_text_seq("NOT", "ENFORCED"):
4804                options.append("NOT ENFORCED")
4805            elif self._match_text_seq("DEFERRABLE"):
4806                options.append("DEFERRABLE")
4807            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4808                options.append("INITIALLY DEFERRED")
4809            elif self._match_text_seq("NORELY"):
4810                options.append("NORELY")
4811            elif self._match_text_seq("MATCH", "FULL"):
4812                options.append("MATCH FULL")
4813            else:
4814                break
4815
4816        return options
4817
4818    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4819        if match and not self._match(TokenType.REFERENCES):
4820            return None
4821
4822        expressions = None
4823        this = self._parse_table(schema=True)
4824        options = self._parse_key_constraint_options()
4825        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4826
4827    def _parse_foreign_key(self) -> exp.ForeignKey:
4828        expressions = self._parse_wrapped_id_vars()
4829        reference = self._parse_references()
4830        options = {}
4831
4832        while self._match(TokenType.ON):
4833            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4834                self.raise_error("Expected DELETE or UPDATE")
4835
4836            kind = self._prev.text.lower()
4837
4838            if self._match_text_seq("NO", "ACTION"):
4839                action = "NO ACTION"
4840            elif self._match(TokenType.SET):
4841                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4842                action = "SET " + self._prev.text.upper()
4843            else:
4844                self._advance()
4845                action = self._prev.text.upper()
4846
4847            options[kind] = action
4848
4849        return self.expression(
4850            exp.ForeignKey,
4851            expressions=expressions,
4852            reference=reference,
4853            **options,  # type: ignore
4854        )
4855
4856    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4857        return self._parse_field()
4858
4859    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4860        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4861            self._retreat(self._index - 1)
4862            return None
4863
4864        id_vars = self._parse_wrapped_id_vars()
4865        return self.expression(
4866            exp.PeriodForSystemTimeConstraint,
4867            this=seq_get(id_vars, 0),
4868            expression=seq_get(id_vars, 1),
4869        )
4870
4871    def _parse_primary_key(
4872        self, wrapped_optional: bool = False, in_props: bool = False
4873    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4874        desc = (
4875            self._match_set((TokenType.ASC, TokenType.DESC))
4876            and self._prev.token_type == TokenType.DESC
4877        )
4878
4879        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4880            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4881
4882        expressions = self._parse_wrapped_csv(
4883            self._parse_primary_key_part, optional=wrapped_optional
4884        )
4885        options = self._parse_key_constraint_options()
4886        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4887
4888    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4889        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4890
4891    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4892        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4893            return this
4894
4895        bracket_kind = self._prev.token_type
4896        expressions = self._parse_csv(
4897            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4898        )
4899
4900        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
4901            self.raise_error("Expected ]")
4902        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
4903            self.raise_error("Expected }")
4904
4905        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4906        if bracket_kind == TokenType.L_BRACE:
4907            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
4908        elif not this or this.name.upper() == "ARRAY":
4909            this = self.expression(exp.Array, expressions=expressions)
4910        else:
4911            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4912            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4913
4914        self._add_comments(this)
4915        return self._parse_bracket(this)
4916
4917    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4918        if self._match(TokenType.COLON):
4919            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4920        return this
4921
4922    def _parse_case(self) -> t.Optional[exp.Expression]:
4923        ifs = []
4924        default = None
4925
4926        comments = self._prev_comments
4927        expression = self._parse_conjunction()
4928
4929        while self._match(TokenType.WHEN):
4930            this = self._parse_conjunction()
4931            self._match(TokenType.THEN)
4932            then = self._parse_conjunction()
4933            ifs.append(self.expression(exp.If, this=this, true=then))
4934
4935        if self._match(TokenType.ELSE):
4936            default = self._parse_conjunction()
4937
4938        if not self._match(TokenType.END):
4939            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4940                default = exp.column("interval")
4941            else:
4942                self.raise_error("Expected END after CASE", self._prev)
4943
4944        return self.expression(
4945            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
4946        )
4947
4948    def _parse_if(self) -> t.Optional[exp.Expression]:
4949        if self._match(TokenType.L_PAREN):
4950            args = self._parse_csv(self._parse_conjunction)
4951            this = self.validate_expression(exp.If.from_arg_list(args), args)
4952            self._match_r_paren()
4953        else:
4954            index = self._index - 1
4955
4956            if self.NO_PAREN_IF_COMMANDS and index == 0:
4957                return self._parse_as_command(self._prev)
4958
4959            condition = self._parse_conjunction()
4960
4961            if not condition:
4962                self._retreat(index)
4963                return None
4964
4965            self._match(TokenType.THEN)
4966            true = self._parse_conjunction()
4967            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4968            self._match(TokenType.END)
4969            this = self.expression(exp.If, this=condition, true=true, false=false)
4970
4971        return this
4972
4973    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4974        if not self._match_text_seq("VALUE", "FOR"):
4975            self._retreat(self._index - 1)
4976            return None
4977
4978        return self.expression(
4979            exp.NextValueFor,
4980            this=self._parse_column(),
4981            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4982        )
4983
4984    def _parse_extract(self) -> exp.Extract:
4985        this = self._parse_function() or self._parse_var() or self._parse_type()
4986
4987        if self._match(TokenType.FROM):
4988            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4989
4990        if not self._match(TokenType.COMMA):
4991            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4992
4993        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4994
4995    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4996        this = self._parse_conjunction()
4997
4998        if not self._match(TokenType.ALIAS):
4999            if self._match(TokenType.COMMA):
5000                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5001
5002            self.raise_error("Expected AS after CAST")
5003
5004        fmt = None
5005        to = self._parse_types()
5006
5007        if self._match(TokenType.FORMAT):
5008            fmt_string = self._parse_string()
5009            fmt = self._parse_at_time_zone(fmt_string)
5010
5011            if not to:
5012                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5013            if to.this in exp.DataType.TEMPORAL_TYPES:
5014                this = self.expression(
5015                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5016                    this=this,
5017                    format=exp.Literal.string(
5018                        format_time(
5019                            fmt_string.this if fmt_string else "",
5020                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5021                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5022                        )
5023                    ),
5024                )
5025
5026                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5027                    this.set("zone", fmt.args["zone"])
5028                return this
5029        elif not to:
5030            self.raise_error("Expected TYPE after CAST")
5031        elif isinstance(to, exp.Identifier):
5032            to = exp.DataType.build(to.name, udt=True)
5033        elif to.this == exp.DataType.Type.CHAR:
5034            if self._match(TokenType.CHARACTER_SET):
5035                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5036
5037        return self.expression(
5038            exp.Cast if strict else exp.TryCast,
5039            this=this,
5040            to=to,
5041            format=fmt,
5042            safe=safe,
5043            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5044        )
5045
5046    def _parse_string_agg(self) -> exp.Expression:
5047        if self._match(TokenType.DISTINCT):
5048            args: t.List[t.Optional[exp.Expression]] = [
5049                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
5050            ]
5051            if self._match(TokenType.COMMA):
5052                args.extend(self._parse_csv(self._parse_conjunction))
5053        else:
5054            args = self._parse_csv(self._parse_conjunction)  # type: ignore
5055
5056        index = self._index
5057        if not self._match(TokenType.R_PAREN) and args:
5058            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5059            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5060            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5061            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5062
5063        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5064        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5065        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5066        if not self._match_text_seq("WITHIN", "GROUP"):
5067            self._retreat(index)
5068            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5069
5070        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5071        order = self._parse_order(this=seq_get(args, 0))
5072        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5073
5074    def _parse_convert(
5075        self, strict: bool, safe: t.Optional[bool] = None
5076    ) -> t.Optional[exp.Expression]:
5077        this = self._parse_bitwise()
5078
5079        if self._match(TokenType.USING):
5080            to: t.Optional[exp.Expression] = self.expression(
5081                exp.CharacterSet, this=self._parse_var()
5082            )
5083        elif self._match(TokenType.COMMA):
5084            to = self._parse_types()
5085        else:
5086            to = None
5087
5088        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5089
5090    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5091        """
5092        There are generally two variants of the DECODE function:
5093
5094        - DECODE(bin, charset)
5095        - DECODE(expression, search, result [, search, result] ... [, default])
5096
5097        The second variant will always be parsed into a CASE expression. Note that NULL
5098        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5099        instead of relying on pattern matching.
5100        """
5101        args = self._parse_csv(self._parse_conjunction)
5102
5103        if len(args) < 3:
5104            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5105
5106        expression, *expressions = args
5107        if not expression:
5108            return None
5109
5110        ifs = []
5111        for search, result in zip(expressions[::2], expressions[1::2]):
5112            if not search or not result:
5113                return None
5114
5115            if isinstance(search, exp.Literal):
5116                ifs.append(
5117                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5118                )
5119            elif isinstance(search, exp.Null):
5120                ifs.append(
5121                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5122                )
5123            else:
5124                cond = exp.or_(
5125                    exp.EQ(this=expression.copy(), expression=search),
5126                    exp.and_(
5127                        exp.Is(this=expression.copy(), expression=exp.Null()),
5128                        exp.Is(this=search.copy(), expression=exp.Null()),
5129                        copy=False,
5130                    ),
5131                    copy=False,
5132                )
5133                ifs.append(exp.If(this=cond, true=result))
5134
5135        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5136
5137    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5138        self._match_text_seq("KEY")
5139        key = self._parse_column()
5140        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5141        self._match_text_seq("VALUE")
5142        value = self._parse_bitwise()
5143
5144        if not key and not value:
5145            return None
5146        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5147
5148    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5149        if not this or not self._match_text_seq("FORMAT", "JSON"):
5150            return this
5151
5152        return self.expression(exp.FormatJson, this=this)
5153
5154    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5155        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5156        for value in values:
5157            if self._match_text_seq(value, "ON", on):
5158                return f"{value} ON {on}"
5159
5160        return None
5161
5162    @t.overload
5163    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5164
5165    @t.overload
5166    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5167
5168    def _parse_json_object(self, agg=False):
5169        star = self._parse_star()
5170        expressions = (
5171            [star]
5172            if star
5173            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5174        )
5175        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5176
5177        unique_keys = None
5178        if self._match_text_seq("WITH", "UNIQUE"):
5179            unique_keys = True
5180        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5181            unique_keys = False
5182
5183        self._match_text_seq("KEYS")
5184
5185        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5186            self._parse_type()
5187        )
5188        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5189
5190        return self.expression(
5191            exp.JSONObjectAgg if agg else exp.JSONObject,
5192            expressions=expressions,
5193            null_handling=null_handling,
5194            unique_keys=unique_keys,
5195            return_type=return_type,
5196            encoding=encoding,
5197        )
5198
5199    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5200    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5201        if not self._match_text_seq("NESTED"):
5202            this = self._parse_id_var()
5203            kind = self._parse_types(allow_identifiers=False)
5204            nested = None
5205        else:
5206            this = None
5207            kind = None
5208            nested = True
5209
5210        path = self._match_text_seq("PATH") and self._parse_string()
5211        nested_schema = nested and self._parse_json_schema()
5212
5213        return self.expression(
5214            exp.JSONColumnDef,
5215            this=this,
5216            kind=kind,
5217            path=path,
5218            nested_schema=nested_schema,
5219        )
5220
5221    def _parse_json_schema(self) -> exp.JSONSchema:
5222        self._match_text_seq("COLUMNS")
5223        return self.expression(
5224            exp.JSONSchema,
5225            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5226        )
5227
5228    def _parse_json_table(self) -> exp.JSONTable:
5229        this = self._parse_format_json(self._parse_bitwise())
5230        path = self._match(TokenType.COMMA) and self._parse_string()
5231        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5232        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5233        schema = self._parse_json_schema()
5234
5235        return exp.JSONTable(
5236            this=this,
5237            schema=schema,
5238            path=path,
5239            error_handling=error_handling,
5240            empty_handling=empty_handling,
5241        )
5242
5243    def _parse_match_against(self) -> exp.MatchAgainst:
5244        expressions = self._parse_csv(self._parse_column)
5245
5246        self._match_text_seq(")", "AGAINST", "(")
5247
5248        this = self._parse_string()
5249
5250        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5251            modifier = "IN NATURAL LANGUAGE MODE"
5252            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5253                modifier = f"{modifier} WITH QUERY EXPANSION"
5254        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5255            modifier = "IN BOOLEAN MODE"
5256        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5257            modifier = "WITH QUERY EXPANSION"
5258        else:
5259            modifier = None
5260
5261        return self.expression(
5262            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5263        )
5264
5265    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5266    def _parse_open_json(self) -> exp.OpenJSON:
5267        this = self._parse_bitwise()
5268        path = self._match(TokenType.COMMA) and self._parse_string()
5269
5270        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5271            this = self._parse_field(any_token=True)
5272            kind = self._parse_types()
5273            path = self._parse_string()
5274            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5275
5276            return self.expression(
5277                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5278            )
5279
5280        expressions = None
5281        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5282            self._match_l_paren()
5283            expressions = self._parse_csv(_parse_open_json_column_def)
5284
5285        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5286
5287    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5288        args = self._parse_csv(self._parse_bitwise)
5289
5290        if self._match(TokenType.IN):
5291            return self.expression(
5292                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5293            )
5294
5295        if haystack_first:
5296            haystack = seq_get(args, 0)
5297            needle = seq_get(args, 1)
5298        else:
5299            needle = seq_get(args, 0)
5300            haystack = seq_get(args, 1)
5301
5302        return self.expression(
5303            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5304        )
5305
5306    def _parse_predict(self) -> exp.Predict:
5307        self._match_text_seq("MODEL")
5308        this = self._parse_table()
5309
5310        self._match(TokenType.COMMA)
5311        self._match_text_seq("TABLE")
5312
5313        return self.expression(
5314            exp.Predict,
5315            this=this,
5316            expression=self._parse_table(),
5317            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5318        )
5319
5320    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5321        args = self._parse_csv(self._parse_table)
5322        return exp.JoinHint(this=func_name.upper(), expressions=args)
5323
5324    def _parse_substring(self) -> exp.Substring:
5325        # Postgres supports the form: substring(string [from int] [for int])
5326        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5327
5328        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5329
5330        if self._match(TokenType.FROM):
5331            args.append(self._parse_bitwise())
5332        if self._match(TokenType.FOR):
5333            if len(args) == 1:
5334                args.append(exp.Literal.number(1))
5335            args.append(self._parse_bitwise())
5336
5337        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5338
5339    def _parse_trim(self) -> exp.Trim:
5340        # https://www.w3resource.com/sql/character-functions/trim.php
5341        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5342
5343        position = None
5344        collation = None
5345        expression = None
5346
5347        if self._match_texts(self.TRIM_TYPES):
5348            position = self._prev.text.upper()
5349
5350        this = self._parse_bitwise()
5351        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5352            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5353            expression = self._parse_bitwise()
5354
5355            if invert_order:
5356                this, expression = expression, this
5357
5358        if self._match(TokenType.COLLATE):
5359            collation = self._parse_bitwise()
5360
5361        return self.expression(
5362            exp.Trim, this=this, position=position, expression=expression, collation=collation
5363        )
5364
5365    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5366        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5367
5368    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5369        return self._parse_window(self._parse_id_var(), alias=True)
5370
5371    def _parse_respect_or_ignore_nulls(
5372        self, this: t.Optional[exp.Expression]
5373    ) -> t.Optional[exp.Expression]:
5374        if self._match_text_seq("IGNORE", "NULLS"):
5375            return self.expression(exp.IgnoreNulls, this=this)
5376        if self._match_text_seq("RESPECT", "NULLS"):
5377            return self.expression(exp.RespectNulls, this=this)
5378        return this
5379
5380    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5381        if self._match(TokenType.HAVING):
5382            self._match_texts(("MAX", "MIN"))
5383            max = self._prev.text.upper() != "MIN"
5384            return self.expression(
5385                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5386            )
5387
5388        return this
5389
5390    def _parse_window(
5391        self, this: t.Optional[exp.Expression], alias: bool = False
5392    ) -> t.Optional[exp.Expression]:
5393        func = this
5394        comments = func.comments if isinstance(func, exp.Expression) else None
5395
5396        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5397            self._match(TokenType.WHERE)
5398            this = self.expression(
5399                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5400            )
5401            self._match_r_paren()
5402
5403        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5404        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5405        if self._match_text_seq("WITHIN", "GROUP"):
5406            order = self._parse_wrapped(self._parse_order)
5407            this = self.expression(exp.WithinGroup, this=this, expression=order)
5408
5409        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5410        # Some dialects choose to implement and some do not.
5411        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5412
5413        # There is some code above in _parse_lambda that handles
5414        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5415
5416        # The below changes handle
5417        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5418
5419        # Oracle allows both formats
5420        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5421        #   and Snowflake chose to do the same for familiarity
5422        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5423        if isinstance(this, exp.AggFunc):
5424            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5425
5426            if ignore_respect and ignore_respect is not this:
5427                ignore_respect.replace(ignore_respect.this)
5428                this = self.expression(ignore_respect.__class__, this=this)
5429
5430        this = self._parse_respect_or_ignore_nulls(this)
5431
5432        # bigquery select from window x AS (partition by ...)
5433        if alias:
5434            over = None
5435            self._match(TokenType.ALIAS)
5436        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5437            return this
5438        else:
5439            over = self._prev.text.upper()
5440
5441        if comments and isinstance(func, exp.Expression):
5442            func.pop_comments()
5443
5444        if not self._match(TokenType.L_PAREN):
5445            return self.expression(
5446                exp.Window,
5447                comments=comments,
5448                this=this,
5449                alias=self._parse_id_var(False),
5450                over=over,
5451            )
5452
5453        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5454
5455        first = self._match(TokenType.FIRST)
5456        if self._match_text_seq("LAST"):
5457            first = False
5458
5459        partition, order = self._parse_partition_and_order()
5460        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5461
5462        if kind:
5463            self._match(TokenType.BETWEEN)
5464            start = self._parse_window_spec()
5465            self._match(TokenType.AND)
5466            end = self._parse_window_spec()
5467
5468            spec = self.expression(
5469                exp.WindowSpec,
5470                kind=kind,
5471                start=start["value"],
5472                start_side=start["side"],
5473                end=end["value"],
5474                end_side=end["side"],
5475            )
5476        else:
5477            spec = None
5478
5479        self._match_r_paren()
5480
5481        window = self.expression(
5482            exp.Window,
5483            comments=comments,
5484            this=this,
5485            partition_by=partition,
5486            order=order,
5487            spec=spec,
5488            alias=window_alias,
5489            over=over,
5490            first=first,
5491        )
5492
5493        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5494        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5495            return self._parse_window(window, alias=alias)
5496
5497        return window
5498
5499    def _parse_partition_and_order(
5500        self,
5501    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5502        return self._parse_partition_by(), self._parse_order()
5503
5504    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5505        self._match(TokenType.BETWEEN)
5506
5507        return {
5508            "value": (
5509                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5510                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5511                or self._parse_bitwise()
5512            ),
5513            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5514        }
5515
5516    def _parse_alias(
5517        self, this: t.Optional[exp.Expression], explicit: bool = False
5518    ) -> t.Optional[exp.Expression]:
5519        any_token = self._match(TokenType.ALIAS)
5520        comments = self._prev_comments or []
5521
5522        if explicit and not any_token:
5523            return this
5524
5525        if self._match(TokenType.L_PAREN):
5526            aliases = self.expression(
5527                exp.Aliases,
5528                comments=comments,
5529                this=this,
5530                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5531            )
5532            self._match_r_paren(aliases)
5533            return aliases
5534
5535        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
5536            self.STRING_ALIASES and self._parse_string_as_identifier()
5537        )
5538
5539        if alias:
5540            comments.extend(alias.pop_comments())
5541            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5542            column = this.this
5543
5544            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5545            if not this.comments and column and column.comments:
5546                this.comments = column.pop_comments()
5547
5548        return this
5549
5550    def _parse_id_var(
5551        self,
5552        any_token: bool = True,
5553        tokens: t.Optional[t.Collection[TokenType]] = None,
5554    ) -> t.Optional[exp.Expression]:
5555        expression = self._parse_identifier()
5556        if not expression and (
5557            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
5558        ):
5559            quoted = self._prev.token_type == TokenType.STRING
5560            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
5561
5562        return expression
5563
5564    def _parse_string(self) -> t.Optional[exp.Expression]:
5565        if self._match_set(self.STRING_PARSERS):
5566            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
5567        return self._parse_placeholder()
5568
5569    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5570        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5571
5572    def _parse_number(self) -> t.Optional[exp.Expression]:
5573        if self._match_set(self.NUMERIC_PARSERS):
5574            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
5575        return self._parse_placeholder()
5576
5577    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5578        if self._match(TokenType.IDENTIFIER):
5579            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5580        return self._parse_placeholder()
5581
5582    def _parse_var(
5583        self,
5584        any_token: bool = False,
5585        tokens: t.Optional[t.Collection[TokenType]] = None,
5586        upper: bool = False,
5587    ) -> t.Optional[exp.Expression]:
5588        if (
5589            (any_token and self._advance_any())
5590            or self._match(TokenType.VAR)
5591            or (self._match_set(tokens) if tokens else False)
5592        ):
5593            return self.expression(
5594                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5595            )
5596        return self._parse_placeholder()
5597
5598    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5599        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5600            self._advance()
5601            return self._prev
5602        return None
5603
5604    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5605        return self._parse_var() or self._parse_string()
5606
5607    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
5608        return self._parse_primary() or self._parse_var(any_token=True)
5609
5610    def _parse_null(self) -> t.Optional[exp.Expression]:
5611        if self._match_set(self.NULL_TOKENS):
5612            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5613        return self._parse_placeholder()
5614
5615    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5616        if self._match(TokenType.TRUE):
5617            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5618        if self._match(TokenType.FALSE):
5619            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5620        return self._parse_placeholder()
5621
5622    def _parse_star(self) -> t.Optional[exp.Expression]:
5623        if self._match(TokenType.STAR):
5624            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5625        return self._parse_placeholder()
5626
5627    def _parse_parameter(self) -> exp.Parameter:
5628        self._match(TokenType.L_BRACE)
5629        this = self._parse_identifier() or self._parse_primary_or_var()
5630        expression = self._match(TokenType.COLON) and (
5631            self._parse_identifier() or self._parse_primary_or_var()
5632        )
5633        self._match(TokenType.R_BRACE)
5634        return self.expression(exp.Parameter, this=this, expression=expression)
5635
5636    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5637        if self._match_set(self.PLACEHOLDER_PARSERS):
5638            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5639            if placeholder:
5640                return placeholder
5641            self._advance(-1)
5642        return None
5643
5644    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5645        if not self._match(TokenType.EXCEPT):
5646            return None
5647        if self._match(TokenType.L_PAREN, advance=False):
5648            return self._parse_wrapped_csv(self._parse_column)
5649
5650        except_column = self._parse_column()
5651        return [except_column] if except_column else None
5652
5653    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5654        if not self._match(TokenType.REPLACE):
5655            return None
5656        if self._match(TokenType.L_PAREN, advance=False):
5657            return self._parse_wrapped_csv(self._parse_expression)
5658
5659        replace_expression = self._parse_expression()
5660        return [replace_expression] if replace_expression else None
5661
5662    def _parse_csv(
5663        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5664    ) -> t.List[exp.Expression]:
5665        parse_result = parse_method()
5666        items = [parse_result] if parse_result is not None else []
5667
5668        while self._match(sep):
5669            self._add_comments(parse_result)
5670            parse_result = parse_method()
5671            if parse_result is not None:
5672                items.append(parse_result)
5673
5674        return items
5675
5676    def _parse_tokens(
5677        self, parse_method: t.Callable, expressions: t.Dict
5678    ) -> t.Optional[exp.Expression]:
5679        this = parse_method()
5680
5681        while self._match_set(expressions):
5682            this = self.expression(
5683                expressions[self._prev.token_type],
5684                this=this,
5685                comments=self._prev_comments,
5686                expression=parse_method(),
5687            )
5688
5689        return this
5690
5691    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5692        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5693
5694    def _parse_wrapped_csv(
5695        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5696    ) -> t.List[exp.Expression]:
5697        return self._parse_wrapped(
5698            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5699        )
5700
5701    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5702        wrapped = self._match(TokenType.L_PAREN)
5703        if not wrapped and not optional:
5704            self.raise_error("Expecting (")
5705        parse_result = parse_method()
5706        if wrapped:
5707            self._match_r_paren()
5708        return parse_result
5709
5710    def _parse_expressions(self) -> t.List[exp.Expression]:
5711        return self._parse_csv(self._parse_expression)
5712
5713    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5714        return self._parse_select() or self._parse_set_operations(
5715            self._parse_expression() if alias else self._parse_conjunction()
5716        )
5717
5718    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5719        return self._parse_query_modifiers(
5720            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5721        )
5722
5723    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5724        this = None
5725        if self._match_texts(self.TRANSACTION_KIND):
5726            this = self._prev.text
5727
5728        self._match_texts(("TRANSACTION", "WORK"))
5729
5730        modes = []
5731        while True:
5732            mode = []
5733            while self._match(TokenType.VAR):
5734                mode.append(self._prev.text)
5735
5736            if mode:
5737                modes.append(" ".join(mode))
5738            if not self._match(TokenType.COMMA):
5739                break
5740
5741        return self.expression(exp.Transaction, this=this, modes=modes)
5742
5743    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5744        chain = None
5745        savepoint = None
5746        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5747
5748        self._match_texts(("TRANSACTION", "WORK"))
5749
5750        if self._match_text_seq("TO"):
5751            self._match_text_seq("SAVEPOINT")
5752            savepoint = self._parse_id_var()
5753
5754        if self._match(TokenType.AND):
5755            chain = not self._match_text_seq("NO")
5756            self._match_text_seq("CHAIN")
5757
5758        if is_rollback:
5759            return self.expression(exp.Rollback, savepoint=savepoint)
5760
5761        return self.expression(exp.Commit, chain=chain)
5762
5763    def _parse_refresh(self) -> exp.Refresh:
5764        self._match(TokenType.TABLE)
5765        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5766
5767    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5768        if not self._match_text_seq("ADD"):
5769            return None
5770
5771        self._match(TokenType.COLUMN)
5772        exists_column = self._parse_exists(not_=True)
5773        expression = self._parse_field_def()
5774
5775        if expression:
5776            expression.set("exists", exists_column)
5777
5778            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5779            if self._match_texts(("FIRST", "AFTER")):
5780                position = self._prev.text
5781                column_position = self.expression(
5782                    exp.ColumnPosition, this=self._parse_column(), position=position
5783                )
5784                expression.set("position", column_position)
5785
5786        return expression
5787
5788    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5789        drop = self._match(TokenType.DROP) and self._parse_drop()
5790        if drop and not isinstance(drop, exp.Command):
5791            drop.set("kind", drop.args.get("kind", "COLUMN"))
5792        return drop
5793
5794    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5795    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5796        return self.expression(
5797            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5798        )
5799
5800    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5801        index = self._index - 1
5802
5803        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
5804            return self._parse_csv(
5805                lambda: self.expression(
5806                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
5807                )
5808            )
5809
5810        self._retreat(index)
5811        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5812            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5813        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5814
5815    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5816        self._match(TokenType.COLUMN)
5817        column = self._parse_field(any_token=True)
5818
5819        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5820            return self.expression(exp.AlterColumn, this=column, drop=True)
5821        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5822            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5823        if self._match(TokenType.COMMENT):
5824            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
5825
5826        self._match_text_seq("SET", "DATA")
5827        self._match_text_seq("TYPE")
5828        return self.expression(
5829            exp.AlterColumn,
5830            this=column,
5831            dtype=self._parse_types(),
5832            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5833            using=self._match(TokenType.USING) and self._parse_conjunction(),
5834        )
5835
5836    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5837        index = self._index - 1
5838
5839        partition_exists = self._parse_exists()
5840        if self._match(TokenType.PARTITION, advance=False):
5841            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5842
5843        self._retreat(index)
5844        return self._parse_csv(self._parse_drop_column)
5845
5846    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
5847        if self._match(TokenType.COLUMN):
5848            exists = self._parse_exists()
5849            old_column = self._parse_column()
5850            to = self._match_text_seq("TO")
5851            new_column = self._parse_column()
5852
5853            if old_column is None or to is None or new_column is None:
5854                return None
5855
5856            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
5857
5858        self._match_text_seq("TO")
5859        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5860
5861    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5862        start = self._prev
5863
5864        if not self._match(TokenType.TABLE):
5865            return self._parse_as_command(start)
5866
5867        exists = self._parse_exists()
5868        only = self._match_text_seq("ONLY")
5869        this = self._parse_table(schema=True)
5870
5871        if self._next:
5872            self._advance()
5873
5874        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5875        if parser:
5876            actions = ensure_list(parser(self))
5877            options = self._parse_csv(self._parse_property)
5878
5879            if not self._curr and actions:
5880                return self.expression(
5881                    exp.AlterTable,
5882                    this=this,
5883                    exists=exists,
5884                    actions=actions,
5885                    only=only,
5886                    options=options,
5887                )
5888
5889        return self._parse_as_command(start)
5890
5891    def _parse_merge(self) -> exp.Merge:
5892        self._match(TokenType.INTO)
5893        target = self._parse_table()
5894
5895        if target and self._match(TokenType.ALIAS, advance=False):
5896            target.set("alias", self._parse_table_alias())
5897
5898        self._match(TokenType.USING)
5899        using = self._parse_table()
5900
5901        self._match(TokenType.ON)
5902        on = self._parse_conjunction()
5903
5904        return self.expression(
5905            exp.Merge,
5906            this=target,
5907            using=using,
5908            on=on,
5909            expressions=self._parse_when_matched(),
5910        )
5911
5912    def _parse_when_matched(self) -> t.List[exp.When]:
5913        whens = []
5914
5915        while self._match(TokenType.WHEN):
5916            matched = not self._match(TokenType.NOT)
5917            self._match_text_seq("MATCHED")
5918            source = (
5919                False
5920                if self._match_text_seq("BY", "TARGET")
5921                else self._match_text_seq("BY", "SOURCE")
5922            )
5923            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5924
5925            self._match(TokenType.THEN)
5926
5927            if self._match(TokenType.INSERT):
5928                _this = self._parse_star()
5929                if _this:
5930                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5931                else:
5932                    then = self.expression(
5933                        exp.Insert,
5934                        this=self._parse_value(),
5935                        expression=self._match_text_seq("VALUES") and self._parse_value(),
5936                    )
5937            elif self._match(TokenType.UPDATE):
5938                expressions = self._parse_star()
5939                if expressions:
5940                    then = self.expression(exp.Update, expressions=expressions)
5941                else:
5942                    then = self.expression(
5943                        exp.Update,
5944                        expressions=self._match(TokenType.SET)
5945                        and self._parse_csv(self._parse_equality),
5946                    )
5947            elif self._match(TokenType.DELETE):
5948                then = self.expression(exp.Var, this=self._prev.text)
5949            else:
5950                then = None
5951
5952            whens.append(
5953                self.expression(
5954                    exp.When,
5955                    matched=matched,
5956                    source=source,
5957                    condition=condition,
5958                    then=then,
5959                )
5960            )
5961        return whens
5962
5963    def _parse_show(self) -> t.Optional[exp.Expression]:
5964        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5965        if parser:
5966            return parser(self)
5967        return self._parse_as_command(self._prev)
5968
5969    def _parse_set_item_assignment(
5970        self, kind: t.Optional[str] = None
5971    ) -> t.Optional[exp.Expression]:
5972        index = self._index
5973
5974        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5975            return self._parse_set_transaction(global_=kind == "GLOBAL")
5976
5977        left = self._parse_primary() or self._parse_id_var()
5978        assignment_delimiter = self._match_texts(("=", "TO"))
5979
5980        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5981            self._retreat(index)
5982            return None
5983
5984        right = self._parse_statement() or self._parse_id_var()
5985        this = self.expression(exp.EQ, this=left, expression=right)
5986
5987        return self.expression(exp.SetItem, this=this, kind=kind)
5988
5989    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5990        self._match_text_seq("TRANSACTION")
5991        characteristics = self._parse_csv(
5992            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5993        )
5994        return self.expression(
5995            exp.SetItem,
5996            expressions=characteristics,
5997            kind="TRANSACTION",
5998            **{"global": global_},  # type: ignore
5999        )
6000
6001    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6002        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6003        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6004
6005    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6006        index = self._index
6007        set_ = self.expression(
6008            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6009        )
6010
6011        if self._curr:
6012            self._retreat(index)
6013            return self._parse_as_command(self._prev)
6014
6015        return set_
6016
6017    def _parse_var_from_options(
6018        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6019    ) -> t.Optional[exp.Var]:
6020        start = self._curr
6021        if not start:
6022            return None
6023
6024        option = start.text.upper()
6025        continuations = options.get(option)
6026
6027        index = self._index
6028        self._advance()
6029        for keywords in continuations or []:
6030            if isinstance(keywords, str):
6031                keywords = (keywords,)
6032
6033            if self._match_text_seq(*keywords):
6034                option = f"{option} {' '.join(keywords)}"
6035                break
6036        else:
6037            if continuations or continuations is None:
6038                if raise_unmatched:
6039                    self.raise_error(f"Unknown option {option}")
6040
6041                self._retreat(index)
6042                return None
6043
6044        return exp.var(option)
6045
6046    def _parse_as_command(self, start: Token) -> exp.Command:
6047        while self._curr:
6048            self._advance()
6049        text = self._find_sql(start, self._prev)
6050        size = len(start.text)
6051        self._warn_unsupported()
6052        return exp.Command(this=text[:size], expression=text[size:])
6053
6054    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6055        settings = []
6056
6057        self._match_l_paren()
6058        kind = self._parse_id_var()
6059
6060        if self._match(TokenType.L_PAREN):
6061            while True:
6062                key = self._parse_id_var()
6063                value = self._parse_primary()
6064
6065                if not key and value is None:
6066                    break
6067                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6068            self._match(TokenType.R_PAREN)
6069
6070        self._match_r_paren()
6071
6072        return self.expression(
6073            exp.DictProperty,
6074            this=this,
6075            kind=kind.this if kind else None,
6076            settings=settings,
6077        )
6078
6079    def _parse_dict_range(self, this: str) -> exp.DictRange:
6080        self._match_l_paren()
6081        has_min = self._match_text_seq("MIN")
6082        if has_min:
6083            min = self._parse_var() or self._parse_primary()
6084            self._match_text_seq("MAX")
6085            max = self._parse_var() or self._parse_primary()
6086        else:
6087            max = self._parse_var() or self._parse_primary()
6088            min = exp.Literal.number(0)
6089        self._match_r_paren()
6090        return self.expression(exp.DictRange, this=this, min=min, max=max)
6091
6092    def _parse_comprehension(
6093        self, this: t.Optional[exp.Expression]
6094    ) -> t.Optional[exp.Comprehension]:
6095        index = self._index
6096        expression = self._parse_column()
6097        if not self._match(TokenType.IN):
6098            self._retreat(index - 1)
6099            return None
6100        iterator = self._parse_column()
6101        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
6102        return self.expression(
6103            exp.Comprehension,
6104            this=this,
6105            expression=expression,
6106            iterator=iterator,
6107            condition=condition,
6108        )
6109
6110    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6111        if self._match(TokenType.HEREDOC_STRING):
6112            return self.expression(exp.Heredoc, this=self._prev.text)
6113
6114        if not self._match_text_seq("$"):
6115            return None
6116
6117        tags = ["$"]
6118        tag_text = None
6119
6120        if self._is_connected():
6121            self._advance()
6122            tags.append(self._prev.text.upper())
6123        else:
6124            self.raise_error("No closing $ found")
6125
6126        if tags[-1] != "$":
6127            if self._is_connected() and self._match_text_seq("$"):
6128                tag_text = tags[-1]
6129                tags.append("$")
6130            else:
6131                self.raise_error("No closing $ found")
6132
6133        heredoc_start = self._curr
6134
6135        while self._curr:
6136            if self._match_text_seq(*tags, advance=False):
6137                this = self._find_sql(heredoc_start, self._prev)
6138                self._advance(len(tags))
6139                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6140
6141            self._advance()
6142
6143        self.raise_error(f"No closing {''.join(tags)} found")
6144        return None
6145
6146    def _find_parser(
6147        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6148    ) -> t.Optional[t.Callable]:
6149        if not self._curr:
6150            return None
6151
6152        index = self._index
6153        this = []
6154        while True:
6155            # The current token might be multiple words
6156            curr = self._curr.text.upper()
6157            key = curr.split(" ")
6158            this.append(curr)
6159
6160            self._advance()
6161            result, trie = in_trie(trie, key)
6162            if result == TrieResult.FAILED:
6163                break
6164
6165            if result == TrieResult.EXISTS:
6166                subparser = parsers[" ".join(this)]
6167                return subparser
6168
6169        self._retreat(index)
6170        return None
6171
6172    def _match(self, token_type, advance=True, expression=None):
6173        if not self._curr:
6174            return None
6175
6176        if self._curr.token_type == token_type:
6177            if advance:
6178                self._advance()
6179            self._add_comments(expression)
6180            return True
6181
6182        return None
6183
6184    def _match_set(self, types, advance=True):
6185        if not self._curr:
6186            return None
6187
6188        if self._curr.token_type in types:
6189            if advance:
6190                self._advance()
6191            return True
6192
6193        return None
6194
6195    def _match_pair(self, token_type_a, token_type_b, advance=True):
6196        if not self._curr or not self._next:
6197            return None
6198
6199        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6200            if advance:
6201                self._advance(2)
6202            return True
6203
6204        return None
6205
6206    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6207        if not self._match(TokenType.L_PAREN, expression=expression):
6208            self.raise_error("Expecting (")
6209
6210    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6211        if not self._match(TokenType.R_PAREN, expression=expression):
6212            self.raise_error("Expecting )")
6213
6214    def _match_texts(self, texts, advance=True):
6215        if self._curr and self._curr.text.upper() in texts:
6216            if advance:
6217                self._advance()
6218            return True
6219        return None
6220
6221    def _match_text_seq(self, *texts, advance=True):
6222        index = self._index
6223        for text in texts:
6224            if self._curr and self._curr.text.upper() == text:
6225                self._advance()
6226            else:
6227                self._retreat(index)
6228                return None
6229
6230        if not advance:
6231            self._retreat(index)
6232
6233        return True
6234
6235    def _replace_lambda(
6236        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
6237    ) -> t.Optional[exp.Expression]:
6238        if not node:
6239            return node
6240
6241        for column in node.find_all(exp.Column):
6242            if column.parts[0].name in lambda_variables:
6243                dot_or_id = column.to_dot() if column.table else column.this
6244                parent = column.parent
6245
6246                while isinstance(parent, exp.Dot):
6247                    if not isinstance(parent.parent, exp.Dot):
6248                        parent.replace(dot_or_id)
6249                        break
6250                    parent = parent.parent
6251                else:
6252                    if column is node:
6253                        node = dot_or_id
6254                    else:
6255                        column.replace(dot_or_id)
6256        return node
6257
6258    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6259        start = self._prev
6260
6261        # Not to be confused with TRUNCATE(number, decimals) function call
6262        if self._match(TokenType.L_PAREN):
6263            self._retreat(self._index - 2)
6264            return self._parse_function()
6265
6266        # Clickhouse supports TRUNCATE DATABASE as well
6267        is_database = self._match(TokenType.DATABASE)
6268
6269        self._match(TokenType.TABLE)
6270
6271        exists = self._parse_exists(not_=False)
6272
6273        expressions = self._parse_csv(
6274            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6275        )
6276
6277        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6278
6279        if self._match_text_seq("RESTART", "IDENTITY"):
6280            identity = "RESTART"
6281        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6282            identity = "CONTINUE"
6283        else:
6284            identity = None
6285
6286        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6287            option = self._prev.text
6288        else:
6289            option = None
6290
6291        partition = self._parse_partition()
6292
6293        # Fallback case
6294        if self._curr:
6295            return self._parse_as_command(start)
6296
6297        return self.expression(
6298            exp.TruncateTable,
6299            expressions=expressions,
6300            is_database=is_database,
6301            exists=exists,
6302            cluster=cluster,
6303            identity=identity,
6304            option=option,
6305            partition=partition,
6306        )
6307
6308    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6309        this = self._parse_ordered(self._parse_opclass)
6310
6311        if not self._match(TokenType.WITH):
6312            return this
6313
6314        op = self._parse_var(any_token=True)
6315
6316        return self.expression(exp.WithOperator, this=this, op=op)
6317
6318    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6319        opts = []
6320        self._match(TokenType.EQ)
6321        self._match(TokenType.L_PAREN)
6322        while self._curr and not self._match(TokenType.R_PAREN):
6323            opts.append(self._parse_conjunction())
6324            self._match(TokenType.COMMA)
6325        return opts
6326
6327    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6328        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6329
6330        options = []
6331        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6332            option = self._parse_unquoted_field()
6333            value = None
6334
6335            # Some options are defined as functions with the values as params
6336            if not isinstance(option, exp.Func):
6337                prev = self._prev.text.upper()
6338                # Different dialects might separate options and values by white space, "=" and "AS"
6339                self._match(TokenType.EQ)
6340                self._match(TokenType.ALIAS)
6341
6342                if prev == "FILE_FORMAT" and self._match(TokenType.L_PAREN):
6343                    # Snowflake FILE_FORMAT case
6344                    value = self._parse_wrapped_options()
6345                else:
6346                    value = self._parse_unquoted_field()
6347
6348            param = self.expression(exp.CopyParameter, this=option, expression=value)
6349            options.append(param)
6350
6351            if sep:
6352                self._match(sep)
6353
6354        return options
6355
6356    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6357        expr = self.expression(exp.Credentials)
6358
6359        if self._match_text_seq("STORAGE_INTEGRATION", advance=False):
6360            expr.set("storage", self._parse_conjunction())
6361        if self._match_text_seq("CREDENTIALS"):
6362            # Snowflake supports CREDENTIALS = (...), while Redshift CREDENTIALS <string>
6363            creds = (
6364                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6365            )
6366            expr.set("credentials", creds)
6367        if self._match_text_seq("ENCRYPTION"):
6368            expr.set("encryption", self._parse_wrapped_options())
6369        if self._match_text_seq("IAM_ROLE"):
6370            expr.set("iam_role", self._parse_field())
6371        if self._match_text_seq("REGION"):
6372            expr.set("region", self._parse_field())
6373
6374        return expr
6375
6376    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6377        return self._parse_field()
6378
6379    def _parse_copy(self) -> exp.Copy | exp.Command:
6380        start = self._prev
6381
6382        self._match(TokenType.INTO)
6383
6384        this = (
6385            self._parse_conjunction()
6386            if self._match(TokenType.L_PAREN, advance=False)
6387            else self._parse_table(schema=True)
6388        )
6389
6390        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
6391
6392        files = self._parse_csv(self._parse_file_location)
6393        credentials = self._parse_credentials()
6394
6395        self._match_text_seq("WITH")
6396
6397        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
6398
6399        # Fallback case
6400        if self._curr:
6401            return self._parse_as_command(start)
6402
6403        return self.expression(
6404            exp.Copy,
6405            this=this,
6406            kind=kind,
6407            credentials=credentials,
6408            files=files,
6409            params=params,
6410        )
logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
27    if len(args) == 1 and args[0].is_star:
28        return exp.StarMap(this=args[0])
29
30    keys = []
31    values = []
32    for i in range(0, len(args), 2):
33        keys.append(args[i])
34        values.append(args[i + 1])
35
36    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
39def build_like(args: t.List) -> exp.Escape | exp.Like:
40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
41    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression]) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
44def binary_range_parser(
45    expr_type: t.Type[exp.Expression],
46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
47    return lambda self, this: self._parse_escape(
48        self.expression(expr_type, this=this, expression=self._parse_bitwise())
49    )
def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
52def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
53    # Default argument order is base, expression
54    this = seq_get(args, 0)
55    expression = seq_get(args, 1)
56
57    if expression:
58        if not dialect.LOG_BASE_FIRST:
59            this, expression = expression, this
60        return exp.Log(this=this, expression=expression)
61
62    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]:
65def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
66    def _builder(args: t.List, dialect: Dialect) -> E:
67        expression = expr_type(
68            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
69        )
70        if len(args) > 2 and expr_type is exp.JSONExtract:
71            expression.set("expressions", args[2:])
72
73        return expression
74
75    return _builder
class Parser:
  88class Parser(metaclass=_Parser):
  89    """
  90    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  91
  92    Args:
  93        error_level: The desired error level.
  94            Default: ErrorLevel.IMMEDIATE
  95        error_message_context: The amount of context to capture from a query string when displaying
  96            the error message (in number of characters).
  97            Default: 100
  98        max_errors: Maximum number of error messages to include in a raised ParseError.
  99            This is only relevant if error_level is ErrorLevel.RAISE.
 100            Default: 3
 101    """
 102
 103    FUNCTIONS: t.Dict[str, t.Callable] = {
 104        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 105        "CONCAT": lambda args, dialect: exp.Concat(
 106            expressions=args,
 107            safe=not dialect.STRICT_STRING_CONCAT,
 108            coalesce=dialect.CONCAT_COALESCE,
 109        ),
 110        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 111            expressions=args,
 112            safe=not dialect.STRICT_STRING_CONCAT,
 113            coalesce=dialect.CONCAT_COALESCE,
 114        ),
 115        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 116            this=seq_get(args, 0),
 117            to=exp.DataType(this=exp.DataType.Type.TEXT),
 118        ),
 119        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 120        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 121        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 122        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 123        "LIKE": build_like,
 124        "LOG": build_logarithm,
 125        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 126        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 127        "MOD": lambda args: exp.Mod(this=seq_get(args, 0), expression=seq_get(args, 1)),
 128        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 129            this=seq_get(args, 0),
 130            to=exp.DataType(this=exp.DataType.Type.TEXT),
 131        ),
 132        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 133            this=exp.Cast(
 134                this=seq_get(args, 0),
 135                to=exp.DataType(this=exp.DataType.Type.TEXT),
 136            ),
 137            start=exp.Literal.number(1),
 138            length=exp.Literal.number(10),
 139        ),
 140        "VAR_MAP": build_var_map,
 141    }
 142
 143    NO_PAREN_FUNCTIONS = {
 144        TokenType.CURRENT_DATE: exp.CurrentDate,
 145        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 146        TokenType.CURRENT_TIME: exp.CurrentTime,
 147        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 148        TokenType.CURRENT_USER: exp.CurrentUser,
 149    }
 150
 151    STRUCT_TYPE_TOKENS = {
 152        TokenType.NESTED,
 153        TokenType.OBJECT,
 154        TokenType.STRUCT,
 155    }
 156
 157    NESTED_TYPE_TOKENS = {
 158        TokenType.ARRAY,
 159        TokenType.LOWCARDINALITY,
 160        TokenType.MAP,
 161        TokenType.NULLABLE,
 162        *STRUCT_TYPE_TOKENS,
 163    }
 164
 165    ENUM_TYPE_TOKENS = {
 166        TokenType.ENUM,
 167        TokenType.ENUM8,
 168        TokenType.ENUM16,
 169    }
 170
 171    AGGREGATE_TYPE_TOKENS = {
 172        TokenType.AGGREGATEFUNCTION,
 173        TokenType.SIMPLEAGGREGATEFUNCTION,
 174    }
 175
 176    TYPE_TOKENS = {
 177        TokenType.BIT,
 178        TokenType.BOOLEAN,
 179        TokenType.TINYINT,
 180        TokenType.UTINYINT,
 181        TokenType.SMALLINT,
 182        TokenType.USMALLINT,
 183        TokenType.INT,
 184        TokenType.UINT,
 185        TokenType.BIGINT,
 186        TokenType.UBIGINT,
 187        TokenType.INT128,
 188        TokenType.UINT128,
 189        TokenType.INT256,
 190        TokenType.UINT256,
 191        TokenType.MEDIUMINT,
 192        TokenType.UMEDIUMINT,
 193        TokenType.FIXEDSTRING,
 194        TokenType.FLOAT,
 195        TokenType.DOUBLE,
 196        TokenType.CHAR,
 197        TokenType.NCHAR,
 198        TokenType.VARCHAR,
 199        TokenType.NVARCHAR,
 200        TokenType.BPCHAR,
 201        TokenType.TEXT,
 202        TokenType.MEDIUMTEXT,
 203        TokenType.LONGTEXT,
 204        TokenType.MEDIUMBLOB,
 205        TokenType.LONGBLOB,
 206        TokenType.BINARY,
 207        TokenType.VARBINARY,
 208        TokenType.JSON,
 209        TokenType.JSONB,
 210        TokenType.INTERVAL,
 211        TokenType.TINYBLOB,
 212        TokenType.TINYTEXT,
 213        TokenType.TIME,
 214        TokenType.TIMETZ,
 215        TokenType.TIMESTAMP,
 216        TokenType.TIMESTAMP_S,
 217        TokenType.TIMESTAMP_MS,
 218        TokenType.TIMESTAMP_NS,
 219        TokenType.TIMESTAMPTZ,
 220        TokenType.TIMESTAMPLTZ,
 221        TokenType.TIMESTAMPNTZ,
 222        TokenType.DATETIME,
 223        TokenType.DATETIME64,
 224        TokenType.DATE,
 225        TokenType.DATE32,
 226        TokenType.INT4RANGE,
 227        TokenType.INT4MULTIRANGE,
 228        TokenType.INT8RANGE,
 229        TokenType.INT8MULTIRANGE,
 230        TokenType.NUMRANGE,
 231        TokenType.NUMMULTIRANGE,
 232        TokenType.TSRANGE,
 233        TokenType.TSMULTIRANGE,
 234        TokenType.TSTZRANGE,
 235        TokenType.TSTZMULTIRANGE,
 236        TokenType.DATERANGE,
 237        TokenType.DATEMULTIRANGE,
 238        TokenType.DECIMAL,
 239        TokenType.UDECIMAL,
 240        TokenType.BIGDECIMAL,
 241        TokenType.UUID,
 242        TokenType.GEOGRAPHY,
 243        TokenType.GEOMETRY,
 244        TokenType.HLLSKETCH,
 245        TokenType.HSTORE,
 246        TokenType.PSEUDO_TYPE,
 247        TokenType.SUPER,
 248        TokenType.SERIAL,
 249        TokenType.SMALLSERIAL,
 250        TokenType.BIGSERIAL,
 251        TokenType.XML,
 252        TokenType.YEAR,
 253        TokenType.UNIQUEIDENTIFIER,
 254        TokenType.USERDEFINED,
 255        TokenType.MONEY,
 256        TokenType.SMALLMONEY,
 257        TokenType.ROWVERSION,
 258        TokenType.IMAGE,
 259        TokenType.VARIANT,
 260        TokenType.OBJECT,
 261        TokenType.OBJECT_IDENTIFIER,
 262        TokenType.INET,
 263        TokenType.IPADDRESS,
 264        TokenType.IPPREFIX,
 265        TokenType.IPV4,
 266        TokenType.IPV6,
 267        TokenType.UNKNOWN,
 268        TokenType.NULL,
 269        TokenType.NAME,
 270        TokenType.TDIGEST,
 271        *ENUM_TYPE_TOKENS,
 272        *NESTED_TYPE_TOKENS,
 273        *AGGREGATE_TYPE_TOKENS,
 274    }
 275
 276    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 277        TokenType.BIGINT: TokenType.UBIGINT,
 278        TokenType.INT: TokenType.UINT,
 279        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 280        TokenType.SMALLINT: TokenType.USMALLINT,
 281        TokenType.TINYINT: TokenType.UTINYINT,
 282        TokenType.DECIMAL: TokenType.UDECIMAL,
 283    }
 284
 285    SUBQUERY_PREDICATES = {
 286        TokenType.ANY: exp.Any,
 287        TokenType.ALL: exp.All,
 288        TokenType.EXISTS: exp.Exists,
 289        TokenType.SOME: exp.Any,
 290    }
 291
 292    RESERVED_TOKENS = {
 293        *Tokenizer.SINGLE_TOKENS.values(),
 294        TokenType.SELECT,
 295    } - {TokenType.IDENTIFIER}
 296
 297    DB_CREATABLES = {
 298        TokenType.DATABASE,
 299        TokenType.SCHEMA,
 300        TokenType.TABLE,
 301        TokenType.VIEW,
 302        TokenType.MODEL,
 303        TokenType.DICTIONARY,
 304        TokenType.SEQUENCE,
 305        TokenType.STORAGE_INTEGRATION,
 306    }
 307
 308    CREATABLES = {
 309        TokenType.COLUMN,
 310        TokenType.CONSTRAINT,
 311        TokenType.FUNCTION,
 312        TokenType.INDEX,
 313        TokenType.PROCEDURE,
 314        TokenType.FOREIGN_KEY,
 315        *DB_CREATABLES,
 316    }
 317
 318    # Tokens that can represent identifiers
 319    ID_VAR_TOKENS = {
 320        TokenType.VAR,
 321        TokenType.ANTI,
 322        TokenType.APPLY,
 323        TokenType.ASC,
 324        TokenType.ASOF,
 325        TokenType.AUTO_INCREMENT,
 326        TokenType.BEGIN,
 327        TokenType.BPCHAR,
 328        TokenType.CACHE,
 329        TokenType.CASE,
 330        TokenType.COLLATE,
 331        TokenType.COMMAND,
 332        TokenType.COMMENT,
 333        TokenType.COMMIT,
 334        TokenType.CONSTRAINT,
 335        TokenType.COPY,
 336        TokenType.DEFAULT,
 337        TokenType.DELETE,
 338        TokenType.DESC,
 339        TokenType.DESCRIBE,
 340        TokenType.DICTIONARY,
 341        TokenType.DIV,
 342        TokenType.END,
 343        TokenType.EXECUTE,
 344        TokenType.ESCAPE,
 345        TokenType.FALSE,
 346        TokenType.FIRST,
 347        TokenType.FILTER,
 348        TokenType.FINAL,
 349        TokenType.FORMAT,
 350        TokenType.FULL,
 351        TokenType.IDENTIFIER,
 352        TokenType.IS,
 353        TokenType.ISNULL,
 354        TokenType.INTERVAL,
 355        TokenType.KEEP,
 356        TokenType.KILL,
 357        TokenType.LEFT,
 358        TokenType.LOAD,
 359        TokenType.MERGE,
 360        TokenType.NATURAL,
 361        TokenType.NEXT,
 362        TokenType.OFFSET,
 363        TokenType.OPERATOR,
 364        TokenType.ORDINALITY,
 365        TokenType.OVERLAPS,
 366        TokenType.OVERWRITE,
 367        TokenType.PARTITION,
 368        TokenType.PERCENT,
 369        TokenType.PIVOT,
 370        TokenType.PRAGMA,
 371        TokenType.RANGE,
 372        TokenType.RECURSIVE,
 373        TokenType.REFERENCES,
 374        TokenType.REFRESH,
 375        TokenType.REPLACE,
 376        TokenType.RIGHT,
 377        TokenType.ROW,
 378        TokenType.ROWS,
 379        TokenType.SEMI,
 380        TokenType.SET,
 381        TokenType.SETTINGS,
 382        TokenType.SHOW,
 383        TokenType.TEMPORARY,
 384        TokenType.TOP,
 385        TokenType.TRUE,
 386        TokenType.TRUNCATE,
 387        TokenType.UNIQUE,
 388        TokenType.UNPIVOT,
 389        TokenType.UPDATE,
 390        TokenType.USE,
 391        TokenType.VOLATILE,
 392        TokenType.WINDOW,
 393        *CREATABLES,
 394        *SUBQUERY_PREDICATES,
 395        *TYPE_TOKENS,
 396        *NO_PAREN_FUNCTIONS,
 397    }
 398
 399    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 400
 401    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 402        TokenType.ANTI,
 403        TokenType.APPLY,
 404        TokenType.ASOF,
 405        TokenType.FULL,
 406        TokenType.LEFT,
 407        TokenType.LOCK,
 408        TokenType.NATURAL,
 409        TokenType.OFFSET,
 410        TokenType.RIGHT,
 411        TokenType.SEMI,
 412        TokenType.WINDOW,
 413    }
 414
 415    ALIAS_TOKENS = ID_VAR_TOKENS
 416
 417    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 418
 419    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 420
 421    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 422
 423    FUNC_TOKENS = {
 424        TokenType.COLLATE,
 425        TokenType.COMMAND,
 426        TokenType.CURRENT_DATE,
 427        TokenType.CURRENT_DATETIME,
 428        TokenType.CURRENT_TIMESTAMP,
 429        TokenType.CURRENT_TIME,
 430        TokenType.CURRENT_USER,
 431        TokenType.FILTER,
 432        TokenType.FIRST,
 433        TokenType.FORMAT,
 434        TokenType.GLOB,
 435        TokenType.IDENTIFIER,
 436        TokenType.INDEX,
 437        TokenType.ISNULL,
 438        TokenType.ILIKE,
 439        TokenType.INSERT,
 440        TokenType.LIKE,
 441        TokenType.MERGE,
 442        TokenType.OFFSET,
 443        TokenType.PRIMARY_KEY,
 444        TokenType.RANGE,
 445        TokenType.REPLACE,
 446        TokenType.RLIKE,
 447        TokenType.ROW,
 448        TokenType.UNNEST,
 449        TokenType.VAR,
 450        TokenType.LEFT,
 451        TokenType.RIGHT,
 452        TokenType.SEQUENCE,
 453        TokenType.DATE,
 454        TokenType.DATETIME,
 455        TokenType.TABLE,
 456        TokenType.TIMESTAMP,
 457        TokenType.TIMESTAMPTZ,
 458        TokenType.TRUNCATE,
 459        TokenType.WINDOW,
 460        TokenType.XOR,
 461        *TYPE_TOKENS,
 462        *SUBQUERY_PREDICATES,
 463    }
 464
 465    CONJUNCTION = {
 466        TokenType.AND: exp.And,
 467        TokenType.OR: exp.Or,
 468    }
 469
 470    EQUALITY = {
 471        TokenType.COLON_EQ: exp.PropertyEQ,
 472        TokenType.EQ: exp.EQ,
 473        TokenType.NEQ: exp.NEQ,
 474        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 475    }
 476
 477    COMPARISON = {
 478        TokenType.GT: exp.GT,
 479        TokenType.GTE: exp.GTE,
 480        TokenType.LT: exp.LT,
 481        TokenType.LTE: exp.LTE,
 482    }
 483
 484    BITWISE = {
 485        TokenType.AMP: exp.BitwiseAnd,
 486        TokenType.CARET: exp.BitwiseXor,
 487        TokenType.PIPE: exp.BitwiseOr,
 488    }
 489
 490    TERM = {
 491        TokenType.DASH: exp.Sub,
 492        TokenType.PLUS: exp.Add,
 493        TokenType.MOD: exp.Mod,
 494        TokenType.COLLATE: exp.Collate,
 495    }
 496
 497    FACTOR = {
 498        TokenType.DIV: exp.IntDiv,
 499        TokenType.LR_ARROW: exp.Distance,
 500        TokenType.SLASH: exp.Div,
 501        TokenType.STAR: exp.Mul,
 502    }
 503
 504    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 505
 506    TIMES = {
 507        TokenType.TIME,
 508        TokenType.TIMETZ,
 509    }
 510
 511    TIMESTAMPS = {
 512        TokenType.TIMESTAMP,
 513        TokenType.TIMESTAMPTZ,
 514        TokenType.TIMESTAMPLTZ,
 515        *TIMES,
 516    }
 517
 518    SET_OPERATIONS = {
 519        TokenType.UNION,
 520        TokenType.INTERSECT,
 521        TokenType.EXCEPT,
 522    }
 523
 524    JOIN_METHODS = {
 525        TokenType.ASOF,
 526        TokenType.NATURAL,
 527        TokenType.POSITIONAL,
 528    }
 529
 530    JOIN_SIDES = {
 531        TokenType.LEFT,
 532        TokenType.RIGHT,
 533        TokenType.FULL,
 534    }
 535
 536    JOIN_KINDS = {
 537        TokenType.INNER,
 538        TokenType.OUTER,
 539        TokenType.CROSS,
 540        TokenType.SEMI,
 541        TokenType.ANTI,
 542    }
 543
 544    JOIN_HINTS: t.Set[str] = set()
 545
 546    LAMBDAS = {
 547        TokenType.ARROW: lambda self, expressions: self.expression(
 548            exp.Lambda,
 549            this=self._replace_lambda(
 550                self._parse_conjunction(),
 551                {node.name for node in expressions},
 552            ),
 553            expressions=expressions,
 554        ),
 555        TokenType.FARROW: lambda self, expressions: self.expression(
 556            exp.Kwarg,
 557            this=exp.var(expressions[0].name),
 558            expression=self._parse_conjunction(),
 559        ),
 560    }
 561
 562    COLUMN_OPERATORS = {
 563        TokenType.DOT: None,
 564        TokenType.DCOLON: lambda self, this, to: self.expression(
 565            exp.Cast if self.STRICT_CAST else exp.TryCast,
 566            this=this,
 567            to=to,
 568        ),
 569        TokenType.ARROW: lambda self, this, path: self.expression(
 570            exp.JSONExtract,
 571            this=this,
 572            expression=self.dialect.to_json_path(path),
 573            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 574        ),
 575        TokenType.DARROW: lambda self, this, path: self.expression(
 576            exp.JSONExtractScalar,
 577            this=this,
 578            expression=self.dialect.to_json_path(path),
 579            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 580        ),
 581        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 582            exp.JSONBExtract,
 583            this=this,
 584            expression=path,
 585        ),
 586        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 587            exp.JSONBExtractScalar,
 588            this=this,
 589            expression=path,
 590        ),
 591        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 592            exp.JSONBContains,
 593            this=this,
 594            expression=key,
 595        ),
 596    }
 597
 598    EXPRESSION_PARSERS = {
 599        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 600        exp.Column: lambda self: self._parse_column(),
 601        exp.Condition: lambda self: self._parse_conjunction(),
 602        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 603        exp.Expression: lambda self: self._parse_expression(),
 604        exp.From: lambda self: self._parse_from(joins=True),
 605        exp.Group: lambda self: self._parse_group(),
 606        exp.Having: lambda self: self._parse_having(),
 607        exp.Identifier: lambda self: self._parse_id_var(),
 608        exp.Join: lambda self: self._parse_join(),
 609        exp.Lambda: lambda self: self._parse_lambda(),
 610        exp.Lateral: lambda self: self._parse_lateral(),
 611        exp.Limit: lambda self: self._parse_limit(),
 612        exp.Offset: lambda self: self._parse_offset(),
 613        exp.Order: lambda self: self._parse_order(),
 614        exp.Ordered: lambda self: self._parse_ordered(),
 615        exp.Properties: lambda self: self._parse_properties(),
 616        exp.Qualify: lambda self: self._parse_qualify(),
 617        exp.Returning: lambda self: self._parse_returning(),
 618        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 619        exp.Table: lambda self: self._parse_table_parts(),
 620        exp.TableAlias: lambda self: self._parse_table_alias(),
 621        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 622        exp.Where: lambda self: self._parse_where(),
 623        exp.Window: lambda self: self._parse_named_window(),
 624        exp.With: lambda self: self._parse_with(),
 625        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 626    }
 627
 628    STATEMENT_PARSERS = {
 629        TokenType.ALTER: lambda self: self._parse_alter(),
 630        TokenType.BEGIN: lambda self: self._parse_transaction(),
 631        TokenType.CACHE: lambda self: self._parse_cache(),
 632        TokenType.COMMENT: lambda self: self._parse_comment(),
 633        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 634        TokenType.COPY: lambda self: self._parse_copy(),
 635        TokenType.CREATE: lambda self: self._parse_create(),
 636        TokenType.DELETE: lambda self: self._parse_delete(),
 637        TokenType.DESC: lambda self: self._parse_describe(),
 638        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 639        TokenType.DROP: lambda self: self._parse_drop(),
 640        TokenType.INSERT: lambda self: self._parse_insert(),
 641        TokenType.KILL: lambda self: self._parse_kill(),
 642        TokenType.LOAD: lambda self: self._parse_load(),
 643        TokenType.MERGE: lambda self: self._parse_merge(),
 644        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 645        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 646        TokenType.REFRESH: lambda self: self._parse_refresh(),
 647        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 648        TokenType.SET: lambda self: self._parse_set(),
 649        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 650        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 651        TokenType.UPDATE: lambda self: self._parse_update(),
 652        TokenType.USE: lambda self: self.expression(
 653            exp.Use,
 654            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 655            this=self._parse_table(schema=False),
 656        ),
 657    }
 658
 659    UNARY_PARSERS = {
 660        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 661        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 662        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 663        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 664        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 665        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 666    }
 667
 668    STRING_PARSERS = {
 669        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 670            exp.RawString, this=token.text
 671        ),
 672        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 673            exp.National, this=token.text
 674        ),
 675        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 676        TokenType.STRING: lambda self, token: self.expression(
 677            exp.Literal, this=token.text, is_string=True
 678        ),
 679        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 680            exp.UnicodeString,
 681            this=token.text,
 682            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 683        ),
 684    }
 685
 686    NUMERIC_PARSERS = {
 687        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 688        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 689        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 690        TokenType.NUMBER: lambda self, token: self.expression(
 691            exp.Literal, this=token.text, is_string=False
 692        ),
 693    }
 694
 695    PRIMARY_PARSERS = {
 696        **STRING_PARSERS,
 697        **NUMERIC_PARSERS,
 698        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 699        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 700        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 701        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 702        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 703        TokenType.STAR: lambda self, _: self.expression(
 704            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 705        ),
 706    }
 707
 708    PLACEHOLDER_PARSERS = {
 709        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 710        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 711        TokenType.COLON: lambda self: (
 712            self.expression(exp.Placeholder, this=self._prev.text)
 713            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 714            else None
 715        ),
 716    }
 717
 718    RANGE_PARSERS = {
 719        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 720        TokenType.GLOB: binary_range_parser(exp.Glob),
 721        TokenType.ILIKE: binary_range_parser(exp.ILike),
 722        TokenType.IN: lambda self, this: self._parse_in(this),
 723        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 724        TokenType.IS: lambda self, this: self._parse_is(this),
 725        TokenType.LIKE: binary_range_parser(exp.Like),
 726        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 727        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 728        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 729        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 730    }
 731
 732    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 733        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 734        "AUTO": lambda self: self._parse_auto_property(),
 735        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 736        "BACKUP": lambda self: self.expression(
 737            exp.BackupProperty, this=self._parse_var(any_token=True)
 738        ),
 739        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 740        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 741        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 742        "CHECKSUM": lambda self: self._parse_checksum(),
 743        "CLUSTER BY": lambda self: self._parse_cluster(),
 744        "CLUSTERED": lambda self: self._parse_clustered_by(),
 745        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 746            exp.CollateProperty, **kwargs
 747        ),
 748        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 749        "CONTAINS": lambda self: self._parse_contains_property(),
 750        "COPY": lambda self: self._parse_copy_property(),
 751        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 752        "DEFINER": lambda self: self._parse_definer(),
 753        "DETERMINISTIC": lambda self: self.expression(
 754            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 755        ),
 756        "DISTKEY": lambda self: self._parse_distkey(),
 757        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 758        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 759        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 760        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 761        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 762        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 763        "FREESPACE": lambda self: self._parse_freespace(),
 764        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 765        "HEAP": lambda self: self.expression(exp.HeapProperty),
 766        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 767        "IMMUTABLE": lambda self: self.expression(
 768            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 769        ),
 770        "INHERITS": lambda self: self.expression(
 771            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 772        ),
 773        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 774        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 775        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 776        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 777        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 778        "LIKE": lambda self: self._parse_create_like(),
 779        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 780        "LOCK": lambda self: self._parse_locking(),
 781        "LOCKING": lambda self: self._parse_locking(),
 782        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 783        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 784        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 785        "MODIFIES": lambda self: self._parse_modifies_property(),
 786        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 787        "NO": lambda self: self._parse_no_property(),
 788        "ON": lambda self: self._parse_on_property(),
 789        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 790        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 791        "PARTITION": lambda self: self._parse_partitioned_of(),
 792        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 793        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 794        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 795        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 796        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 797        "READS": lambda self: self._parse_reads_property(),
 798        "REMOTE": lambda self: self._parse_remote_with_connection(),
 799        "RETURNS": lambda self: self._parse_returns(),
 800        "ROW": lambda self: self._parse_row(),
 801        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 802        "SAMPLE": lambda self: self.expression(
 803            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 804        ),
 805        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 806        "SETTINGS": lambda self: self.expression(
 807            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 808        ),
 809        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 810        "SORTKEY": lambda self: self._parse_sortkey(),
 811        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 812        "STABLE": lambda self: self.expression(
 813            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 814        ),
 815        "STORED": lambda self: self._parse_stored(),
 816        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 817        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 818        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 819        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 820        "TO": lambda self: self._parse_to_table(),
 821        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 822        "TRANSFORM": lambda self: self.expression(
 823            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 824        ),
 825        "TTL": lambda self: self._parse_ttl(),
 826        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 827        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 828        "VOLATILE": lambda self: self._parse_volatile_property(),
 829        "WITH": lambda self: self._parse_with_property(),
 830    }
 831
 832    CONSTRAINT_PARSERS = {
 833        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 834        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 835        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 836        "CHARACTER SET": lambda self: self.expression(
 837            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 838        ),
 839        "CHECK": lambda self: self.expression(
 840            exp.CheckColumnConstraint,
 841            this=self._parse_wrapped(self._parse_conjunction),
 842            enforced=self._match_text_seq("ENFORCED"),
 843        ),
 844        "COLLATE": lambda self: self.expression(
 845            exp.CollateColumnConstraint, this=self._parse_var()
 846        ),
 847        "COMMENT": lambda self: self.expression(
 848            exp.CommentColumnConstraint, this=self._parse_string()
 849        ),
 850        "COMPRESS": lambda self: self._parse_compress(),
 851        "CLUSTERED": lambda self: self.expression(
 852            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 853        ),
 854        "NONCLUSTERED": lambda self: self.expression(
 855            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 856        ),
 857        "DEFAULT": lambda self: self.expression(
 858            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 859        ),
 860        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 861        "EPHEMERAL": lambda self: self.expression(
 862            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 863        ),
 864        "EXCLUDE": lambda self: self.expression(
 865            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 866        ),
 867        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 868        "FORMAT": lambda self: self.expression(
 869            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 870        ),
 871        "GENERATED": lambda self: self._parse_generated_as_identity(),
 872        "IDENTITY": lambda self: self._parse_auto_increment(),
 873        "INLINE": lambda self: self._parse_inline(),
 874        "LIKE": lambda self: self._parse_create_like(),
 875        "NOT": lambda self: self._parse_not_constraint(),
 876        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 877        "ON": lambda self: (
 878            self._match(TokenType.UPDATE)
 879            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 880        )
 881        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 882        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 883        "PERIOD": lambda self: self._parse_period_for_system_time(),
 884        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 885        "REFERENCES": lambda self: self._parse_references(match=False),
 886        "TITLE": lambda self: self.expression(
 887            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 888        ),
 889        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 890        "UNIQUE": lambda self: self._parse_unique(),
 891        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 892        "WITH": lambda self: self.expression(
 893            exp.Properties, expressions=self._parse_wrapped_properties()
 894        ),
 895    }
 896
 897    ALTER_PARSERS = {
 898        "ADD": lambda self: self._parse_alter_table_add(),
 899        "ALTER": lambda self: self._parse_alter_table_alter(),
 900        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 901        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 902        "DROP": lambda self: self._parse_alter_table_drop(),
 903        "RENAME": lambda self: self._parse_alter_table_rename(),
 904    }
 905
 906    SCHEMA_UNNAMED_CONSTRAINTS = {
 907        "CHECK",
 908        "EXCLUDE",
 909        "FOREIGN KEY",
 910        "LIKE",
 911        "PERIOD",
 912        "PRIMARY KEY",
 913        "UNIQUE",
 914    }
 915
 916    NO_PAREN_FUNCTION_PARSERS = {
 917        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 918        "CASE": lambda self: self._parse_case(),
 919        "IF": lambda self: self._parse_if(),
 920        "NEXT": lambda self: self._parse_next_value_for(),
 921    }
 922
 923    INVALID_FUNC_NAME_TOKENS = {
 924        TokenType.IDENTIFIER,
 925        TokenType.STRING,
 926    }
 927
 928    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 929
 930    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
 931
 932    FUNCTION_PARSERS = {
 933        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 934        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 935        "DECODE": lambda self: self._parse_decode(),
 936        "EXTRACT": lambda self: self._parse_extract(),
 937        "JSON_OBJECT": lambda self: self._parse_json_object(),
 938        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 939        "JSON_TABLE": lambda self: self._parse_json_table(),
 940        "MATCH": lambda self: self._parse_match_against(),
 941        "OPENJSON": lambda self: self._parse_open_json(),
 942        "POSITION": lambda self: self._parse_position(),
 943        "PREDICT": lambda self: self._parse_predict(),
 944        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 945        "STRING_AGG": lambda self: self._parse_string_agg(),
 946        "SUBSTRING": lambda self: self._parse_substring(),
 947        "TRIM": lambda self: self._parse_trim(),
 948        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 949        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 950    }
 951
 952    QUERY_MODIFIER_PARSERS = {
 953        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 954        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
 955        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 956        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 957        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 958        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 959        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 960        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 961        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 962        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 963        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 964        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 965        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 966        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 967        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 968        TokenType.CLUSTER_BY: lambda self: (
 969            "cluster",
 970            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 971        ),
 972        TokenType.DISTRIBUTE_BY: lambda self: (
 973            "distribute",
 974            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 975        ),
 976        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 977        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 978        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 979    }
 980
 981    SET_PARSERS = {
 982        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 983        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 984        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 985        "TRANSACTION": lambda self: self._parse_set_transaction(),
 986    }
 987
 988    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 989
 990    TYPE_LITERAL_PARSERS = {
 991        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 992    }
 993
 994    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 995
 996    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 997
 998    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 999    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1000        "ISOLATION": (
1001            ("LEVEL", "REPEATABLE", "READ"),
1002            ("LEVEL", "READ", "COMMITTED"),
1003            ("LEVEL", "READ", "UNCOMITTED"),
1004            ("LEVEL", "SERIALIZABLE"),
1005        ),
1006        "READ": ("WRITE", "ONLY"),
1007    }
1008
1009    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1010        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1011    )
1012    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1013
1014    CREATE_SEQUENCE: OPTIONS_TYPE = {
1015        "SCALE": ("EXTEND", "NOEXTEND"),
1016        "SHARD": ("EXTEND", "NOEXTEND"),
1017        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1018        **dict.fromkeys(
1019            (
1020                "SESSION",
1021                "GLOBAL",
1022                "KEEP",
1023                "NOKEEP",
1024                "ORDER",
1025                "NOORDER",
1026                "NOCACHE",
1027                "CYCLE",
1028                "NOCYCLE",
1029                "NOMINVALUE",
1030                "NOMAXVALUE",
1031                "NOSCALE",
1032                "NOSHARD",
1033            ),
1034            tuple(),
1035        ),
1036    }
1037
1038    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1039
1040    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
1041
1042    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1043
1044    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1045
1046    CLONE_KEYWORDS = {"CLONE", "COPY"}
1047    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1048
1049    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1050
1051    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1052
1053    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1054
1055    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1056
1057    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1058    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1059    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1060
1061    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1062
1063    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1064
1065    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
1066
1067    DISTINCT_TOKENS = {TokenType.DISTINCT}
1068
1069    NULL_TOKENS = {TokenType.NULL}
1070
1071    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1072
1073    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1074
1075    STRICT_CAST = True
1076
1077    PREFIXED_PIVOT_COLUMNS = False
1078    IDENTIFY_PIVOT_STRINGS = False
1079
1080    LOG_DEFAULTS_TO_LN = False
1081
1082    # Whether ADD is present for each column added by ALTER TABLE
1083    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1084
1085    # Whether the table sample clause expects CSV syntax
1086    TABLESAMPLE_CSV = False
1087
1088    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1089    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1090
1091    # Whether the TRIM function expects the characters to trim as its first argument
1092    TRIM_PATTERN_FIRST = False
1093
1094    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1095    STRING_ALIASES = False
1096
1097    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1098    MODIFIERS_ATTACHED_TO_UNION = True
1099    UNION_MODIFIERS = {"order", "limit", "offset"}
1100
1101    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1102    NO_PAREN_IF_COMMANDS = True
1103
1104    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1105    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1106
1107    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1108    # If this is True and '(' is not found, the keyword will be treated as an identifier
1109    VALUES_FOLLOWED_BY_PAREN = True
1110
1111    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1112    SUPPORTS_IMPLICIT_UNNEST = False
1113
1114    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1115    INTERVAL_SPANS = True
1116
1117    # Whether a PARTITION clause can follow a table reference
1118    SUPPORTS_PARTITION_SELECTION = False
1119
1120    __slots__ = (
1121        "error_level",
1122        "error_message_context",
1123        "max_errors",
1124        "dialect",
1125        "sql",
1126        "errors",
1127        "_tokens",
1128        "_index",
1129        "_curr",
1130        "_next",
1131        "_prev",
1132        "_prev_comments",
1133    )
1134
1135    # Autofilled
1136    SHOW_TRIE: t.Dict = {}
1137    SET_TRIE: t.Dict = {}
1138
1139    def __init__(
1140        self,
1141        error_level: t.Optional[ErrorLevel] = None,
1142        error_message_context: int = 100,
1143        max_errors: int = 3,
1144        dialect: DialectType = None,
1145    ):
1146        from sqlglot.dialects import Dialect
1147
1148        self.error_level = error_level or ErrorLevel.IMMEDIATE
1149        self.error_message_context = error_message_context
1150        self.max_errors = max_errors
1151        self.dialect = Dialect.get_or_raise(dialect)
1152        self.reset()
1153
1154    def reset(self):
1155        self.sql = ""
1156        self.errors = []
1157        self._tokens = []
1158        self._index = 0
1159        self._curr = None
1160        self._next = None
1161        self._prev = None
1162        self._prev_comments = None
1163
1164    def parse(
1165        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1166    ) -> t.List[t.Optional[exp.Expression]]:
1167        """
1168        Parses a list of tokens and returns a list of syntax trees, one tree
1169        per parsed SQL statement.
1170
1171        Args:
1172            raw_tokens: The list of tokens.
1173            sql: The original SQL string, used to produce helpful debug messages.
1174
1175        Returns:
1176            The list of the produced syntax trees.
1177        """
1178        return self._parse(
1179            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1180        )
1181
1182    def parse_into(
1183        self,
1184        expression_types: exp.IntoType,
1185        raw_tokens: t.List[Token],
1186        sql: t.Optional[str] = None,
1187    ) -> t.List[t.Optional[exp.Expression]]:
1188        """
1189        Parses a list of tokens into a given Expression type. If a collection of Expression
1190        types is given instead, this method will try to parse the token list into each one
1191        of them, stopping at the first for which the parsing succeeds.
1192
1193        Args:
1194            expression_types: The expression type(s) to try and parse the token list into.
1195            raw_tokens: The list of tokens.
1196            sql: The original SQL string, used to produce helpful debug messages.
1197
1198        Returns:
1199            The target Expression.
1200        """
1201        errors = []
1202        for expression_type in ensure_list(expression_types):
1203            parser = self.EXPRESSION_PARSERS.get(expression_type)
1204            if not parser:
1205                raise TypeError(f"No parser registered for {expression_type}")
1206
1207            try:
1208                return self._parse(parser, raw_tokens, sql)
1209            except ParseError as e:
1210                e.errors[0]["into_expression"] = expression_type
1211                errors.append(e)
1212
1213        raise ParseError(
1214            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1215            errors=merge_errors(errors),
1216        ) from errors[-1]
1217
1218    def _parse(
1219        self,
1220        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1221        raw_tokens: t.List[Token],
1222        sql: t.Optional[str] = None,
1223    ) -> t.List[t.Optional[exp.Expression]]:
1224        self.reset()
1225        self.sql = sql or ""
1226
1227        total = len(raw_tokens)
1228        chunks: t.List[t.List[Token]] = [[]]
1229
1230        for i, token in enumerate(raw_tokens):
1231            if token.token_type == TokenType.SEMICOLON:
1232                if i < total - 1:
1233                    chunks.append([])
1234            else:
1235                chunks[-1].append(token)
1236
1237        expressions = []
1238
1239        for tokens in chunks:
1240            self._index = -1
1241            self._tokens = tokens
1242            self._advance()
1243
1244            expressions.append(parse_method(self))
1245
1246            if self._index < len(self._tokens):
1247                self.raise_error("Invalid expression / Unexpected token")
1248
1249            self.check_errors()
1250
1251        return expressions
1252
1253    def check_errors(self) -> None:
1254        """Logs or raises any found errors, depending on the chosen error level setting."""
1255        if self.error_level == ErrorLevel.WARN:
1256            for error in self.errors:
1257                logger.error(str(error))
1258        elif self.error_level == ErrorLevel.RAISE and self.errors:
1259            raise ParseError(
1260                concat_messages(self.errors, self.max_errors),
1261                errors=merge_errors(self.errors),
1262            )
1263
1264    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1265        """
1266        Appends an error in the list of recorded errors or raises it, depending on the chosen
1267        error level setting.
1268        """
1269        token = token or self._curr or self._prev or Token.string("")
1270        start = token.start
1271        end = token.end + 1
1272        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1273        highlight = self.sql[start:end]
1274        end_context = self.sql[end : end + self.error_message_context]
1275
1276        error = ParseError.new(
1277            f"{message}. Line {token.line}, Col: {token.col}.\n"
1278            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1279            description=message,
1280            line=token.line,
1281            col=token.col,
1282            start_context=start_context,
1283            highlight=highlight,
1284            end_context=end_context,
1285        )
1286
1287        if self.error_level == ErrorLevel.IMMEDIATE:
1288            raise error
1289
1290        self.errors.append(error)
1291
1292    def expression(
1293        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1294    ) -> E:
1295        """
1296        Creates a new, validated Expression.
1297
1298        Args:
1299            exp_class: The expression class to instantiate.
1300            comments: An optional list of comments to attach to the expression.
1301            kwargs: The arguments to set for the expression along with their respective values.
1302
1303        Returns:
1304            The target expression.
1305        """
1306        instance = exp_class(**kwargs)
1307        instance.add_comments(comments) if comments else self._add_comments(instance)
1308        return self.validate_expression(instance)
1309
1310    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1311        if expression and self._prev_comments:
1312            expression.add_comments(self._prev_comments)
1313            self._prev_comments = None
1314
1315    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1316        """
1317        Validates an Expression, making sure that all its mandatory arguments are set.
1318
1319        Args:
1320            expression: The expression to validate.
1321            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1322
1323        Returns:
1324            The validated expression.
1325        """
1326        if self.error_level != ErrorLevel.IGNORE:
1327            for error_message in expression.error_messages(args):
1328                self.raise_error(error_message)
1329
1330        return expression
1331
1332    def _find_sql(self, start: Token, end: Token) -> str:
1333        return self.sql[start.start : end.end + 1]
1334
1335    def _is_connected(self) -> bool:
1336        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1337
1338    def _advance(self, times: int = 1) -> None:
1339        self._index += times
1340        self._curr = seq_get(self._tokens, self._index)
1341        self._next = seq_get(self._tokens, self._index + 1)
1342
1343        if self._index > 0:
1344            self._prev = self._tokens[self._index - 1]
1345            self._prev_comments = self._prev.comments
1346        else:
1347            self._prev = None
1348            self._prev_comments = None
1349
1350    def _retreat(self, index: int) -> None:
1351        if index != self._index:
1352            self._advance(index - self._index)
1353
1354    def _warn_unsupported(self) -> None:
1355        if len(self._tokens) <= 1:
1356            return
1357
1358        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1359        # interested in emitting a warning for the one being currently processed.
1360        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1361
1362        logger.warning(
1363            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1364        )
1365
1366    def _parse_command(self) -> exp.Command:
1367        self._warn_unsupported()
1368        return self.expression(
1369            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1370        )
1371
1372    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1373        """
1374        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
1375        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
1376        the parser state accordingly
1377        """
1378        index = self._index
1379        error_level = self.error_level
1380
1381        self.error_level = ErrorLevel.IMMEDIATE
1382        try:
1383            this = parse_method()
1384        except ParseError:
1385            this = None
1386        finally:
1387            if not this or retreat:
1388                self._retreat(index)
1389            self.error_level = error_level
1390
1391        return this
1392
1393    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1394        start = self._prev
1395        exists = self._parse_exists() if allow_exists else None
1396
1397        self._match(TokenType.ON)
1398
1399        materialized = self._match_text_seq("MATERIALIZED")
1400        kind = self._match_set(self.CREATABLES) and self._prev
1401        if not kind:
1402            return self._parse_as_command(start)
1403
1404        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1405            this = self._parse_user_defined_function(kind=kind.token_type)
1406        elif kind.token_type == TokenType.TABLE:
1407            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1408        elif kind.token_type == TokenType.COLUMN:
1409            this = self._parse_column()
1410        else:
1411            this = self._parse_id_var()
1412
1413        self._match(TokenType.IS)
1414
1415        return self.expression(
1416            exp.Comment,
1417            this=this,
1418            kind=kind.text,
1419            expression=self._parse_string(),
1420            exists=exists,
1421            materialized=materialized,
1422        )
1423
1424    def _parse_to_table(
1425        self,
1426    ) -> exp.ToTableProperty:
1427        table = self._parse_table_parts(schema=True)
1428        return self.expression(exp.ToTableProperty, this=table)
1429
1430    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1431    def _parse_ttl(self) -> exp.Expression:
1432        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1433            this = self._parse_bitwise()
1434
1435            if self._match_text_seq("DELETE"):
1436                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1437            if self._match_text_seq("RECOMPRESS"):
1438                return self.expression(
1439                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1440                )
1441            if self._match_text_seq("TO", "DISK"):
1442                return self.expression(
1443                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1444                )
1445            if self._match_text_seq("TO", "VOLUME"):
1446                return self.expression(
1447                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1448                )
1449
1450            return this
1451
1452        expressions = self._parse_csv(_parse_ttl_action)
1453        where = self._parse_where()
1454        group = self._parse_group()
1455
1456        aggregates = None
1457        if group and self._match(TokenType.SET):
1458            aggregates = self._parse_csv(self._parse_set_item)
1459
1460        return self.expression(
1461            exp.MergeTreeTTL,
1462            expressions=expressions,
1463            where=where,
1464            group=group,
1465            aggregates=aggregates,
1466        )
1467
1468    def _parse_statement(self) -> t.Optional[exp.Expression]:
1469        if self._curr is None:
1470            return None
1471
1472        if self._match_set(self.STATEMENT_PARSERS):
1473            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1474
1475        if self._match_set(Tokenizer.COMMANDS):
1476            return self._parse_command()
1477
1478        expression = self._parse_expression()
1479        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1480        return self._parse_query_modifiers(expression)
1481
1482    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1483        start = self._prev
1484        temporary = self._match(TokenType.TEMPORARY)
1485        materialized = self._match_text_seq("MATERIALIZED")
1486
1487        kind = self._match_set(self.CREATABLES) and self._prev.text
1488        if not kind:
1489            return self._parse_as_command(start)
1490
1491        if_exists = exists or self._parse_exists()
1492        table = self._parse_table_parts(
1493            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1494        )
1495
1496        if self._match(TokenType.L_PAREN, advance=False):
1497            expressions = self._parse_wrapped_csv(self._parse_types)
1498        else:
1499            expressions = None
1500
1501        return self.expression(
1502            exp.Drop,
1503            comments=start.comments,
1504            exists=if_exists,
1505            this=table,
1506            expressions=expressions,
1507            kind=kind,
1508            temporary=temporary,
1509            materialized=materialized,
1510            cascade=self._match_text_seq("CASCADE"),
1511            constraints=self._match_text_seq("CONSTRAINTS"),
1512            purge=self._match_text_seq("PURGE"),
1513        )
1514
1515    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1516        return (
1517            self._match_text_seq("IF")
1518            and (not not_ or self._match(TokenType.NOT))
1519            and self._match(TokenType.EXISTS)
1520        )
1521
1522    def _parse_create(self) -> exp.Create | exp.Command:
1523        # Note: this can't be None because we've matched a statement parser
1524        start = self._prev
1525        comments = self._prev_comments
1526
1527        replace = (
1528            start.token_type == TokenType.REPLACE
1529            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1530            or self._match_pair(TokenType.OR, TokenType.ALTER)
1531        )
1532
1533        unique = self._match(TokenType.UNIQUE)
1534
1535        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1536            self._advance()
1537
1538        properties = None
1539        create_token = self._match_set(self.CREATABLES) and self._prev
1540
1541        if not create_token:
1542            # exp.Properties.Location.POST_CREATE
1543            properties = self._parse_properties()
1544            create_token = self._match_set(self.CREATABLES) and self._prev
1545
1546            if not properties or not create_token:
1547                return self._parse_as_command(start)
1548
1549        exists = self._parse_exists(not_=True)
1550        this = None
1551        expression: t.Optional[exp.Expression] = None
1552        indexes = None
1553        no_schema_binding = None
1554        begin = None
1555        end = None
1556        clone = None
1557
1558        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1559            nonlocal properties
1560            if properties and temp_props:
1561                properties.expressions.extend(temp_props.expressions)
1562            elif temp_props:
1563                properties = temp_props
1564
1565        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1566            this = self._parse_user_defined_function(kind=create_token.token_type)
1567
1568            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1569            extend_props(self._parse_properties())
1570
1571            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1572
1573            if not expression:
1574                if self._match(TokenType.COMMAND):
1575                    expression = self._parse_as_command(self._prev)
1576                else:
1577                    begin = self._match(TokenType.BEGIN)
1578                    return_ = self._match_text_seq("RETURN")
1579
1580                    if self._match(TokenType.STRING, advance=False):
1581                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1582                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1583                        expression = self._parse_string()
1584                        extend_props(self._parse_properties())
1585                    else:
1586                        expression = self._parse_statement()
1587
1588                    end = self._match_text_seq("END")
1589
1590                    if return_:
1591                        expression = self.expression(exp.Return, this=expression)
1592        elif create_token.token_type == TokenType.INDEX:
1593            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1594            if not self._match(TokenType.ON):
1595                index = self._parse_id_var()
1596                anonymous = False
1597            else:
1598                index = None
1599                anonymous = True
1600
1601            this = self._parse_index(index=index, anonymous=anonymous)
1602        elif create_token.token_type in self.DB_CREATABLES:
1603            table_parts = self._parse_table_parts(
1604                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1605            )
1606
1607            # exp.Properties.Location.POST_NAME
1608            self._match(TokenType.COMMA)
1609            extend_props(self._parse_properties(before=True))
1610
1611            this = self._parse_schema(this=table_parts)
1612
1613            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1614            extend_props(self._parse_properties())
1615
1616            self._match(TokenType.ALIAS)
1617            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1618                # exp.Properties.Location.POST_ALIAS
1619                extend_props(self._parse_properties())
1620
1621            if create_token.token_type == TokenType.SEQUENCE:
1622                expression = self._parse_types()
1623                extend_props(self._parse_properties())
1624            else:
1625                expression = self._parse_ddl_select()
1626
1627            if create_token.token_type == TokenType.TABLE:
1628                # exp.Properties.Location.POST_EXPRESSION
1629                extend_props(self._parse_properties())
1630
1631                indexes = []
1632                while True:
1633                    index = self._parse_index()
1634
1635                    # exp.Properties.Location.POST_INDEX
1636                    extend_props(self._parse_properties())
1637
1638                    if not index:
1639                        break
1640                    else:
1641                        self._match(TokenType.COMMA)
1642                        indexes.append(index)
1643            elif create_token.token_type == TokenType.VIEW:
1644                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1645                    no_schema_binding = True
1646
1647            shallow = self._match_text_seq("SHALLOW")
1648
1649            if self._match_texts(self.CLONE_KEYWORDS):
1650                copy = self._prev.text.lower() == "copy"
1651                clone = self.expression(
1652                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1653                )
1654
1655        if self._curr:
1656            return self._parse_as_command(start)
1657
1658        return self.expression(
1659            exp.Create,
1660            comments=comments,
1661            this=this,
1662            kind=create_token.text.upper(),
1663            replace=replace,
1664            unique=unique,
1665            expression=expression,
1666            exists=exists,
1667            properties=properties,
1668            indexes=indexes,
1669            no_schema_binding=no_schema_binding,
1670            begin=begin,
1671            end=end,
1672            clone=clone,
1673        )
1674
1675    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1676        seq = exp.SequenceProperties()
1677
1678        options = []
1679        index = self._index
1680
1681        while self._curr:
1682            if self._match_text_seq("INCREMENT"):
1683                self._match_text_seq("BY")
1684                self._match_text_seq("=")
1685                seq.set("increment", self._parse_term())
1686            elif self._match_text_seq("MINVALUE"):
1687                seq.set("minvalue", self._parse_term())
1688            elif self._match_text_seq("MAXVALUE"):
1689                seq.set("maxvalue", self._parse_term())
1690            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1691                self._match_text_seq("=")
1692                seq.set("start", self._parse_term())
1693            elif self._match_text_seq("CACHE"):
1694                # T-SQL allows empty CACHE which is initialized dynamically
1695                seq.set("cache", self._parse_number() or True)
1696            elif self._match_text_seq("OWNED", "BY"):
1697                # "OWNED BY NONE" is the default
1698                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1699            else:
1700                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1701                if opt:
1702                    options.append(opt)
1703                else:
1704                    break
1705
1706        seq.set("options", options if options else None)
1707        return None if self._index == index else seq
1708
1709    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1710        # only used for teradata currently
1711        self._match(TokenType.COMMA)
1712
1713        kwargs = {
1714            "no": self._match_text_seq("NO"),
1715            "dual": self._match_text_seq("DUAL"),
1716            "before": self._match_text_seq("BEFORE"),
1717            "default": self._match_text_seq("DEFAULT"),
1718            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1719            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1720            "after": self._match_text_seq("AFTER"),
1721            "minimum": self._match_texts(("MIN", "MINIMUM")),
1722            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1723        }
1724
1725        if self._match_texts(self.PROPERTY_PARSERS):
1726            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1727            try:
1728                return parser(self, **{k: v for k, v in kwargs.items() if v})
1729            except TypeError:
1730                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1731
1732        return None
1733
1734    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1735        return self._parse_wrapped_csv(self._parse_property)
1736
1737    def _parse_property(self) -> t.Optional[exp.Expression]:
1738        if self._match_texts(self.PROPERTY_PARSERS):
1739            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1740
1741        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1742            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1743
1744        if self._match_text_seq("COMPOUND", "SORTKEY"):
1745            return self._parse_sortkey(compound=True)
1746
1747        if self._match_text_seq("SQL", "SECURITY"):
1748            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1749
1750        index = self._index
1751        key = self._parse_column()
1752
1753        if not self._match(TokenType.EQ):
1754            self._retreat(index)
1755            return self._parse_sequence_properties()
1756
1757        return self.expression(
1758            exp.Property,
1759            this=key.to_dot() if isinstance(key, exp.Column) else key,
1760            value=self._parse_bitwise() or self._parse_var(any_token=True),
1761        )
1762
1763    def _parse_stored(self) -> exp.FileFormatProperty:
1764        self._match(TokenType.ALIAS)
1765
1766        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1767        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1768
1769        return self.expression(
1770            exp.FileFormatProperty,
1771            this=(
1772                self.expression(
1773                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1774                )
1775                if input_format or output_format
1776                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1777            ),
1778        )
1779
1780    def _parse_unquoted_field(self):
1781        field = self._parse_field()
1782        if isinstance(field, exp.Identifier) and not field.quoted:
1783            field = exp.var(field)
1784
1785        return field
1786
1787    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1788        self._match(TokenType.EQ)
1789        self._match(TokenType.ALIAS)
1790
1791        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1792
1793    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1794        properties = []
1795        while True:
1796            if before:
1797                prop = self._parse_property_before()
1798            else:
1799                prop = self._parse_property()
1800            if not prop:
1801                break
1802            for p in ensure_list(prop):
1803                properties.append(p)
1804
1805        if properties:
1806            return self.expression(exp.Properties, expressions=properties)
1807
1808        return None
1809
1810    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1811        return self.expression(
1812            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1813        )
1814
1815    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1816        if self._index >= 2:
1817            pre_volatile_token = self._tokens[self._index - 2]
1818        else:
1819            pre_volatile_token = None
1820
1821        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1822            return exp.VolatileProperty()
1823
1824        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1825
1826    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1827        self._match_pair(TokenType.EQ, TokenType.ON)
1828
1829        prop = self.expression(exp.WithSystemVersioningProperty)
1830        if self._match(TokenType.L_PAREN):
1831            self._match_text_seq("HISTORY_TABLE", "=")
1832            prop.set("this", self._parse_table_parts())
1833
1834            if self._match(TokenType.COMMA):
1835                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1836                prop.set("expression", self._advance_any() and self._prev.text.upper())
1837
1838            self._match_r_paren()
1839
1840        return prop
1841
1842    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1843        if self._match(TokenType.L_PAREN, advance=False):
1844            return self._parse_wrapped_properties()
1845
1846        if self._match_text_seq("JOURNAL"):
1847            return self._parse_withjournaltable()
1848
1849        if self._match_texts(self.VIEW_ATTRIBUTES):
1850            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
1851
1852        if self._match_text_seq("DATA"):
1853            return self._parse_withdata(no=False)
1854        elif self._match_text_seq("NO", "DATA"):
1855            return self._parse_withdata(no=True)
1856
1857        if not self._next:
1858            return None
1859
1860        return self._parse_withisolatedloading()
1861
1862    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1863    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1864        self._match(TokenType.EQ)
1865
1866        user = self._parse_id_var()
1867        self._match(TokenType.PARAMETER)
1868        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1869
1870        if not user or not host:
1871            return None
1872
1873        return exp.DefinerProperty(this=f"{user}@{host}")
1874
1875    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1876        self._match(TokenType.TABLE)
1877        self._match(TokenType.EQ)
1878        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1879
1880    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1881        return self.expression(exp.LogProperty, no=no)
1882
1883    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1884        return self.expression(exp.JournalProperty, **kwargs)
1885
1886    def _parse_checksum(self) -> exp.ChecksumProperty:
1887        self._match(TokenType.EQ)
1888
1889        on = None
1890        if self._match(TokenType.ON):
1891            on = True
1892        elif self._match_text_seq("OFF"):
1893            on = False
1894
1895        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1896
1897    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
1898        return self.expression(
1899            exp.Cluster,
1900            expressions=(
1901                self._parse_wrapped_csv(self._parse_ordered)
1902                if wrapped
1903                else self._parse_csv(self._parse_ordered)
1904            ),
1905        )
1906
1907    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1908        self._match_text_seq("BY")
1909
1910        self._match_l_paren()
1911        expressions = self._parse_csv(self._parse_column)
1912        self._match_r_paren()
1913
1914        if self._match_text_seq("SORTED", "BY"):
1915            self._match_l_paren()
1916            sorted_by = self._parse_csv(self._parse_ordered)
1917            self._match_r_paren()
1918        else:
1919            sorted_by = None
1920
1921        self._match(TokenType.INTO)
1922        buckets = self._parse_number()
1923        self._match_text_seq("BUCKETS")
1924
1925        return self.expression(
1926            exp.ClusteredByProperty,
1927            expressions=expressions,
1928            sorted_by=sorted_by,
1929            buckets=buckets,
1930        )
1931
1932    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1933        if not self._match_text_seq("GRANTS"):
1934            self._retreat(self._index - 1)
1935            return None
1936
1937        return self.expression(exp.CopyGrantsProperty)
1938
1939    def _parse_freespace(self) -> exp.FreespaceProperty:
1940        self._match(TokenType.EQ)
1941        return self.expression(
1942            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1943        )
1944
1945    def _parse_mergeblockratio(
1946        self, no: bool = False, default: bool = False
1947    ) -> exp.MergeBlockRatioProperty:
1948        if self._match(TokenType.EQ):
1949            return self.expression(
1950                exp.MergeBlockRatioProperty,
1951                this=self._parse_number(),
1952                percent=self._match(TokenType.PERCENT),
1953            )
1954
1955        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1956
1957    def _parse_datablocksize(
1958        self,
1959        default: t.Optional[bool] = None,
1960        minimum: t.Optional[bool] = None,
1961        maximum: t.Optional[bool] = None,
1962    ) -> exp.DataBlocksizeProperty:
1963        self._match(TokenType.EQ)
1964        size = self._parse_number()
1965
1966        units = None
1967        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1968            units = self._prev.text
1969
1970        return self.expression(
1971            exp.DataBlocksizeProperty,
1972            size=size,
1973            units=units,
1974            default=default,
1975            minimum=minimum,
1976            maximum=maximum,
1977        )
1978
1979    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1980        self._match(TokenType.EQ)
1981        always = self._match_text_seq("ALWAYS")
1982        manual = self._match_text_seq("MANUAL")
1983        never = self._match_text_seq("NEVER")
1984        default = self._match_text_seq("DEFAULT")
1985
1986        autotemp = None
1987        if self._match_text_seq("AUTOTEMP"):
1988            autotemp = self._parse_schema()
1989
1990        return self.expression(
1991            exp.BlockCompressionProperty,
1992            always=always,
1993            manual=manual,
1994            never=never,
1995            default=default,
1996            autotemp=autotemp,
1997        )
1998
1999    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2000        index = self._index
2001        no = self._match_text_seq("NO")
2002        concurrent = self._match_text_seq("CONCURRENT")
2003
2004        if not self._match_text_seq("ISOLATED", "LOADING"):
2005            self._retreat(index)
2006            return None
2007
2008        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2009        return self.expression(
2010            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2011        )
2012
2013    def _parse_locking(self) -> exp.LockingProperty:
2014        if self._match(TokenType.TABLE):
2015            kind = "TABLE"
2016        elif self._match(TokenType.VIEW):
2017            kind = "VIEW"
2018        elif self._match(TokenType.ROW):
2019            kind = "ROW"
2020        elif self._match_text_seq("DATABASE"):
2021            kind = "DATABASE"
2022        else:
2023            kind = None
2024
2025        if kind in ("DATABASE", "TABLE", "VIEW"):
2026            this = self._parse_table_parts()
2027        else:
2028            this = None
2029
2030        if self._match(TokenType.FOR):
2031            for_or_in = "FOR"
2032        elif self._match(TokenType.IN):
2033            for_or_in = "IN"
2034        else:
2035            for_or_in = None
2036
2037        if self._match_text_seq("ACCESS"):
2038            lock_type = "ACCESS"
2039        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2040            lock_type = "EXCLUSIVE"
2041        elif self._match_text_seq("SHARE"):
2042            lock_type = "SHARE"
2043        elif self._match_text_seq("READ"):
2044            lock_type = "READ"
2045        elif self._match_text_seq("WRITE"):
2046            lock_type = "WRITE"
2047        elif self._match_text_seq("CHECKSUM"):
2048            lock_type = "CHECKSUM"
2049        else:
2050            lock_type = None
2051
2052        override = self._match_text_seq("OVERRIDE")
2053
2054        return self.expression(
2055            exp.LockingProperty,
2056            this=this,
2057            kind=kind,
2058            for_or_in=for_or_in,
2059            lock_type=lock_type,
2060            override=override,
2061        )
2062
2063    def _parse_partition_by(self) -> t.List[exp.Expression]:
2064        if self._match(TokenType.PARTITION_BY):
2065            return self._parse_csv(self._parse_conjunction)
2066        return []
2067
2068    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2069        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2070            if self._match_text_seq("MINVALUE"):
2071                return exp.var("MINVALUE")
2072            if self._match_text_seq("MAXVALUE"):
2073                return exp.var("MAXVALUE")
2074            return self._parse_bitwise()
2075
2076        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2077        expression = None
2078        from_expressions = None
2079        to_expressions = None
2080
2081        if self._match(TokenType.IN):
2082            this = self._parse_wrapped_csv(self._parse_bitwise)
2083        elif self._match(TokenType.FROM):
2084            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2085            self._match_text_seq("TO")
2086            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2087        elif self._match_text_seq("WITH", "(", "MODULUS"):
2088            this = self._parse_number()
2089            self._match_text_seq(",", "REMAINDER")
2090            expression = self._parse_number()
2091            self._match_r_paren()
2092        else:
2093            self.raise_error("Failed to parse partition bound spec.")
2094
2095        return self.expression(
2096            exp.PartitionBoundSpec,
2097            this=this,
2098            expression=expression,
2099            from_expressions=from_expressions,
2100            to_expressions=to_expressions,
2101        )
2102
2103    # https://www.postgresql.org/docs/current/sql-createtable.html
2104    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2105        if not self._match_text_seq("OF"):
2106            self._retreat(self._index - 1)
2107            return None
2108
2109        this = self._parse_table(schema=True)
2110
2111        if self._match(TokenType.DEFAULT):
2112            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2113        elif self._match_text_seq("FOR", "VALUES"):
2114            expression = self._parse_partition_bound_spec()
2115        else:
2116            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2117
2118        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2119
2120    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2121        self._match(TokenType.EQ)
2122        return self.expression(
2123            exp.PartitionedByProperty,
2124            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2125        )
2126
2127    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2128        if self._match_text_seq("AND", "STATISTICS"):
2129            statistics = True
2130        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2131            statistics = False
2132        else:
2133            statistics = None
2134
2135        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2136
2137    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2138        if self._match_text_seq("SQL"):
2139            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2140        return None
2141
2142    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2143        if self._match_text_seq("SQL", "DATA"):
2144            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2145        return None
2146
2147    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2148        if self._match_text_seq("PRIMARY", "INDEX"):
2149            return exp.NoPrimaryIndexProperty()
2150        if self._match_text_seq("SQL"):
2151            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2152        return None
2153
2154    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2155        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2156            return exp.OnCommitProperty()
2157        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2158            return exp.OnCommitProperty(delete=True)
2159        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2160
2161    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2162        if self._match_text_seq("SQL", "DATA"):
2163            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2164        return None
2165
2166    def _parse_distkey(self) -> exp.DistKeyProperty:
2167        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2168
2169    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2170        table = self._parse_table(schema=True)
2171
2172        options = []
2173        while self._match_texts(("INCLUDING", "EXCLUDING")):
2174            this = self._prev.text.upper()
2175
2176            id_var = self._parse_id_var()
2177            if not id_var:
2178                return None
2179
2180            options.append(
2181                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2182            )
2183
2184        return self.expression(exp.LikeProperty, this=table, expressions=options)
2185
2186    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2187        return self.expression(
2188            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2189        )
2190
2191    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2192        self._match(TokenType.EQ)
2193        return self.expression(
2194            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2195        )
2196
2197    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2198        self._match_text_seq("WITH", "CONNECTION")
2199        return self.expression(
2200            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2201        )
2202
2203    def _parse_returns(self) -> exp.ReturnsProperty:
2204        value: t.Optional[exp.Expression]
2205        is_table = self._match(TokenType.TABLE)
2206
2207        if is_table:
2208            if self._match(TokenType.LT):
2209                value = self.expression(
2210                    exp.Schema,
2211                    this="TABLE",
2212                    expressions=self._parse_csv(self._parse_struct_types),
2213                )
2214                if not self._match(TokenType.GT):
2215                    self.raise_error("Expecting >")
2216            else:
2217                value = self._parse_schema(exp.var("TABLE"))
2218        else:
2219            value = self._parse_types()
2220
2221        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
2222
2223    def _parse_describe(self) -> exp.Describe:
2224        kind = self._match_set(self.CREATABLES) and self._prev.text
2225        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2226        if self._match(TokenType.DOT):
2227            style = None
2228            self._retreat(self._index - 2)
2229        this = self._parse_table(schema=True)
2230        properties = self._parse_properties()
2231        expressions = properties.expressions if properties else None
2232        return self.expression(
2233            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2234        )
2235
2236    def _parse_insert(self) -> exp.Insert:
2237        comments = ensure_list(self._prev_comments)
2238        hint = self._parse_hint()
2239        overwrite = self._match(TokenType.OVERWRITE)
2240        ignore = self._match(TokenType.IGNORE)
2241        local = self._match_text_seq("LOCAL")
2242        alternative = None
2243        is_function = None
2244
2245        if self._match_text_seq("DIRECTORY"):
2246            this: t.Optional[exp.Expression] = self.expression(
2247                exp.Directory,
2248                this=self._parse_var_or_string(),
2249                local=local,
2250                row_format=self._parse_row_format(match_row=True),
2251            )
2252        else:
2253            if self._match(TokenType.OR):
2254                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2255
2256            self._match(TokenType.INTO)
2257            comments += ensure_list(self._prev_comments)
2258            self._match(TokenType.TABLE)
2259            is_function = self._match(TokenType.FUNCTION)
2260
2261            this = (
2262                self._parse_table(schema=True, parse_partition=True)
2263                if not is_function
2264                else self._parse_function()
2265            )
2266
2267        returning = self._parse_returning()
2268
2269        return self.expression(
2270            exp.Insert,
2271            comments=comments,
2272            hint=hint,
2273            is_function=is_function,
2274            this=this,
2275            stored=self._match_text_seq("STORED") and self._parse_stored(),
2276            by_name=self._match_text_seq("BY", "NAME"),
2277            exists=self._parse_exists(),
2278            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
2279            and self._parse_conjunction(),
2280            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2281            conflict=self._parse_on_conflict(),
2282            returning=returning or self._parse_returning(),
2283            overwrite=overwrite,
2284            alternative=alternative,
2285            ignore=ignore,
2286        )
2287
2288    def _parse_kill(self) -> exp.Kill:
2289        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2290
2291        return self.expression(
2292            exp.Kill,
2293            this=self._parse_primary(),
2294            kind=kind,
2295        )
2296
2297    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2298        conflict = self._match_text_seq("ON", "CONFLICT")
2299        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2300
2301        if not conflict and not duplicate:
2302            return None
2303
2304        conflict_keys = None
2305        constraint = None
2306
2307        if conflict:
2308            if self._match_text_seq("ON", "CONSTRAINT"):
2309                constraint = self._parse_id_var()
2310            elif self._match(TokenType.L_PAREN):
2311                conflict_keys = self._parse_csv(self._parse_id_var)
2312                self._match_r_paren()
2313
2314        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2315        if self._prev.token_type == TokenType.UPDATE:
2316            self._match(TokenType.SET)
2317            expressions = self._parse_csv(self._parse_equality)
2318        else:
2319            expressions = None
2320
2321        return self.expression(
2322            exp.OnConflict,
2323            duplicate=duplicate,
2324            expressions=expressions,
2325            action=action,
2326            conflict_keys=conflict_keys,
2327            constraint=constraint,
2328        )
2329
2330    def _parse_returning(self) -> t.Optional[exp.Returning]:
2331        if not self._match(TokenType.RETURNING):
2332            return None
2333        return self.expression(
2334            exp.Returning,
2335            expressions=self._parse_csv(self._parse_expression),
2336            into=self._match(TokenType.INTO) and self._parse_table_part(),
2337        )
2338
2339    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2340        if not self._match(TokenType.FORMAT):
2341            return None
2342        return self._parse_row_format()
2343
2344    def _parse_row_format(
2345        self, match_row: bool = False
2346    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2347        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2348            return None
2349
2350        if self._match_text_seq("SERDE"):
2351            this = self._parse_string()
2352
2353            serde_properties = None
2354            if self._match(TokenType.SERDE_PROPERTIES):
2355                serde_properties = self.expression(
2356                    exp.SerdeProperties, expressions=self._parse_wrapped_properties()
2357                )
2358
2359            return self.expression(
2360                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2361            )
2362
2363        self._match_text_seq("DELIMITED")
2364
2365        kwargs = {}
2366
2367        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2368            kwargs["fields"] = self._parse_string()
2369            if self._match_text_seq("ESCAPED", "BY"):
2370                kwargs["escaped"] = self._parse_string()
2371        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2372            kwargs["collection_items"] = self._parse_string()
2373        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2374            kwargs["map_keys"] = self._parse_string()
2375        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2376            kwargs["lines"] = self._parse_string()
2377        if self._match_text_seq("NULL", "DEFINED", "AS"):
2378            kwargs["null"] = self._parse_string()
2379
2380        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2381
2382    def _parse_load(self) -> exp.LoadData | exp.Command:
2383        if self._match_text_seq("DATA"):
2384            local = self._match_text_seq("LOCAL")
2385            self._match_text_seq("INPATH")
2386            inpath = self._parse_string()
2387            overwrite = self._match(TokenType.OVERWRITE)
2388            self._match_pair(TokenType.INTO, TokenType.TABLE)
2389
2390            return self.expression(
2391                exp.LoadData,
2392                this=self._parse_table(schema=True),
2393                local=local,
2394                overwrite=overwrite,
2395                inpath=inpath,
2396                partition=self._parse_partition(),
2397                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2398                serde=self._match_text_seq("SERDE") and self._parse_string(),
2399            )
2400        return self._parse_as_command(self._prev)
2401
2402    def _parse_delete(self) -> exp.Delete:
2403        # This handles MySQL's "Multiple-Table Syntax"
2404        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2405        tables = None
2406        comments = self._prev_comments
2407        if not self._match(TokenType.FROM, advance=False):
2408            tables = self._parse_csv(self._parse_table) or None
2409
2410        returning = self._parse_returning()
2411
2412        return self.expression(
2413            exp.Delete,
2414            comments=comments,
2415            tables=tables,
2416            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2417            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2418            where=self._parse_where(),
2419            returning=returning or self._parse_returning(),
2420            limit=self._parse_limit(),
2421        )
2422
2423    def _parse_update(self) -> exp.Update:
2424        comments = self._prev_comments
2425        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2426        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2427        returning = self._parse_returning()
2428        return self.expression(
2429            exp.Update,
2430            comments=comments,
2431            **{  # type: ignore
2432                "this": this,
2433                "expressions": expressions,
2434                "from": self._parse_from(joins=True),
2435                "where": self._parse_where(),
2436                "returning": returning or self._parse_returning(),
2437                "order": self._parse_order(),
2438                "limit": self._parse_limit(),
2439            },
2440        )
2441
2442    def _parse_uncache(self) -> exp.Uncache:
2443        if not self._match(TokenType.TABLE):
2444            self.raise_error("Expecting TABLE after UNCACHE")
2445
2446        return self.expression(
2447            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2448        )
2449
2450    def _parse_cache(self) -> exp.Cache:
2451        lazy = self._match_text_seq("LAZY")
2452        self._match(TokenType.TABLE)
2453        table = self._parse_table(schema=True)
2454
2455        options = []
2456        if self._match_text_seq("OPTIONS"):
2457            self._match_l_paren()
2458            k = self._parse_string()
2459            self._match(TokenType.EQ)
2460            v = self._parse_string()
2461            options = [k, v]
2462            self._match_r_paren()
2463
2464        self._match(TokenType.ALIAS)
2465        return self.expression(
2466            exp.Cache,
2467            this=table,
2468            lazy=lazy,
2469            options=options,
2470            expression=self._parse_select(nested=True),
2471        )
2472
2473    def _parse_partition(self) -> t.Optional[exp.Partition]:
2474        if not self._match(TokenType.PARTITION):
2475            return None
2476
2477        return self.expression(
2478            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2479        )
2480
2481    def _parse_value(self) -> t.Optional[exp.Tuple]:
2482        if self._match(TokenType.L_PAREN):
2483            expressions = self._parse_csv(self._parse_expression)
2484            self._match_r_paren()
2485            return self.expression(exp.Tuple, expressions=expressions)
2486
2487        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2488        expression = self._parse_expression()
2489        if expression:
2490            return self.expression(exp.Tuple, expressions=[expression])
2491        return None
2492
2493    def _parse_projections(self) -> t.List[exp.Expression]:
2494        return self._parse_expressions()
2495
2496    def _parse_select(
2497        self,
2498        nested: bool = False,
2499        table: bool = False,
2500        parse_subquery_alias: bool = True,
2501        parse_set_operation: bool = True,
2502    ) -> t.Optional[exp.Expression]:
2503        cte = self._parse_with()
2504
2505        if cte:
2506            this = self._parse_statement()
2507
2508            if not this:
2509                self.raise_error("Failed to parse any statement following CTE")
2510                return cte
2511
2512            if "with" in this.arg_types:
2513                this.set("with", cte)
2514            else:
2515                self.raise_error(f"{this.key} does not support CTE")
2516                this = cte
2517
2518            return this
2519
2520        # duckdb supports leading with FROM x
2521        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2522
2523        if self._match(TokenType.SELECT):
2524            comments = self._prev_comments
2525
2526            hint = self._parse_hint()
2527            all_ = self._match(TokenType.ALL)
2528            distinct = self._match_set(self.DISTINCT_TOKENS)
2529
2530            kind = (
2531                self._match(TokenType.ALIAS)
2532                and self._match_texts(("STRUCT", "VALUE"))
2533                and self._prev.text.upper()
2534            )
2535
2536            if distinct:
2537                distinct = self.expression(
2538                    exp.Distinct,
2539                    on=self._parse_value() if self._match(TokenType.ON) else None,
2540                )
2541
2542            if all_ and distinct:
2543                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2544
2545            limit = self._parse_limit(top=True)
2546            projections = self._parse_projections()
2547
2548            this = self.expression(
2549                exp.Select,
2550                kind=kind,
2551                hint=hint,
2552                distinct=distinct,
2553                expressions=projections,
2554                limit=limit,
2555            )
2556            this.comments = comments
2557
2558            into = self._parse_into()
2559            if into:
2560                this.set("into", into)
2561
2562            if not from_:
2563                from_ = self._parse_from()
2564
2565            if from_:
2566                this.set("from", from_)
2567
2568            this = self._parse_query_modifiers(this)
2569        elif (table or nested) and self._match(TokenType.L_PAREN):
2570            if self._match(TokenType.PIVOT):
2571                this = self._parse_simplified_pivot()
2572            elif self._match(TokenType.FROM):
2573                this = exp.select("*").from_(
2574                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2575                )
2576            else:
2577                this = (
2578                    self._parse_table()
2579                    if table
2580                    else self._parse_select(nested=True, parse_set_operation=False)
2581                )
2582                this = self._parse_query_modifiers(self._parse_set_operations(this))
2583
2584            self._match_r_paren()
2585
2586            # We return early here so that the UNION isn't attached to the subquery by the
2587            # following call to _parse_set_operations, but instead becomes the parent node
2588            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2589        elif self._match(TokenType.VALUES, advance=False):
2590            this = self._parse_derived_table_values()
2591        elif from_:
2592            this = exp.select("*").from_(from_.this, copy=False)
2593        else:
2594            this = None
2595
2596        if parse_set_operation:
2597            return self._parse_set_operations(this)
2598        return this
2599
2600    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2601        if not skip_with_token and not self._match(TokenType.WITH):
2602            return None
2603
2604        comments = self._prev_comments
2605        recursive = self._match(TokenType.RECURSIVE)
2606
2607        expressions = []
2608        while True:
2609            expressions.append(self._parse_cte())
2610
2611            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2612                break
2613            else:
2614                self._match(TokenType.WITH)
2615
2616        return self.expression(
2617            exp.With, comments=comments, expressions=expressions, recursive=recursive
2618        )
2619
2620    def _parse_cte(self) -> exp.CTE:
2621        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2622        if not alias or not alias.this:
2623            self.raise_error("Expected CTE to have alias")
2624
2625        self._match(TokenType.ALIAS)
2626
2627        if self._match_text_seq("NOT", "MATERIALIZED"):
2628            materialized = False
2629        elif self._match_text_seq("MATERIALIZED"):
2630            materialized = True
2631        else:
2632            materialized = None
2633
2634        return self.expression(
2635            exp.CTE,
2636            this=self._parse_wrapped(self._parse_statement),
2637            alias=alias,
2638            materialized=materialized,
2639        )
2640
2641    def _parse_table_alias(
2642        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2643    ) -> t.Optional[exp.TableAlias]:
2644        any_token = self._match(TokenType.ALIAS)
2645        alias = (
2646            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2647            or self._parse_string_as_identifier()
2648        )
2649
2650        index = self._index
2651        if self._match(TokenType.L_PAREN):
2652            columns = self._parse_csv(self._parse_function_parameter)
2653            self._match_r_paren() if columns else self._retreat(index)
2654        else:
2655            columns = None
2656
2657        if not alias and not columns:
2658            return None
2659
2660        return self.expression(exp.TableAlias, this=alias, columns=columns)
2661
2662    def _parse_subquery(
2663        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2664    ) -> t.Optional[exp.Subquery]:
2665        if not this:
2666            return None
2667
2668        return self.expression(
2669            exp.Subquery,
2670            this=this,
2671            pivots=self._parse_pivots(),
2672            alias=self._parse_table_alias() if parse_alias else None,
2673        )
2674
2675    def _implicit_unnests_to_explicit(self, this: E) -> E:
2676        from sqlglot.optimizer.normalize_identifiers import (
2677            normalize_identifiers as _norm,
2678        )
2679
2680        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2681        for i, join in enumerate(this.args.get("joins") or []):
2682            table = join.this
2683            normalized_table = table.copy()
2684            normalized_table.meta["maybe_column"] = True
2685            normalized_table = _norm(normalized_table, dialect=self.dialect)
2686
2687            if isinstance(table, exp.Table) and not join.args.get("on"):
2688                if normalized_table.parts[0].name in refs:
2689                    table_as_column = table.to_column()
2690                    unnest = exp.Unnest(expressions=[table_as_column])
2691
2692                    # Table.to_column creates a parent Alias node that we want to convert to
2693                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2694                    if isinstance(table.args.get("alias"), exp.TableAlias):
2695                        table_as_column.replace(table_as_column.this)
2696                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2697
2698                    table.replace(unnest)
2699
2700            refs.add(normalized_table.alias_or_name)
2701
2702        return this
2703
2704    def _parse_query_modifiers(
2705        self, this: t.Optional[exp.Expression]
2706    ) -> t.Optional[exp.Expression]:
2707        if isinstance(this, (exp.Query, exp.Table)):
2708            for join in self._parse_joins():
2709                this.append("joins", join)
2710            for lateral in iter(self._parse_lateral, None):
2711                this.append("laterals", lateral)
2712
2713            while True:
2714                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2715                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2716                    key, expression = parser(self)
2717
2718                    if expression:
2719                        this.set(key, expression)
2720                        if key == "limit":
2721                            offset = expression.args.pop("offset", None)
2722
2723                            if offset:
2724                                offset = exp.Offset(expression=offset)
2725                                this.set("offset", offset)
2726
2727                                limit_by_expressions = expression.expressions
2728                                expression.set("expressions", None)
2729                                offset.set("expressions", limit_by_expressions)
2730                        continue
2731                break
2732
2733        if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
2734            this = self._implicit_unnests_to_explicit(this)
2735
2736        return this
2737
2738    def _parse_hint(self) -> t.Optional[exp.Hint]:
2739        if self._match(TokenType.HINT):
2740            hints = []
2741            for hint in iter(
2742                lambda: self._parse_csv(
2743                    lambda: self._parse_function() or self._parse_var(upper=True)
2744                ),
2745                [],
2746            ):
2747                hints.extend(hint)
2748
2749            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2750                self.raise_error("Expected */ after HINT")
2751
2752            return self.expression(exp.Hint, expressions=hints)
2753
2754        return None
2755
2756    def _parse_into(self) -> t.Optional[exp.Into]:
2757        if not self._match(TokenType.INTO):
2758            return None
2759
2760        temp = self._match(TokenType.TEMPORARY)
2761        unlogged = self._match_text_seq("UNLOGGED")
2762        self._match(TokenType.TABLE)
2763
2764        return self.expression(
2765            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2766        )
2767
2768    def _parse_from(
2769        self, joins: bool = False, skip_from_token: bool = False
2770    ) -> t.Optional[exp.From]:
2771        if not skip_from_token and not self._match(TokenType.FROM):
2772            return None
2773
2774        return self.expression(
2775            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2776        )
2777
2778    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
2779        return self.expression(
2780            exp.MatchRecognizeMeasure,
2781            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
2782            this=self._parse_expression(),
2783        )
2784
2785    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2786        if not self._match(TokenType.MATCH_RECOGNIZE):
2787            return None
2788
2789        self._match_l_paren()
2790
2791        partition = self._parse_partition_by()
2792        order = self._parse_order()
2793
2794        measures = (
2795            self._parse_csv(self._parse_match_recognize_measure)
2796            if self._match_text_seq("MEASURES")
2797            else None
2798        )
2799
2800        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2801            rows = exp.var("ONE ROW PER MATCH")
2802        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2803            text = "ALL ROWS PER MATCH"
2804            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2805                text += " SHOW EMPTY MATCHES"
2806            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2807                text += " OMIT EMPTY MATCHES"
2808            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2809                text += " WITH UNMATCHED ROWS"
2810            rows = exp.var(text)
2811        else:
2812            rows = None
2813
2814        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2815            text = "AFTER MATCH SKIP"
2816            if self._match_text_seq("PAST", "LAST", "ROW"):
2817                text += " PAST LAST ROW"
2818            elif self._match_text_seq("TO", "NEXT", "ROW"):
2819                text += " TO NEXT ROW"
2820            elif self._match_text_seq("TO", "FIRST"):
2821                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2822            elif self._match_text_seq("TO", "LAST"):
2823                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2824            after = exp.var(text)
2825        else:
2826            after = None
2827
2828        if self._match_text_seq("PATTERN"):
2829            self._match_l_paren()
2830
2831            if not self._curr:
2832                self.raise_error("Expecting )", self._curr)
2833
2834            paren = 1
2835            start = self._curr
2836
2837            while self._curr and paren > 0:
2838                if self._curr.token_type == TokenType.L_PAREN:
2839                    paren += 1
2840                if self._curr.token_type == TokenType.R_PAREN:
2841                    paren -= 1
2842
2843                end = self._prev
2844                self._advance()
2845
2846            if paren > 0:
2847                self.raise_error("Expecting )", self._curr)
2848
2849            pattern = exp.var(self._find_sql(start, end))
2850        else:
2851            pattern = None
2852
2853        define = (
2854            self._parse_csv(self._parse_name_as_expression)
2855            if self._match_text_seq("DEFINE")
2856            else None
2857        )
2858
2859        self._match_r_paren()
2860
2861        return self.expression(
2862            exp.MatchRecognize,
2863            partition_by=partition,
2864            order=order,
2865            measures=measures,
2866            rows=rows,
2867            after=after,
2868            pattern=pattern,
2869            define=define,
2870            alias=self._parse_table_alias(),
2871        )
2872
2873    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2874        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2875        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2876            cross_apply = False
2877
2878        if cross_apply is not None:
2879            this = self._parse_select(table=True)
2880            view = None
2881            outer = None
2882        elif self._match(TokenType.LATERAL):
2883            this = self._parse_select(table=True)
2884            view = self._match(TokenType.VIEW)
2885            outer = self._match(TokenType.OUTER)
2886        else:
2887            return None
2888
2889        if not this:
2890            this = (
2891                self._parse_unnest()
2892                or self._parse_function()
2893                or self._parse_id_var(any_token=False)
2894            )
2895
2896            while self._match(TokenType.DOT):
2897                this = exp.Dot(
2898                    this=this,
2899                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2900                )
2901
2902        if view:
2903            table = self._parse_id_var(any_token=False)
2904            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2905            table_alias: t.Optional[exp.TableAlias] = self.expression(
2906                exp.TableAlias, this=table, columns=columns
2907            )
2908        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2909            # We move the alias from the lateral's child node to the lateral itself
2910            table_alias = this.args["alias"].pop()
2911        else:
2912            table_alias = self._parse_table_alias()
2913
2914        return self.expression(
2915            exp.Lateral,
2916            this=this,
2917            view=view,
2918            outer=outer,
2919            alias=table_alias,
2920            cross_apply=cross_apply,
2921        )
2922
2923    def _parse_join_parts(
2924        self,
2925    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2926        return (
2927            self._match_set(self.JOIN_METHODS) and self._prev,
2928            self._match_set(self.JOIN_SIDES) and self._prev,
2929            self._match_set(self.JOIN_KINDS) and self._prev,
2930        )
2931
2932    def _parse_join(
2933        self, skip_join_token: bool = False, parse_bracket: bool = False
2934    ) -> t.Optional[exp.Join]:
2935        if self._match(TokenType.COMMA):
2936            return self.expression(exp.Join, this=self._parse_table())
2937
2938        index = self._index
2939        method, side, kind = self._parse_join_parts()
2940        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2941        join = self._match(TokenType.JOIN)
2942
2943        if not skip_join_token and not join:
2944            self._retreat(index)
2945            kind = None
2946            method = None
2947            side = None
2948
2949        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2950        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2951
2952        if not skip_join_token and not join and not outer_apply and not cross_apply:
2953            return None
2954
2955        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2956
2957        if method:
2958            kwargs["method"] = method.text
2959        if side:
2960            kwargs["side"] = side.text
2961        if kind:
2962            kwargs["kind"] = kind.text
2963        if hint:
2964            kwargs["hint"] = hint
2965
2966        if self._match(TokenType.MATCH_CONDITION):
2967            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
2968
2969        if self._match(TokenType.ON):
2970            kwargs["on"] = self._parse_conjunction()
2971        elif self._match(TokenType.USING):
2972            kwargs["using"] = self._parse_wrapped_id_vars()
2973        elif not isinstance(kwargs["this"], exp.Unnest) and not (
2974            kind and kind.token_type == TokenType.CROSS
2975        ):
2976            index = self._index
2977            joins: t.Optional[list] = list(self._parse_joins())
2978
2979            if joins and self._match(TokenType.ON):
2980                kwargs["on"] = self._parse_conjunction()
2981            elif joins and self._match(TokenType.USING):
2982                kwargs["using"] = self._parse_wrapped_id_vars()
2983            else:
2984                joins = None
2985                self._retreat(index)
2986
2987            kwargs["this"].set("joins", joins if joins else None)
2988
2989        comments = [c for token in (method, side, kind) if token for c in token.comments]
2990        return self.expression(exp.Join, comments=comments, **kwargs)
2991
2992    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2993        this = self._parse_conjunction()
2994
2995        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2996            return this
2997
2998        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2999            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3000
3001        return this
3002
3003    def _parse_index_params(self) -> exp.IndexParameters:
3004        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3005
3006        if self._match(TokenType.L_PAREN, advance=False):
3007            columns = self._parse_wrapped_csv(self._parse_with_operator)
3008        else:
3009            columns = None
3010
3011        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3012        partition_by = self._parse_partition_by()
3013        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3014        tablespace = (
3015            self._parse_var(any_token=True)
3016            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3017            else None
3018        )
3019        where = self._parse_where()
3020
3021        return self.expression(
3022            exp.IndexParameters,
3023            using=using,
3024            columns=columns,
3025            include=include,
3026            partition_by=partition_by,
3027            where=where,
3028            with_storage=with_storage,
3029            tablespace=tablespace,
3030        )
3031
3032    def _parse_index(
3033        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3034    ) -> t.Optional[exp.Index]:
3035        if index or anonymous:
3036            unique = None
3037            primary = None
3038            amp = None
3039
3040            self._match(TokenType.ON)
3041            self._match(TokenType.TABLE)  # hive
3042            table = self._parse_table_parts(schema=True)
3043        else:
3044            unique = self._match(TokenType.UNIQUE)
3045            primary = self._match_text_seq("PRIMARY")
3046            amp = self._match_text_seq("AMP")
3047
3048            if not self._match(TokenType.INDEX):
3049                return None
3050
3051            index = self._parse_id_var()
3052            table = None
3053
3054        params = self._parse_index_params()
3055
3056        return self.expression(
3057            exp.Index,
3058            this=index,
3059            table=table,
3060            unique=unique,
3061            primary=primary,
3062            amp=amp,
3063            params=params,
3064        )
3065
3066    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3067        hints: t.List[exp.Expression] = []
3068        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3069            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3070            hints.append(
3071                self.expression(
3072                    exp.WithTableHint,
3073                    expressions=self._parse_csv(
3074                        lambda: self._parse_function() or self._parse_var(any_token=True)
3075                    ),
3076                )
3077            )
3078            self._match_r_paren()
3079        else:
3080            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3081            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3082                hint = exp.IndexTableHint(this=self._prev.text.upper())
3083
3084                self._match_texts(("INDEX", "KEY"))
3085                if self._match(TokenType.FOR):
3086                    hint.set("target", self._advance_any() and self._prev.text.upper())
3087
3088                hint.set("expressions", self._parse_wrapped_id_vars())
3089                hints.append(hint)
3090
3091        return hints or None
3092
3093    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3094        return (
3095            (not schema and self._parse_function(optional_parens=False))
3096            or self._parse_id_var(any_token=False)
3097            or self._parse_string_as_identifier()
3098            or self._parse_placeholder()
3099        )
3100
3101    def _parse_table_parts(
3102        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3103    ) -> exp.Table:
3104        catalog = None
3105        db = None
3106        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3107
3108        while self._match(TokenType.DOT):
3109            if catalog:
3110                # This allows nesting the table in arbitrarily many dot expressions if needed
3111                table = self.expression(
3112                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3113                )
3114            else:
3115                catalog = db
3116                db = table
3117                # "" used for tsql FROM a..b case
3118                table = self._parse_table_part(schema=schema) or ""
3119
3120        if (
3121            wildcard
3122            and self._is_connected()
3123            and (isinstance(table, exp.Identifier) or not table)
3124            and self._match(TokenType.STAR)
3125        ):
3126            if isinstance(table, exp.Identifier):
3127                table.args["this"] += "*"
3128            else:
3129                table = exp.Identifier(this="*")
3130
3131        # We bubble up comments from the Identifier to the Table
3132        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3133
3134        if is_db_reference:
3135            catalog = db
3136            db = table
3137            table = None
3138
3139        if not table and not is_db_reference:
3140            self.raise_error(f"Expected table name but got {self._curr}")
3141        if not db and is_db_reference:
3142            self.raise_error(f"Expected database name but got {self._curr}")
3143
3144        return self.expression(
3145            exp.Table,
3146            comments=comments,
3147            this=table,
3148            db=db,
3149            catalog=catalog,
3150            pivots=self._parse_pivots(),
3151        )
3152
3153    def _parse_table(
3154        self,
3155        schema: bool = False,
3156        joins: bool = False,
3157        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3158        parse_bracket: bool = False,
3159        is_db_reference: bool = False,
3160        parse_partition: bool = False,
3161    ) -> t.Optional[exp.Expression]:
3162        lateral = self._parse_lateral()
3163        if lateral:
3164            return lateral
3165
3166        unnest = self._parse_unnest()
3167        if unnest:
3168            return unnest
3169
3170        values = self._parse_derived_table_values()
3171        if values:
3172            return values
3173
3174        subquery = self._parse_select(table=True)
3175        if subquery:
3176            if not subquery.args.get("pivots"):
3177                subquery.set("pivots", self._parse_pivots())
3178            return subquery
3179
3180        bracket = parse_bracket and self._parse_bracket(None)
3181        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3182
3183        only = self._match(TokenType.ONLY)
3184
3185        this = t.cast(
3186            exp.Expression,
3187            bracket
3188            or self._parse_bracket(
3189                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3190            ),
3191        )
3192
3193        if only:
3194            this.set("only", only)
3195
3196        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3197        self._match_text_seq("*")
3198
3199        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3200        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3201            this.set("partition", self._parse_partition())
3202
3203        if schema:
3204            return self._parse_schema(this=this)
3205
3206        version = self._parse_version()
3207
3208        if version:
3209            this.set("version", version)
3210
3211        if self.dialect.ALIAS_POST_TABLESAMPLE:
3212            table_sample = self._parse_table_sample()
3213
3214        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3215        if alias:
3216            this.set("alias", alias)
3217
3218        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3219            return self.expression(
3220                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3221            )
3222
3223        this.set("hints", self._parse_table_hints())
3224
3225        if not this.args.get("pivots"):
3226            this.set("pivots", self._parse_pivots())
3227
3228        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3229            table_sample = self._parse_table_sample()
3230
3231        if table_sample:
3232            table_sample.set("this", this)
3233            this = table_sample
3234
3235        if joins:
3236            for join in self._parse_joins():
3237                this.append("joins", join)
3238
3239        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3240            this.set("ordinality", True)
3241            this.set("alias", self._parse_table_alias())
3242
3243        return this
3244
3245    def _parse_version(self) -> t.Optional[exp.Version]:
3246        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3247            this = "TIMESTAMP"
3248        elif self._match(TokenType.VERSION_SNAPSHOT):
3249            this = "VERSION"
3250        else:
3251            return None
3252
3253        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3254            kind = self._prev.text.upper()
3255            start = self._parse_bitwise()
3256            self._match_texts(("TO", "AND"))
3257            end = self._parse_bitwise()
3258            expression: t.Optional[exp.Expression] = self.expression(
3259                exp.Tuple, expressions=[start, end]
3260            )
3261        elif self._match_text_seq("CONTAINED", "IN"):
3262            kind = "CONTAINED IN"
3263            expression = self.expression(
3264                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3265            )
3266        elif self._match(TokenType.ALL):
3267            kind = "ALL"
3268            expression = None
3269        else:
3270            self._match_text_seq("AS", "OF")
3271            kind = "AS OF"
3272            expression = self._parse_type()
3273
3274        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3275
3276    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3277        if not self._match(TokenType.UNNEST):
3278            return None
3279
3280        expressions = self._parse_wrapped_csv(self._parse_equality)
3281        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3282
3283        alias = self._parse_table_alias() if with_alias else None
3284
3285        if alias:
3286            if self.dialect.UNNEST_COLUMN_ONLY:
3287                if alias.args.get("columns"):
3288                    self.raise_error("Unexpected extra column alias in unnest.")
3289
3290                alias.set("columns", [alias.this])
3291                alias.set("this", None)
3292
3293            columns = alias.args.get("columns") or []
3294            if offset and len(expressions) < len(columns):
3295                offset = columns.pop()
3296
3297        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3298            self._match(TokenType.ALIAS)
3299            offset = self._parse_id_var(
3300                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3301            ) or exp.to_identifier("offset")
3302
3303        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3304
3305    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3306        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3307        if not is_derived and not self._match_text_seq("VALUES"):
3308            return None
3309
3310        expressions = self._parse_csv(self._parse_value)
3311        alias = self._parse_table_alias()
3312
3313        if is_derived:
3314            self._match_r_paren()
3315
3316        return self.expression(
3317            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3318        )
3319
3320    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3321        if not self._match(TokenType.TABLE_SAMPLE) and not (
3322            as_modifier and self._match_text_seq("USING", "SAMPLE")
3323        ):
3324            return None
3325
3326        bucket_numerator = None
3327        bucket_denominator = None
3328        bucket_field = None
3329        percent = None
3330        size = None
3331        seed = None
3332
3333        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3334        matched_l_paren = self._match(TokenType.L_PAREN)
3335
3336        if self.TABLESAMPLE_CSV:
3337            num = None
3338            expressions = self._parse_csv(self._parse_primary)
3339        else:
3340            expressions = None
3341            num = (
3342                self._parse_factor()
3343                if self._match(TokenType.NUMBER, advance=False)
3344                else self._parse_primary() or self._parse_placeholder()
3345            )
3346
3347        if self._match_text_seq("BUCKET"):
3348            bucket_numerator = self._parse_number()
3349            self._match_text_seq("OUT", "OF")
3350            bucket_denominator = bucket_denominator = self._parse_number()
3351            self._match(TokenType.ON)
3352            bucket_field = self._parse_field()
3353        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3354            percent = num
3355        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3356            size = num
3357        else:
3358            percent = num
3359
3360        if matched_l_paren:
3361            self._match_r_paren()
3362
3363        if self._match(TokenType.L_PAREN):
3364            method = self._parse_var(upper=True)
3365            seed = self._match(TokenType.COMMA) and self._parse_number()
3366            self._match_r_paren()
3367        elif self._match_texts(("SEED", "REPEATABLE")):
3368            seed = self._parse_wrapped(self._parse_number)
3369
3370        return self.expression(
3371            exp.TableSample,
3372            expressions=expressions,
3373            method=method,
3374            bucket_numerator=bucket_numerator,
3375            bucket_denominator=bucket_denominator,
3376            bucket_field=bucket_field,
3377            percent=percent,
3378            size=size,
3379            seed=seed,
3380        )
3381
3382    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3383        return list(iter(self._parse_pivot, None)) or None
3384
3385    def _parse_joins(self) -> t.Iterator[exp.Join]:
3386        return iter(self._parse_join, None)
3387
3388    # https://duckdb.org/docs/sql/statements/pivot
3389    def _parse_simplified_pivot(self) -> exp.Pivot:
3390        def _parse_on() -> t.Optional[exp.Expression]:
3391            this = self._parse_bitwise()
3392            return self._parse_in(this) if self._match(TokenType.IN) else this
3393
3394        this = self._parse_table()
3395        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3396        using = self._match(TokenType.USING) and self._parse_csv(
3397            lambda: self._parse_alias(self._parse_function())
3398        )
3399        group = self._parse_group()
3400        return self.expression(
3401            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3402        )
3403
3404    def _parse_pivot_in(self) -> exp.In:
3405        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3406            this = self._parse_conjunction()
3407
3408            self._match(TokenType.ALIAS)
3409            alias = self._parse_field()
3410            if alias:
3411                return self.expression(exp.PivotAlias, this=this, alias=alias)
3412
3413            return this
3414
3415        value = self._parse_column()
3416
3417        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3418            self.raise_error("Expecting IN (")
3419
3420        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3421
3422        self._match_r_paren()
3423        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3424
3425    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3426        index = self._index
3427        include_nulls = None
3428
3429        if self._match(TokenType.PIVOT):
3430            unpivot = False
3431        elif self._match(TokenType.UNPIVOT):
3432            unpivot = True
3433
3434            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3435            if self._match_text_seq("INCLUDE", "NULLS"):
3436                include_nulls = True
3437            elif self._match_text_seq("EXCLUDE", "NULLS"):
3438                include_nulls = False
3439        else:
3440            return None
3441
3442        expressions = []
3443
3444        if not self._match(TokenType.L_PAREN):
3445            self._retreat(index)
3446            return None
3447
3448        if unpivot:
3449            expressions = self._parse_csv(self._parse_column)
3450        else:
3451            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3452
3453        if not expressions:
3454            self.raise_error("Failed to parse PIVOT's aggregation list")
3455
3456        if not self._match(TokenType.FOR):
3457            self.raise_error("Expecting FOR")
3458
3459        field = self._parse_pivot_in()
3460
3461        self._match_r_paren()
3462
3463        pivot = self.expression(
3464            exp.Pivot,
3465            expressions=expressions,
3466            field=field,
3467            unpivot=unpivot,
3468            include_nulls=include_nulls,
3469        )
3470
3471        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3472            pivot.set("alias", self._parse_table_alias())
3473
3474        if not unpivot:
3475            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3476
3477            columns: t.List[exp.Expression] = []
3478            for fld in pivot.args["field"].expressions:
3479                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3480                for name in names:
3481                    if self.PREFIXED_PIVOT_COLUMNS:
3482                        name = f"{name}_{field_name}" if name else field_name
3483                    else:
3484                        name = f"{field_name}_{name}" if name else field_name
3485
3486                    columns.append(exp.to_identifier(name))
3487
3488            pivot.set("columns", columns)
3489
3490        return pivot
3491
3492    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3493        return [agg.alias for agg in aggregations]
3494
3495    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3496        if not skip_where_token and not self._match(TokenType.PREWHERE):
3497            return None
3498
3499        return self.expression(
3500            exp.PreWhere, comments=self._prev_comments, this=self._parse_conjunction()
3501        )
3502
3503    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3504        if not skip_where_token and not self._match(TokenType.WHERE):
3505            return None
3506
3507        return self.expression(
3508            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3509        )
3510
3511    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3512        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3513            return None
3514
3515        elements: t.Dict[str, t.Any] = defaultdict(list)
3516
3517        if self._match(TokenType.ALL):
3518            elements["all"] = True
3519        elif self._match(TokenType.DISTINCT):
3520            elements["all"] = False
3521
3522        while True:
3523            expressions = self._parse_csv(self._parse_conjunction)
3524            if expressions:
3525                elements["expressions"].extend(expressions)
3526
3527            grouping_sets = self._parse_grouping_sets()
3528            if grouping_sets:
3529                elements["grouping_sets"].extend(grouping_sets)
3530
3531            rollup = None
3532            cube = None
3533            totals = None
3534
3535            index = self._index
3536            with_ = self._match(TokenType.WITH)
3537            if self._match(TokenType.ROLLUP):
3538                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3539                elements["rollup"].extend(ensure_list(rollup))
3540
3541            if self._match(TokenType.CUBE):
3542                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3543                elements["cube"].extend(ensure_list(cube))
3544
3545            if self._match_text_seq("TOTALS"):
3546                totals = True
3547                elements["totals"] = True  # type: ignore
3548
3549            if not (grouping_sets or rollup or cube or totals):
3550                if with_:
3551                    self._retreat(index)
3552                break
3553
3554        return self.expression(exp.Group, **elements)  # type: ignore
3555
3556    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3557        if not self._match(TokenType.GROUPING_SETS):
3558            return None
3559
3560        return self._parse_wrapped_csv(self._parse_grouping_set)
3561
3562    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3563        if self._match(TokenType.L_PAREN):
3564            grouping_set = self._parse_csv(self._parse_column)
3565            self._match_r_paren()
3566            return self.expression(exp.Tuple, expressions=grouping_set)
3567
3568        return self._parse_column()
3569
3570    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3571        if not skip_having_token and not self._match(TokenType.HAVING):
3572            return None
3573        return self.expression(exp.Having, this=self._parse_conjunction())
3574
3575    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3576        if not self._match(TokenType.QUALIFY):
3577            return None
3578        return self.expression(exp.Qualify, this=self._parse_conjunction())
3579
3580    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3581        if skip_start_token:
3582            start = None
3583        elif self._match(TokenType.START_WITH):
3584            start = self._parse_conjunction()
3585        else:
3586            return None
3587
3588        self._match(TokenType.CONNECT_BY)
3589        nocycle = self._match_text_seq("NOCYCLE")
3590        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3591            exp.Prior, this=self._parse_bitwise()
3592        )
3593        connect = self._parse_conjunction()
3594        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3595
3596        if not start and self._match(TokenType.START_WITH):
3597            start = self._parse_conjunction()
3598
3599        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3600
3601    def _parse_name_as_expression(self) -> exp.Alias:
3602        return self.expression(
3603            exp.Alias,
3604            alias=self._parse_id_var(any_token=True),
3605            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3606        )
3607
3608    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3609        if self._match_text_seq("INTERPOLATE"):
3610            return self._parse_wrapped_csv(self._parse_name_as_expression)
3611        return None
3612
3613    def _parse_order(
3614        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3615    ) -> t.Optional[exp.Expression]:
3616        siblings = None
3617        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3618            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3619                return this
3620
3621            siblings = True
3622
3623        return self.expression(
3624            exp.Order,
3625            this=this,
3626            expressions=self._parse_csv(self._parse_ordered),
3627            interpolate=self._parse_interpolate(),
3628            siblings=siblings,
3629        )
3630
3631    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3632        if not self._match(token):
3633            return None
3634        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3635
3636    def _parse_ordered(
3637        self, parse_method: t.Optional[t.Callable] = None
3638    ) -> t.Optional[exp.Ordered]:
3639        this = parse_method() if parse_method else self._parse_conjunction()
3640        if not this:
3641            return None
3642
3643        asc = self._match(TokenType.ASC)
3644        desc = self._match(TokenType.DESC) or (asc and False)
3645
3646        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3647        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3648
3649        nulls_first = is_nulls_first or False
3650        explicitly_null_ordered = is_nulls_first or is_nulls_last
3651
3652        if (
3653            not explicitly_null_ordered
3654            and (
3655                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3656                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3657            )
3658            and self.dialect.NULL_ORDERING != "nulls_are_last"
3659        ):
3660            nulls_first = True
3661
3662        if self._match_text_seq("WITH", "FILL"):
3663            with_fill = self.expression(
3664                exp.WithFill,
3665                **{  # type: ignore
3666                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3667                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3668                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3669                },
3670            )
3671        else:
3672            with_fill = None
3673
3674        return self.expression(
3675            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3676        )
3677
3678    def _parse_limit(
3679        self,
3680        this: t.Optional[exp.Expression] = None,
3681        top: bool = False,
3682        skip_limit_token: bool = False,
3683    ) -> t.Optional[exp.Expression]:
3684        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3685            comments = self._prev_comments
3686            if top:
3687                limit_paren = self._match(TokenType.L_PAREN)
3688                expression = self._parse_term() if limit_paren else self._parse_number()
3689
3690                if limit_paren:
3691                    self._match_r_paren()
3692            else:
3693                expression = self._parse_term()
3694
3695            if self._match(TokenType.COMMA):
3696                offset = expression
3697                expression = self._parse_term()
3698            else:
3699                offset = None
3700
3701            limit_exp = self.expression(
3702                exp.Limit,
3703                this=this,
3704                expression=expression,
3705                offset=offset,
3706                comments=comments,
3707                expressions=self._parse_limit_by(),
3708            )
3709
3710            return limit_exp
3711
3712        if self._match(TokenType.FETCH):
3713            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3714            direction = self._prev.text.upper() if direction else "FIRST"
3715
3716            count = self._parse_field(tokens=self.FETCH_TOKENS)
3717            percent = self._match(TokenType.PERCENT)
3718
3719            self._match_set((TokenType.ROW, TokenType.ROWS))
3720
3721            only = self._match_text_seq("ONLY")
3722            with_ties = self._match_text_seq("WITH", "TIES")
3723
3724            if only and with_ties:
3725                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3726
3727            return self.expression(
3728                exp.Fetch,
3729                direction=direction,
3730                count=count,
3731                percent=percent,
3732                with_ties=with_ties,
3733            )
3734
3735        return this
3736
3737    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3738        if not self._match(TokenType.OFFSET):
3739            return this
3740
3741        count = self._parse_term()
3742        self._match_set((TokenType.ROW, TokenType.ROWS))
3743
3744        return self.expression(
3745            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
3746        )
3747
3748    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
3749        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
3750
3751    def _parse_locks(self) -> t.List[exp.Lock]:
3752        locks = []
3753        while True:
3754            if self._match_text_seq("FOR", "UPDATE"):
3755                update = True
3756            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3757                "LOCK", "IN", "SHARE", "MODE"
3758            ):
3759                update = False
3760            else:
3761                break
3762
3763            expressions = None
3764            if self._match_text_seq("OF"):
3765                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3766
3767            wait: t.Optional[bool | exp.Expression] = None
3768            if self._match_text_seq("NOWAIT"):
3769                wait = True
3770            elif self._match_text_seq("WAIT"):
3771                wait = self._parse_primary()
3772            elif self._match_text_seq("SKIP", "LOCKED"):
3773                wait = False
3774
3775            locks.append(
3776                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3777            )
3778
3779        return locks
3780
3781    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3782        while this and self._match_set(self.SET_OPERATIONS):
3783            token_type = self._prev.token_type
3784
3785            if token_type == TokenType.UNION:
3786                operation = exp.Union
3787            elif token_type == TokenType.EXCEPT:
3788                operation = exp.Except
3789            else:
3790                operation = exp.Intersect
3791
3792            comments = self._prev.comments
3793            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3794            by_name = self._match_text_seq("BY", "NAME")
3795            expression = self._parse_select(nested=True, parse_set_operation=False)
3796
3797            this = self.expression(
3798                operation,
3799                comments=comments,
3800                this=this,
3801                distinct=distinct,
3802                by_name=by_name,
3803                expression=expression,
3804            )
3805
3806        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3807            expression = this.expression
3808
3809            if expression:
3810                for arg in self.UNION_MODIFIERS:
3811                    expr = expression.args.get(arg)
3812                    if expr:
3813                        this.set(arg, expr.pop())
3814
3815        return this
3816
3817    def _parse_expression(self) -> t.Optional[exp.Expression]:
3818        return self._parse_alias(self._parse_conjunction())
3819
3820    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3821        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3822
3823    def _parse_equality(self) -> t.Optional[exp.Expression]:
3824        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3825
3826    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3827        return self._parse_tokens(self._parse_range, self.COMPARISON)
3828
3829    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3830        this = this or self._parse_bitwise()
3831        negate = self._match(TokenType.NOT)
3832
3833        if self._match_set(self.RANGE_PARSERS):
3834            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3835            if not expression:
3836                return this
3837
3838            this = expression
3839        elif self._match(TokenType.ISNULL):
3840            this = self.expression(exp.Is, this=this, expression=exp.Null())
3841
3842        # Postgres supports ISNULL and NOTNULL for conditions.
3843        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3844        if self._match(TokenType.NOTNULL):
3845            this = self.expression(exp.Is, this=this, expression=exp.Null())
3846            this = self.expression(exp.Not, this=this)
3847
3848        if negate:
3849            this = self.expression(exp.Not, this=this)
3850
3851        if self._match(TokenType.IS):
3852            this = self._parse_is(this)
3853
3854        return this
3855
3856    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3857        index = self._index - 1
3858        negate = self._match(TokenType.NOT)
3859
3860        if self._match_text_seq("DISTINCT", "FROM"):
3861            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3862            return self.expression(klass, this=this, expression=self._parse_bitwise())
3863
3864        expression = self._parse_null() or self._parse_boolean()
3865        if not expression:
3866            self._retreat(index)
3867            return None
3868
3869        this = self.expression(exp.Is, this=this, expression=expression)
3870        return self.expression(exp.Not, this=this) if negate else this
3871
3872    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3873        unnest = self._parse_unnest(with_alias=False)
3874        if unnest:
3875            this = self.expression(exp.In, this=this, unnest=unnest)
3876        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3877            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3878            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3879
3880            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
3881                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
3882            else:
3883                this = self.expression(exp.In, this=this, expressions=expressions)
3884
3885            if matched_l_paren:
3886                self._match_r_paren(this)
3887            elif not self._match(TokenType.R_BRACKET, expression=this):
3888                self.raise_error("Expecting ]")
3889        else:
3890            this = self.expression(exp.In, this=this, field=self._parse_field())
3891
3892        return this
3893
3894    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3895        low = self._parse_bitwise()
3896        self._match(TokenType.AND)
3897        high = self._parse_bitwise()
3898        return self.expression(exp.Between, this=this, low=low, high=high)
3899
3900    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3901        if not self._match(TokenType.ESCAPE):
3902            return this
3903        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3904
3905    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3906        index = self._index
3907
3908        if not self._match(TokenType.INTERVAL) and match_interval:
3909            return None
3910
3911        if self._match(TokenType.STRING, advance=False):
3912            this = self._parse_primary()
3913        else:
3914            this = self._parse_term()
3915
3916        if not this or (
3917            isinstance(this, exp.Column)
3918            and not this.table
3919            and not this.this.quoted
3920            and this.name.upper() == "IS"
3921        ):
3922            self._retreat(index)
3923            return None
3924
3925        unit = self._parse_function() or (
3926            not self._match(TokenType.ALIAS, advance=False)
3927            and self._parse_var(any_token=True, upper=True)
3928        )
3929
3930        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3931        # each INTERVAL expression into this canonical form so it's easy to transpile
3932        if this and this.is_number:
3933            this = exp.Literal.string(this.name)
3934        elif this and this.is_string:
3935            parts = this.name.split()
3936
3937            if len(parts) == 2:
3938                if unit:
3939                    # This is not actually a unit, it's something else (e.g. a "window side")
3940                    unit = None
3941                    self._retreat(self._index - 1)
3942
3943                this = exp.Literal.string(parts[0])
3944                unit = self.expression(exp.Var, this=parts[1].upper())
3945
3946        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
3947            unit = self.expression(
3948                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
3949            )
3950
3951        return self.expression(exp.Interval, this=this, unit=unit)
3952
3953    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3954        this = self._parse_term()
3955
3956        while True:
3957            if self._match_set(self.BITWISE):
3958                this = self.expression(
3959                    self.BITWISE[self._prev.token_type],
3960                    this=this,
3961                    expression=self._parse_term(),
3962                )
3963            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3964                this = self.expression(
3965                    exp.DPipe,
3966                    this=this,
3967                    expression=self._parse_term(),
3968                    safe=not self.dialect.STRICT_STRING_CONCAT,
3969                )
3970            elif self._match(TokenType.DQMARK):
3971                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3972            elif self._match_pair(TokenType.LT, TokenType.LT):
3973                this = self.expression(
3974                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3975                )
3976            elif self._match_pair(TokenType.GT, TokenType.GT):
3977                this = self.expression(
3978                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3979                )
3980            else:
3981                break
3982
3983        return this
3984
3985    def _parse_term(self) -> t.Optional[exp.Expression]:
3986        return self._parse_tokens(self._parse_factor, self.TERM)
3987
3988    def _parse_factor(self) -> t.Optional[exp.Expression]:
3989        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
3990        this = parse_method()
3991
3992        while self._match_set(self.FACTOR):
3993            this = self.expression(
3994                self.FACTOR[self._prev.token_type],
3995                this=this,
3996                comments=self._prev_comments,
3997                expression=parse_method(),
3998            )
3999            if isinstance(this, exp.Div):
4000                this.args["typed"] = self.dialect.TYPED_DIVISION
4001                this.args["safe"] = self.dialect.SAFE_DIVISION
4002
4003        return this
4004
4005    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4006        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4007
4008    def _parse_unary(self) -> t.Optional[exp.Expression]:
4009        if self._match_set(self.UNARY_PARSERS):
4010            return self.UNARY_PARSERS[self._prev.token_type](self)
4011        return self._parse_at_time_zone(self._parse_type())
4012
4013    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
4014        interval = parse_interval and self._parse_interval()
4015        if interval:
4016            # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4017            while True:
4018                index = self._index
4019                self._match(TokenType.PLUS)
4020
4021                if not self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4022                    self._retreat(index)
4023                    break
4024
4025                interval = self.expression(  # type: ignore
4026                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4027                )
4028
4029            return interval
4030
4031        index = self._index
4032        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4033        this = self._parse_column()
4034
4035        if data_type:
4036            if isinstance(this, exp.Literal):
4037                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4038                if parser:
4039                    return parser(self, this, data_type)
4040                return self.expression(exp.Cast, this=this, to=data_type)
4041            if not data_type.expressions:
4042                self._retreat(index)
4043                return self._parse_column()
4044            return self._parse_column_ops(data_type)
4045
4046        return this and self._parse_column_ops(this)
4047
4048    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4049        this = self._parse_type()
4050        if not this:
4051            return None
4052
4053        if isinstance(this, exp.Column) and not this.table:
4054            this = exp.var(this.name.upper())
4055
4056        return self.expression(
4057            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4058        )
4059
4060    def _parse_types(
4061        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4062    ) -> t.Optional[exp.Expression]:
4063        index = self._index
4064
4065        prefix = self._match_text_seq("SYSUDTLIB", ".")
4066
4067        if not self._match_set(self.TYPE_TOKENS):
4068            identifier = allow_identifiers and self._parse_id_var(
4069                any_token=False, tokens=(TokenType.VAR,)
4070            )
4071            if identifier:
4072                tokens = self.dialect.tokenize(identifier.name)
4073
4074                if len(tokens) != 1:
4075                    self.raise_error("Unexpected identifier", self._prev)
4076
4077                if tokens[0].token_type in self.TYPE_TOKENS:
4078                    self._prev = tokens[0]
4079                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4080                    type_name = identifier.name
4081
4082                    while self._match(TokenType.DOT):
4083                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4084
4085                    return exp.DataType.build(type_name, udt=True)
4086                else:
4087                    self._retreat(self._index - 1)
4088                    return None
4089            else:
4090                return None
4091
4092        type_token = self._prev.token_type
4093
4094        if type_token == TokenType.PSEUDO_TYPE:
4095            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4096
4097        if type_token == TokenType.OBJECT_IDENTIFIER:
4098            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4099
4100        nested = type_token in self.NESTED_TYPE_TOKENS
4101        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4102        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4103        expressions = None
4104        maybe_func = False
4105
4106        if self._match(TokenType.L_PAREN):
4107            if is_struct:
4108                expressions = self._parse_csv(self._parse_struct_types)
4109            elif nested:
4110                expressions = self._parse_csv(
4111                    lambda: self._parse_types(
4112                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4113                    )
4114                )
4115            elif type_token in self.ENUM_TYPE_TOKENS:
4116                expressions = self._parse_csv(self._parse_equality)
4117            elif is_aggregate:
4118                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4119                    any_token=False, tokens=(TokenType.VAR,)
4120                )
4121                if not func_or_ident or not self._match(TokenType.COMMA):
4122                    return None
4123                expressions = self._parse_csv(
4124                    lambda: self._parse_types(
4125                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4126                    )
4127                )
4128                expressions.insert(0, func_or_ident)
4129            else:
4130                expressions = self._parse_csv(self._parse_type_size)
4131
4132            if not expressions or not self._match(TokenType.R_PAREN):
4133                self._retreat(index)
4134                return None
4135
4136            maybe_func = True
4137
4138        this: t.Optional[exp.Expression] = None
4139        values: t.Optional[t.List[exp.Expression]] = None
4140
4141        if nested and self._match(TokenType.LT):
4142            if is_struct:
4143                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4144            else:
4145                expressions = self._parse_csv(
4146                    lambda: self._parse_types(
4147                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4148                    )
4149                )
4150
4151            if not self._match(TokenType.GT):
4152                self.raise_error("Expecting >")
4153
4154            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4155                values = self._parse_csv(self._parse_conjunction)
4156                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4157
4158        if type_token in self.TIMESTAMPS:
4159            if self._match_text_seq("WITH", "TIME", "ZONE"):
4160                maybe_func = False
4161                tz_type = (
4162                    exp.DataType.Type.TIMETZ
4163                    if type_token in self.TIMES
4164                    else exp.DataType.Type.TIMESTAMPTZ
4165                )
4166                this = exp.DataType(this=tz_type, expressions=expressions)
4167            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4168                maybe_func = False
4169                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4170            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4171                maybe_func = False
4172        elif type_token == TokenType.INTERVAL:
4173            unit = self._parse_var(upper=True)
4174            if unit:
4175                if self._match_text_seq("TO"):
4176                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4177
4178                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4179            else:
4180                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4181
4182        if maybe_func and check_func:
4183            index2 = self._index
4184            peek = self._parse_string()
4185
4186            if not peek:
4187                self._retreat(index)
4188                return None
4189
4190            self._retreat(index2)
4191
4192        if not this:
4193            if self._match_text_seq("UNSIGNED"):
4194                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4195                if not unsigned_type_token:
4196                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4197
4198                type_token = unsigned_type_token or type_token
4199
4200            this = exp.DataType(
4201                this=exp.DataType.Type[type_token.value],
4202                expressions=expressions,
4203                nested=nested,
4204                values=values,
4205                prefix=prefix,
4206            )
4207
4208        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
4209            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
4210
4211        return this
4212
4213    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4214        index = self._index
4215        this = self._parse_type(parse_interval=False) or self._parse_id_var()
4216        self._match(TokenType.COLON)
4217        column_def = self._parse_column_def(this)
4218
4219        if type_required and (
4220            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
4221        ):
4222            self._retreat(index)
4223            return self._parse_types()
4224
4225        return column_def
4226
4227    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4228        if not self._match_text_seq("AT", "TIME", "ZONE"):
4229            return this
4230        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4231
4232    def _parse_column(self) -> t.Optional[exp.Expression]:
4233        this = self._parse_column_reference()
4234        return self._parse_column_ops(this) if this else self._parse_bracket(this)
4235
4236    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4237        this = self._parse_field()
4238        if (
4239            not this
4240            and self._match(TokenType.VALUES, advance=False)
4241            and self.VALUES_FOLLOWED_BY_PAREN
4242            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4243        ):
4244            this = self._parse_id_var()
4245
4246        if isinstance(this, exp.Identifier):
4247            # We bubble up comments from the Identifier to the Column
4248            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4249
4250        return this
4251
4252    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4253        this = self._parse_bracket(this)
4254
4255        while self._match_set(self.COLUMN_OPERATORS):
4256            op_token = self._prev.token_type
4257            op = self.COLUMN_OPERATORS.get(op_token)
4258
4259            if op_token == TokenType.DCOLON:
4260                field = self._parse_types()
4261                if not field:
4262                    self.raise_error("Expected type")
4263            elif op and self._curr:
4264                field = self._parse_column_reference()
4265            else:
4266                field = self._parse_field(any_token=True, anonymous_func=True)
4267
4268            if isinstance(field, exp.Func) and this:
4269                # bigquery allows function calls like x.y.count(...)
4270                # SAFE.SUBSTR(...)
4271                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4272                this = exp.replace_tree(
4273                    this,
4274                    lambda n: (
4275                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4276                        if n.table
4277                        else n.this
4278                    )
4279                    if isinstance(n, exp.Column)
4280                    else n,
4281                )
4282
4283            if op:
4284                this = op(self, this, field)
4285            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4286                this = self.expression(
4287                    exp.Column,
4288                    this=field,
4289                    table=this.this,
4290                    db=this.args.get("table"),
4291                    catalog=this.args.get("db"),
4292                )
4293            else:
4294                this = self.expression(exp.Dot, this=this, expression=field)
4295            this = self._parse_bracket(this)
4296        return this
4297
4298    def _parse_primary(self) -> t.Optional[exp.Expression]:
4299        if self._match_set(self.PRIMARY_PARSERS):
4300            token_type = self._prev.token_type
4301            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4302
4303            if token_type == TokenType.STRING:
4304                expressions = [primary]
4305                while self._match(TokenType.STRING):
4306                    expressions.append(exp.Literal.string(self._prev.text))
4307
4308                if len(expressions) > 1:
4309                    return self.expression(exp.Concat, expressions=expressions)
4310
4311            return primary
4312
4313        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4314            return exp.Literal.number(f"0.{self._prev.text}")
4315
4316        if self._match(TokenType.L_PAREN):
4317            comments = self._prev_comments
4318            query = self._parse_select()
4319
4320            if query:
4321                expressions = [query]
4322            else:
4323                expressions = self._parse_expressions()
4324
4325            this = self._parse_query_modifiers(seq_get(expressions, 0))
4326
4327            if not this and self._match(TokenType.R_PAREN, advance=False):
4328                this = self.expression(exp.Tuple)
4329            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4330                this = self._parse_set_operations(
4331                    self._parse_subquery(this=this, parse_alias=False)
4332                )
4333            elif isinstance(this, exp.Subquery):
4334                this = self._parse_subquery(
4335                    this=self._parse_set_operations(this), parse_alias=False
4336                )
4337            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4338                this = self.expression(exp.Tuple, expressions=expressions)
4339            else:
4340                this = self.expression(exp.Paren, this=this)
4341
4342            if this:
4343                this.add_comments(comments)
4344
4345            self._match_r_paren(expression=this)
4346            return this
4347
4348        return None
4349
4350    def _parse_field(
4351        self,
4352        any_token: bool = False,
4353        tokens: t.Optional[t.Collection[TokenType]] = None,
4354        anonymous_func: bool = False,
4355    ) -> t.Optional[exp.Expression]:
4356        if anonymous_func:
4357            field = (
4358                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4359                or self._parse_primary()
4360            )
4361        else:
4362            field = self._parse_primary() or self._parse_function(
4363                anonymous=anonymous_func, any_token=any_token
4364            )
4365        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4366
4367    def _parse_function(
4368        self,
4369        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4370        anonymous: bool = False,
4371        optional_parens: bool = True,
4372        any_token: bool = False,
4373    ) -> t.Optional[exp.Expression]:
4374        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4375        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4376        fn_syntax = False
4377        if (
4378            self._match(TokenType.L_BRACE, advance=False)
4379            and self._next
4380            and self._next.text.upper() == "FN"
4381        ):
4382            self._advance(2)
4383            fn_syntax = True
4384
4385        func = self._parse_function_call(
4386            functions=functions,
4387            anonymous=anonymous,
4388            optional_parens=optional_parens,
4389            any_token=any_token,
4390        )
4391
4392        if fn_syntax:
4393            self._match(TokenType.R_BRACE)
4394
4395        return func
4396
4397    def _parse_function_call(
4398        self,
4399        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4400        anonymous: bool = False,
4401        optional_parens: bool = True,
4402        any_token: bool = False,
4403    ) -> t.Optional[exp.Expression]:
4404        if not self._curr:
4405            return None
4406
4407        comments = self._curr.comments
4408        token_type = self._curr.token_type
4409        this = self._curr.text
4410        upper = this.upper()
4411
4412        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4413        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4414            self._advance()
4415            return self._parse_window(parser(self))
4416
4417        if not self._next or self._next.token_type != TokenType.L_PAREN:
4418            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4419                self._advance()
4420                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4421
4422            return None
4423
4424        if any_token:
4425            if token_type in self.RESERVED_TOKENS:
4426                return None
4427        elif token_type not in self.FUNC_TOKENS:
4428            return None
4429
4430        self._advance(2)
4431
4432        parser = self.FUNCTION_PARSERS.get(upper)
4433        if parser and not anonymous:
4434            this = parser(self)
4435        else:
4436            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4437
4438            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4439                this = self.expression(subquery_predicate, this=self._parse_select())
4440                self._match_r_paren()
4441                return this
4442
4443            if functions is None:
4444                functions = self.FUNCTIONS
4445
4446            function = functions.get(upper)
4447
4448            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4449            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4450
4451            if alias:
4452                args = self._kv_to_prop_eq(args)
4453
4454            if function and not anonymous:
4455                if "dialect" in function.__code__.co_varnames:
4456                    func = function(args, dialect=self.dialect)
4457                else:
4458                    func = function(args)
4459
4460                func = self.validate_expression(func, args)
4461                if not self.dialect.NORMALIZE_FUNCTIONS:
4462                    func.meta["name"] = this
4463
4464                this = func
4465            else:
4466                if token_type == TokenType.IDENTIFIER:
4467                    this = exp.Identifier(this=this, quoted=True)
4468                this = self.expression(exp.Anonymous, this=this, expressions=args)
4469
4470        if isinstance(this, exp.Expression):
4471            this.add_comments(comments)
4472
4473        self._match_r_paren(this)
4474        return self._parse_window(this)
4475
4476    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4477        transformed = []
4478
4479        for e in expressions:
4480            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4481                if isinstance(e, exp.Alias):
4482                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4483
4484                if not isinstance(e, exp.PropertyEQ):
4485                    e = self.expression(
4486                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4487                    )
4488
4489                if isinstance(e.this, exp.Column):
4490                    e.this.replace(e.this.this)
4491
4492            transformed.append(e)
4493
4494        return transformed
4495
4496    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4497        return self._parse_column_def(self._parse_id_var())
4498
4499    def _parse_user_defined_function(
4500        self, kind: t.Optional[TokenType] = None
4501    ) -> t.Optional[exp.Expression]:
4502        this = self._parse_id_var()
4503
4504        while self._match(TokenType.DOT):
4505            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4506
4507        if not self._match(TokenType.L_PAREN):
4508            return this
4509
4510        expressions = self._parse_csv(self._parse_function_parameter)
4511        self._match_r_paren()
4512        return self.expression(
4513            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4514        )
4515
4516    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4517        literal = self._parse_primary()
4518        if literal:
4519            return self.expression(exp.Introducer, this=token.text, expression=literal)
4520
4521        return self.expression(exp.Identifier, this=token.text)
4522
4523    def _parse_session_parameter(self) -> exp.SessionParameter:
4524        kind = None
4525        this = self._parse_id_var() or self._parse_primary()
4526
4527        if this and self._match(TokenType.DOT):
4528            kind = this.name
4529            this = self._parse_var() or self._parse_primary()
4530
4531        return self.expression(exp.SessionParameter, this=this, kind=kind)
4532
4533    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4534        index = self._index
4535
4536        if self._match(TokenType.L_PAREN):
4537            expressions = t.cast(
4538                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4539            )
4540
4541            if not self._match(TokenType.R_PAREN):
4542                self._retreat(index)
4543        else:
4544            expressions = [self._parse_id_var()]
4545
4546        if self._match_set(self.LAMBDAS):
4547            return self.LAMBDAS[self._prev.token_type](self, expressions)
4548
4549        self._retreat(index)
4550
4551        this: t.Optional[exp.Expression]
4552
4553        if self._match(TokenType.DISTINCT):
4554            this = self.expression(
4555                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4556            )
4557        else:
4558            this = self._parse_select_or_expression(alias=alias)
4559
4560        return self._parse_limit(
4561            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
4562        )
4563
4564    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4565        index = self._index
4566        if not self._match(TokenType.L_PAREN):
4567            return this
4568
4569        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
4570        # expr can be of both types
4571        if self._match_set(self.SELECT_START_TOKENS):
4572            self._retreat(index)
4573            return this
4574        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4575        self._match_r_paren()
4576        return self.expression(exp.Schema, this=this, expressions=args)
4577
4578    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4579        return self._parse_column_def(self._parse_field(any_token=True))
4580
4581    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4582        # column defs are not really columns, they're identifiers
4583        if isinstance(this, exp.Column):
4584            this = this.this
4585
4586        kind = self._parse_types(schema=True)
4587
4588        if self._match_text_seq("FOR", "ORDINALITY"):
4589            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4590
4591        constraints: t.List[exp.Expression] = []
4592
4593        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
4594            ("ALIAS", "MATERIALIZED")
4595        ):
4596            persisted = self._prev.text.upper() == "MATERIALIZED"
4597            constraints.append(
4598                self.expression(
4599                    exp.ComputedColumnConstraint,
4600                    this=self._parse_conjunction(),
4601                    persisted=persisted or self._match_text_seq("PERSISTED"),
4602                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4603                )
4604            )
4605        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4606            self._match(TokenType.ALIAS)
4607            constraints.append(
4608                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4609            )
4610
4611        while True:
4612            constraint = self._parse_column_constraint()
4613            if not constraint:
4614                break
4615            constraints.append(constraint)
4616
4617        if not kind and not constraints:
4618            return this
4619
4620        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4621
4622    def _parse_auto_increment(
4623        self,
4624    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4625        start = None
4626        increment = None
4627
4628        if self._match(TokenType.L_PAREN, advance=False):
4629            args = self._parse_wrapped_csv(self._parse_bitwise)
4630            start = seq_get(args, 0)
4631            increment = seq_get(args, 1)
4632        elif self._match_text_seq("START"):
4633            start = self._parse_bitwise()
4634            self._match_text_seq("INCREMENT")
4635            increment = self._parse_bitwise()
4636
4637        if start and increment:
4638            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4639
4640        return exp.AutoIncrementColumnConstraint()
4641
4642    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4643        if not self._match_text_seq("REFRESH"):
4644            self._retreat(self._index - 1)
4645            return None
4646        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4647
4648    def _parse_compress(self) -> exp.CompressColumnConstraint:
4649        if self._match(TokenType.L_PAREN, advance=False):
4650            return self.expression(
4651                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4652            )
4653
4654        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4655
4656    def _parse_generated_as_identity(
4657        self,
4658    ) -> (
4659        exp.GeneratedAsIdentityColumnConstraint
4660        | exp.ComputedColumnConstraint
4661        | exp.GeneratedAsRowColumnConstraint
4662    ):
4663        if self._match_text_seq("BY", "DEFAULT"):
4664            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4665            this = self.expression(
4666                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4667            )
4668        else:
4669            self._match_text_seq("ALWAYS")
4670            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4671
4672        self._match(TokenType.ALIAS)
4673
4674        if self._match_text_seq("ROW"):
4675            start = self._match_text_seq("START")
4676            if not start:
4677                self._match(TokenType.END)
4678            hidden = self._match_text_seq("HIDDEN")
4679            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4680
4681        identity = self._match_text_seq("IDENTITY")
4682
4683        if self._match(TokenType.L_PAREN):
4684            if self._match(TokenType.START_WITH):
4685                this.set("start", self._parse_bitwise())
4686            if self._match_text_seq("INCREMENT", "BY"):
4687                this.set("increment", self._parse_bitwise())
4688            if self._match_text_seq("MINVALUE"):
4689                this.set("minvalue", self._parse_bitwise())
4690            if self._match_text_seq("MAXVALUE"):
4691                this.set("maxvalue", self._parse_bitwise())
4692
4693            if self._match_text_seq("CYCLE"):
4694                this.set("cycle", True)
4695            elif self._match_text_seq("NO", "CYCLE"):
4696                this.set("cycle", False)
4697
4698            if not identity:
4699                this.set("expression", self._parse_range())
4700            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4701                args = self._parse_csv(self._parse_bitwise)
4702                this.set("start", seq_get(args, 0))
4703                this.set("increment", seq_get(args, 1))
4704
4705            self._match_r_paren()
4706
4707        return this
4708
4709    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4710        self._match_text_seq("LENGTH")
4711        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4712
4713    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
4714        if self._match_text_seq("NULL"):
4715            return self.expression(exp.NotNullColumnConstraint)
4716        if self._match_text_seq("CASESPECIFIC"):
4717            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4718        if self._match_text_seq("FOR", "REPLICATION"):
4719            return self.expression(exp.NotForReplicationColumnConstraint)
4720        return None
4721
4722    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4723        if self._match(TokenType.CONSTRAINT):
4724            this = self._parse_id_var()
4725        else:
4726            this = None
4727
4728        if self._match_texts(self.CONSTRAINT_PARSERS):
4729            return self.expression(
4730                exp.ColumnConstraint,
4731                this=this,
4732                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4733            )
4734
4735        return this
4736
4737    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4738        if not self._match(TokenType.CONSTRAINT):
4739            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4740
4741        return self.expression(
4742            exp.Constraint,
4743            this=self._parse_id_var(),
4744            expressions=self._parse_unnamed_constraints(),
4745        )
4746
4747    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
4748        constraints = []
4749        while True:
4750            constraint = self._parse_unnamed_constraint() or self._parse_function()
4751            if not constraint:
4752                break
4753            constraints.append(constraint)
4754
4755        return constraints
4756
4757    def _parse_unnamed_constraint(
4758        self, constraints: t.Optional[t.Collection[str]] = None
4759    ) -> t.Optional[exp.Expression]:
4760        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4761            constraints or self.CONSTRAINT_PARSERS
4762        ):
4763            return None
4764
4765        constraint = self._prev.text.upper()
4766        if constraint not in self.CONSTRAINT_PARSERS:
4767            self.raise_error(f"No parser found for schema constraint {constraint}.")
4768
4769        return self.CONSTRAINT_PARSERS[constraint](self)
4770
4771    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4772        self._match_text_seq("KEY")
4773        return self.expression(
4774            exp.UniqueColumnConstraint,
4775            this=self._parse_schema(self._parse_id_var(any_token=False)),
4776            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4777            on_conflict=self._parse_on_conflict(),
4778        )
4779
4780    def _parse_key_constraint_options(self) -> t.List[str]:
4781        options = []
4782        while True:
4783            if not self._curr:
4784                break
4785
4786            if self._match(TokenType.ON):
4787                action = None
4788                on = self._advance_any() and self._prev.text
4789
4790                if self._match_text_seq("NO", "ACTION"):
4791                    action = "NO ACTION"
4792                elif self._match_text_seq("CASCADE"):
4793                    action = "CASCADE"
4794                elif self._match_text_seq("RESTRICT"):
4795                    action = "RESTRICT"
4796                elif self._match_pair(TokenType.SET, TokenType.NULL):
4797                    action = "SET NULL"
4798                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4799                    action = "SET DEFAULT"
4800                else:
4801                    self.raise_error("Invalid key constraint")
4802
4803                options.append(f"ON {on} {action}")
4804            elif self._match_text_seq("NOT", "ENFORCED"):
4805                options.append("NOT ENFORCED")
4806            elif self._match_text_seq("DEFERRABLE"):
4807                options.append("DEFERRABLE")
4808            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4809                options.append("INITIALLY DEFERRED")
4810            elif self._match_text_seq("NORELY"):
4811                options.append("NORELY")
4812            elif self._match_text_seq("MATCH", "FULL"):
4813                options.append("MATCH FULL")
4814            else:
4815                break
4816
4817        return options
4818
4819    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4820        if match and not self._match(TokenType.REFERENCES):
4821            return None
4822
4823        expressions = None
4824        this = self._parse_table(schema=True)
4825        options = self._parse_key_constraint_options()
4826        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4827
4828    def _parse_foreign_key(self) -> exp.ForeignKey:
4829        expressions = self._parse_wrapped_id_vars()
4830        reference = self._parse_references()
4831        options = {}
4832
4833        while self._match(TokenType.ON):
4834            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4835                self.raise_error("Expected DELETE or UPDATE")
4836
4837            kind = self._prev.text.lower()
4838
4839            if self._match_text_seq("NO", "ACTION"):
4840                action = "NO ACTION"
4841            elif self._match(TokenType.SET):
4842                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4843                action = "SET " + self._prev.text.upper()
4844            else:
4845                self._advance()
4846                action = self._prev.text.upper()
4847
4848            options[kind] = action
4849
4850        return self.expression(
4851            exp.ForeignKey,
4852            expressions=expressions,
4853            reference=reference,
4854            **options,  # type: ignore
4855        )
4856
4857    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4858        return self._parse_field()
4859
4860    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4861        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4862            self._retreat(self._index - 1)
4863            return None
4864
4865        id_vars = self._parse_wrapped_id_vars()
4866        return self.expression(
4867            exp.PeriodForSystemTimeConstraint,
4868            this=seq_get(id_vars, 0),
4869            expression=seq_get(id_vars, 1),
4870        )
4871
4872    def _parse_primary_key(
4873        self, wrapped_optional: bool = False, in_props: bool = False
4874    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4875        desc = (
4876            self._match_set((TokenType.ASC, TokenType.DESC))
4877            and self._prev.token_type == TokenType.DESC
4878        )
4879
4880        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4881            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4882
4883        expressions = self._parse_wrapped_csv(
4884            self._parse_primary_key_part, optional=wrapped_optional
4885        )
4886        options = self._parse_key_constraint_options()
4887        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4888
4889    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4890        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4891
4892    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4893        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4894            return this
4895
4896        bracket_kind = self._prev.token_type
4897        expressions = self._parse_csv(
4898            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4899        )
4900
4901        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
4902            self.raise_error("Expected ]")
4903        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
4904            self.raise_error("Expected }")
4905
4906        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4907        if bracket_kind == TokenType.L_BRACE:
4908            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
4909        elif not this or this.name.upper() == "ARRAY":
4910            this = self.expression(exp.Array, expressions=expressions)
4911        else:
4912            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4913            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4914
4915        self._add_comments(this)
4916        return self._parse_bracket(this)
4917
4918    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4919        if self._match(TokenType.COLON):
4920            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4921        return this
4922
4923    def _parse_case(self) -> t.Optional[exp.Expression]:
4924        ifs = []
4925        default = None
4926
4927        comments = self._prev_comments
4928        expression = self._parse_conjunction()
4929
4930        while self._match(TokenType.WHEN):
4931            this = self._parse_conjunction()
4932            self._match(TokenType.THEN)
4933            then = self._parse_conjunction()
4934            ifs.append(self.expression(exp.If, this=this, true=then))
4935
4936        if self._match(TokenType.ELSE):
4937            default = self._parse_conjunction()
4938
4939        if not self._match(TokenType.END):
4940            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4941                default = exp.column("interval")
4942            else:
4943                self.raise_error("Expected END after CASE", self._prev)
4944
4945        return self.expression(
4946            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
4947        )
4948
4949    def _parse_if(self) -> t.Optional[exp.Expression]:
4950        if self._match(TokenType.L_PAREN):
4951            args = self._parse_csv(self._parse_conjunction)
4952            this = self.validate_expression(exp.If.from_arg_list(args), args)
4953            self._match_r_paren()
4954        else:
4955            index = self._index - 1
4956
4957            if self.NO_PAREN_IF_COMMANDS and index == 0:
4958                return self._parse_as_command(self._prev)
4959
4960            condition = self._parse_conjunction()
4961
4962            if not condition:
4963                self._retreat(index)
4964                return None
4965
4966            self._match(TokenType.THEN)
4967            true = self._parse_conjunction()
4968            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4969            self._match(TokenType.END)
4970            this = self.expression(exp.If, this=condition, true=true, false=false)
4971
4972        return this
4973
4974    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4975        if not self._match_text_seq("VALUE", "FOR"):
4976            self._retreat(self._index - 1)
4977            return None
4978
4979        return self.expression(
4980            exp.NextValueFor,
4981            this=self._parse_column(),
4982            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4983        )
4984
4985    def _parse_extract(self) -> exp.Extract:
4986        this = self._parse_function() or self._parse_var() or self._parse_type()
4987
4988        if self._match(TokenType.FROM):
4989            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4990
4991        if not self._match(TokenType.COMMA):
4992            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4993
4994        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4995
4996    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4997        this = self._parse_conjunction()
4998
4999        if not self._match(TokenType.ALIAS):
5000            if self._match(TokenType.COMMA):
5001                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5002
5003            self.raise_error("Expected AS after CAST")
5004
5005        fmt = None
5006        to = self._parse_types()
5007
5008        if self._match(TokenType.FORMAT):
5009            fmt_string = self._parse_string()
5010            fmt = self._parse_at_time_zone(fmt_string)
5011
5012            if not to:
5013                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5014            if to.this in exp.DataType.TEMPORAL_TYPES:
5015                this = self.expression(
5016                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5017                    this=this,
5018                    format=exp.Literal.string(
5019                        format_time(
5020                            fmt_string.this if fmt_string else "",
5021                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5022                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5023                        )
5024                    ),
5025                )
5026
5027                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5028                    this.set("zone", fmt.args["zone"])
5029                return this
5030        elif not to:
5031            self.raise_error("Expected TYPE after CAST")
5032        elif isinstance(to, exp.Identifier):
5033            to = exp.DataType.build(to.name, udt=True)
5034        elif to.this == exp.DataType.Type.CHAR:
5035            if self._match(TokenType.CHARACTER_SET):
5036                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5037
5038        return self.expression(
5039            exp.Cast if strict else exp.TryCast,
5040            this=this,
5041            to=to,
5042            format=fmt,
5043            safe=safe,
5044            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5045        )
5046
5047    def _parse_string_agg(self) -> exp.Expression:
5048        if self._match(TokenType.DISTINCT):
5049            args: t.List[t.Optional[exp.Expression]] = [
5050                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
5051            ]
5052            if self._match(TokenType.COMMA):
5053                args.extend(self._parse_csv(self._parse_conjunction))
5054        else:
5055            args = self._parse_csv(self._parse_conjunction)  # type: ignore
5056
5057        index = self._index
5058        if not self._match(TokenType.R_PAREN) and args:
5059            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5060            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5061            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5062            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5063
5064        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5065        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5066        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5067        if not self._match_text_seq("WITHIN", "GROUP"):
5068            self._retreat(index)
5069            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5070
5071        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5072        order = self._parse_order(this=seq_get(args, 0))
5073        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5074
5075    def _parse_convert(
5076        self, strict: bool, safe: t.Optional[bool] = None
5077    ) -> t.Optional[exp.Expression]:
5078        this = self._parse_bitwise()
5079
5080        if self._match(TokenType.USING):
5081            to: t.Optional[exp.Expression] = self.expression(
5082                exp.CharacterSet, this=self._parse_var()
5083            )
5084        elif self._match(TokenType.COMMA):
5085            to = self._parse_types()
5086        else:
5087            to = None
5088
5089        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5090
5091    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5092        """
5093        There are generally two variants of the DECODE function:
5094
5095        - DECODE(bin, charset)
5096        - DECODE(expression, search, result [, search, result] ... [, default])
5097
5098        The second variant will always be parsed into a CASE expression. Note that NULL
5099        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5100        instead of relying on pattern matching.
5101        """
5102        args = self._parse_csv(self._parse_conjunction)
5103
5104        if len(args) < 3:
5105            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5106
5107        expression, *expressions = args
5108        if not expression:
5109            return None
5110
5111        ifs = []
5112        for search, result in zip(expressions[::2], expressions[1::2]):
5113            if not search or not result:
5114                return None
5115
5116            if isinstance(search, exp.Literal):
5117                ifs.append(
5118                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5119                )
5120            elif isinstance(search, exp.Null):
5121                ifs.append(
5122                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5123                )
5124            else:
5125                cond = exp.or_(
5126                    exp.EQ(this=expression.copy(), expression=search),
5127                    exp.and_(
5128                        exp.Is(this=expression.copy(), expression=exp.Null()),
5129                        exp.Is(this=search.copy(), expression=exp.Null()),
5130                        copy=False,
5131                    ),
5132                    copy=False,
5133                )
5134                ifs.append(exp.If(this=cond, true=result))
5135
5136        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5137
5138    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5139        self._match_text_seq("KEY")
5140        key = self._parse_column()
5141        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5142        self._match_text_seq("VALUE")
5143        value = self._parse_bitwise()
5144
5145        if not key and not value:
5146            return None
5147        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5148
5149    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5150        if not this or not self._match_text_seq("FORMAT", "JSON"):
5151            return this
5152
5153        return self.expression(exp.FormatJson, this=this)
5154
5155    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5156        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5157        for value in values:
5158            if self._match_text_seq(value, "ON", on):
5159                return f"{value} ON {on}"
5160
5161        return None
5162
5163    @t.overload
5164    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5165
5166    @t.overload
5167    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5168
5169    def _parse_json_object(self, agg=False):
5170        star = self._parse_star()
5171        expressions = (
5172            [star]
5173            if star
5174            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5175        )
5176        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5177
5178        unique_keys = None
5179        if self._match_text_seq("WITH", "UNIQUE"):
5180            unique_keys = True
5181        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5182            unique_keys = False
5183
5184        self._match_text_seq("KEYS")
5185
5186        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5187            self._parse_type()
5188        )
5189        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5190
5191        return self.expression(
5192            exp.JSONObjectAgg if agg else exp.JSONObject,
5193            expressions=expressions,
5194            null_handling=null_handling,
5195            unique_keys=unique_keys,
5196            return_type=return_type,
5197            encoding=encoding,
5198        )
5199
5200    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5201    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5202        if not self._match_text_seq("NESTED"):
5203            this = self._parse_id_var()
5204            kind = self._parse_types(allow_identifiers=False)
5205            nested = None
5206        else:
5207            this = None
5208            kind = None
5209            nested = True
5210
5211        path = self._match_text_seq("PATH") and self._parse_string()
5212        nested_schema = nested and self._parse_json_schema()
5213
5214        return self.expression(
5215            exp.JSONColumnDef,
5216            this=this,
5217            kind=kind,
5218            path=path,
5219            nested_schema=nested_schema,
5220        )
5221
5222    def _parse_json_schema(self) -> exp.JSONSchema:
5223        self._match_text_seq("COLUMNS")
5224        return self.expression(
5225            exp.JSONSchema,
5226            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5227        )
5228
5229    def _parse_json_table(self) -> exp.JSONTable:
5230        this = self._parse_format_json(self._parse_bitwise())
5231        path = self._match(TokenType.COMMA) and self._parse_string()
5232        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5233        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5234        schema = self._parse_json_schema()
5235
5236        return exp.JSONTable(
5237            this=this,
5238            schema=schema,
5239            path=path,
5240            error_handling=error_handling,
5241            empty_handling=empty_handling,
5242        )
5243
5244    def _parse_match_against(self) -> exp.MatchAgainst:
5245        expressions = self._parse_csv(self._parse_column)
5246
5247        self._match_text_seq(")", "AGAINST", "(")
5248
5249        this = self._parse_string()
5250
5251        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5252            modifier = "IN NATURAL LANGUAGE MODE"
5253            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5254                modifier = f"{modifier} WITH QUERY EXPANSION"
5255        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5256            modifier = "IN BOOLEAN MODE"
5257        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5258            modifier = "WITH QUERY EXPANSION"
5259        else:
5260            modifier = None
5261
5262        return self.expression(
5263            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5264        )
5265
5266    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5267    def _parse_open_json(self) -> exp.OpenJSON:
5268        this = self._parse_bitwise()
5269        path = self._match(TokenType.COMMA) and self._parse_string()
5270
5271        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5272            this = self._parse_field(any_token=True)
5273            kind = self._parse_types()
5274            path = self._parse_string()
5275            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5276
5277            return self.expression(
5278                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5279            )
5280
5281        expressions = None
5282        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5283            self._match_l_paren()
5284            expressions = self._parse_csv(_parse_open_json_column_def)
5285
5286        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5287
5288    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5289        args = self._parse_csv(self._parse_bitwise)
5290
5291        if self._match(TokenType.IN):
5292            return self.expression(
5293                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5294            )
5295
5296        if haystack_first:
5297            haystack = seq_get(args, 0)
5298            needle = seq_get(args, 1)
5299        else:
5300            needle = seq_get(args, 0)
5301            haystack = seq_get(args, 1)
5302
5303        return self.expression(
5304            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5305        )
5306
5307    def _parse_predict(self) -> exp.Predict:
5308        self._match_text_seq("MODEL")
5309        this = self._parse_table()
5310
5311        self._match(TokenType.COMMA)
5312        self._match_text_seq("TABLE")
5313
5314        return self.expression(
5315            exp.Predict,
5316            this=this,
5317            expression=self._parse_table(),
5318            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5319        )
5320
5321    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5322        args = self._parse_csv(self._parse_table)
5323        return exp.JoinHint(this=func_name.upper(), expressions=args)
5324
5325    def _parse_substring(self) -> exp.Substring:
5326        # Postgres supports the form: substring(string [from int] [for int])
5327        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5328
5329        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5330
5331        if self._match(TokenType.FROM):
5332            args.append(self._parse_bitwise())
5333        if self._match(TokenType.FOR):
5334            if len(args) == 1:
5335                args.append(exp.Literal.number(1))
5336            args.append(self._parse_bitwise())
5337
5338        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5339
5340    def _parse_trim(self) -> exp.Trim:
5341        # https://www.w3resource.com/sql/character-functions/trim.php
5342        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5343
5344        position = None
5345        collation = None
5346        expression = None
5347
5348        if self._match_texts(self.TRIM_TYPES):
5349            position = self._prev.text.upper()
5350
5351        this = self._parse_bitwise()
5352        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5353            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5354            expression = self._parse_bitwise()
5355
5356            if invert_order:
5357                this, expression = expression, this
5358
5359        if self._match(TokenType.COLLATE):
5360            collation = self._parse_bitwise()
5361
5362        return self.expression(
5363            exp.Trim, this=this, position=position, expression=expression, collation=collation
5364        )
5365
5366    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5367        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5368
5369    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5370        return self._parse_window(self._parse_id_var(), alias=True)
5371
5372    def _parse_respect_or_ignore_nulls(
5373        self, this: t.Optional[exp.Expression]
5374    ) -> t.Optional[exp.Expression]:
5375        if self._match_text_seq("IGNORE", "NULLS"):
5376            return self.expression(exp.IgnoreNulls, this=this)
5377        if self._match_text_seq("RESPECT", "NULLS"):
5378            return self.expression(exp.RespectNulls, this=this)
5379        return this
5380
5381    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5382        if self._match(TokenType.HAVING):
5383            self._match_texts(("MAX", "MIN"))
5384            max = self._prev.text.upper() != "MIN"
5385            return self.expression(
5386                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5387            )
5388
5389        return this
5390
5391    def _parse_window(
5392        self, this: t.Optional[exp.Expression], alias: bool = False
5393    ) -> t.Optional[exp.Expression]:
5394        func = this
5395        comments = func.comments if isinstance(func, exp.Expression) else None
5396
5397        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5398            self._match(TokenType.WHERE)
5399            this = self.expression(
5400                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5401            )
5402            self._match_r_paren()
5403
5404        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5405        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5406        if self._match_text_seq("WITHIN", "GROUP"):
5407            order = self._parse_wrapped(self._parse_order)
5408            this = self.expression(exp.WithinGroup, this=this, expression=order)
5409
5410        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5411        # Some dialects choose to implement and some do not.
5412        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5413
5414        # There is some code above in _parse_lambda that handles
5415        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5416
5417        # The below changes handle
5418        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5419
5420        # Oracle allows both formats
5421        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5422        #   and Snowflake chose to do the same for familiarity
5423        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5424        if isinstance(this, exp.AggFunc):
5425            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5426
5427            if ignore_respect and ignore_respect is not this:
5428                ignore_respect.replace(ignore_respect.this)
5429                this = self.expression(ignore_respect.__class__, this=this)
5430
5431        this = self._parse_respect_or_ignore_nulls(this)
5432
5433        # bigquery select from window x AS (partition by ...)
5434        if alias:
5435            over = None
5436            self._match(TokenType.ALIAS)
5437        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5438            return this
5439        else:
5440            over = self._prev.text.upper()
5441
5442        if comments and isinstance(func, exp.Expression):
5443            func.pop_comments()
5444
5445        if not self._match(TokenType.L_PAREN):
5446            return self.expression(
5447                exp.Window,
5448                comments=comments,
5449                this=this,
5450                alias=self._parse_id_var(False),
5451                over=over,
5452            )
5453
5454        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5455
5456        first = self._match(TokenType.FIRST)
5457        if self._match_text_seq("LAST"):
5458            first = False
5459
5460        partition, order = self._parse_partition_and_order()
5461        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5462
5463        if kind:
5464            self._match(TokenType.BETWEEN)
5465            start = self._parse_window_spec()
5466            self._match(TokenType.AND)
5467            end = self._parse_window_spec()
5468
5469            spec = self.expression(
5470                exp.WindowSpec,
5471                kind=kind,
5472                start=start["value"],
5473                start_side=start["side"],
5474                end=end["value"],
5475                end_side=end["side"],
5476            )
5477        else:
5478            spec = None
5479
5480        self._match_r_paren()
5481
5482        window = self.expression(
5483            exp.Window,
5484            comments=comments,
5485            this=this,
5486            partition_by=partition,
5487            order=order,
5488            spec=spec,
5489            alias=window_alias,
5490            over=over,
5491            first=first,
5492        )
5493
5494        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5495        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5496            return self._parse_window(window, alias=alias)
5497
5498        return window
5499
5500    def _parse_partition_and_order(
5501        self,
5502    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5503        return self._parse_partition_by(), self._parse_order()
5504
5505    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5506        self._match(TokenType.BETWEEN)
5507
5508        return {
5509            "value": (
5510                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5511                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5512                or self._parse_bitwise()
5513            ),
5514            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5515        }
5516
5517    def _parse_alias(
5518        self, this: t.Optional[exp.Expression], explicit: bool = False
5519    ) -> t.Optional[exp.Expression]:
5520        any_token = self._match(TokenType.ALIAS)
5521        comments = self._prev_comments or []
5522
5523        if explicit and not any_token:
5524            return this
5525
5526        if self._match(TokenType.L_PAREN):
5527            aliases = self.expression(
5528                exp.Aliases,
5529                comments=comments,
5530                this=this,
5531                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5532            )
5533            self._match_r_paren(aliases)
5534            return aliases
5535
5536        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
5537            self.STRING_ALIASES and self._parse_string_as_identifier()
5538        )
5539
5540        if alias:
5541            comments.extend(alias.pop_comments())
5542            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5543            column = this.this
5544
5545            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5546            if not this.comments and column and column.comments:
5547                this.comments = column.pop_comments()
5548
5549        return this
5550
5551    def _parse_id_var(
5552        self,
5553        any_token: bool = True,
5554        tokens: t.Optional[t.Collection[TokenType]] = None,
5555    ) -> t.Optional[exp.Expression]:
5556        expression = self._parse_identifier()
5557        if not expression and (
5558            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
5559        ):
5560            quoted = self._prev.token_type == TokenType.STRING
5561            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
5562
5563        return expression
5564
5565    def _parse_string(self) -> t.Optional[exp.Expression]:
5566        if self._match_set(self.STRING_PARSERS):
5567            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
5568        return self._parse_placeholder()
5569
5570    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5571        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5572
5573    def _parse_number(self) -> t.Optional[exp.Expression]:
5574        if self._match_set(self.NUMERIC_PARSERS):
5575            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
5576        return self._parse_placeholder()
5577
5578    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5579        if self._match(TokenType.IDENTIFIER):
5580            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5581        return self._parse_placeholder()
5582
5583    def _parse_var(
5584        self,
5585        any_token: bool = False,
5586        tokens: t.Optional[t.Collection[TokenType]] = None,
5587        upper: bool = False,
5588    ) -> t.Optional[exp.Expression]:
5589        if (
5590            (any_token and self._advance_any())
5591            or self._match(TokenType.VAR)
5592            or (self._match_set(tokens) if tokens else False)
5593        ):
5594            return self.expression(
5595                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5596            )
5597        return self._parse_placeholder()
5598
5599    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5600        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5601            self._advance()
5602            return self._prev
5603        return None
5604
5605    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5606        return self._parse_var() or self._parse_string()
5607
5608    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
5609        return self._parse_primary() or self._parse_var(any_token=True)
5610
5611    def _parse_null(self) -> t.Optional[exp.Expression]:
5612        if self._match_set(self.NULL_TOKENS):
5613            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5614        return self._parse_placeholder()
5615
5616    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5617        if self._match(TokenType.TRUE):
5618            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5619        if self._match(TokenType.FALSE):
5620            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5621        return self._parse_placeholder()
5622
5623    def _parse_star(self) -> t.Optional[exp.Expression]:
5624        if self._match(TokenType.STAR):
5625            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5626        return self._parse_placeholder()
5627
5628    def _parse_parameter(self) -> exp.Parameter:
5629        self._match(TokenType.L_BRACE)
5630        this = self._parse_identifier() or self._parse_primary_or_var()
5631        expression = self._match(TokenType.COLON) and (
5632            self._parse_identifier() or self._parse_primary_or_var()
5633        )
5634        self._match(TokenType.R_BRACE)
5635        return self.expression(exp.Parameter, this=this, expression=expression)
5636
5637    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5638        if self._match_set(self.PLACEHOLDER_PARSERS):
5639            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5640            if placeholder:
5641                return placeholder
5642            self._advance(-1)
5643        return None
5644
5645    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5646        if not self._match(TokenType.EXCEPT):
5647            return None
5648        if self._match(TokenType.L_PAREN, advance=False):
5649            return self._parse_wrapped_csv(self._parse_column)
5650
5651        except_column = self._parse_column()
5652        return [except_column] if except_column else None
5653
5654    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5655        if not self._match(TokenType.REPLACE):
5656            return None
5657        if self._match(TokenType.L_PAREN, advance=False):
5658            return self._parse_wrapped_csv(self._parse_expression)
5659
5660        replace_expression = self._parse_expression()
5661        return [replace_expression] if replace_expression else None
5662
5663    def _parse_csv(
5664        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5665    ) -> t.List[exp.Expression]:
5666        parse_result = parse_method()
5667        items = [parse_result] if parse_result is not None else []
5668
5669        while self._match(sep):
5670            self._add_comments(parse_result)
5671            parse_result = parse_method()
5672            if parse_result is not None:
5673                items.append(parse_result)
5674
5675        return items
5676
5677    def _parse_tokens(
5678        self, parse_method: t.Callable, expressions: t.Dict
5679    ) -> t.Optional[exp.Expression]:
5680        this = parse_method()
5681
5682        while self._match_set(expressions):
5683            this = self.expression(
5684                expressions[self._prev.token_type],
5685                this=this,
5686                comments=self._prev_comments,
5687                expression=parse_method(),
5688            )
5689
5690        return this
5691
5692    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5693        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5694
5695    def _parse_wrapped_csv(
5696        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5697    ) -> t.List[exp.Expression]:
5698        return self._parse_wrapped(
5699            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5700        )
5701
5702    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5703        wrapped = self._match(TokenType.L_PAREN)
5704        if not wrapped and not optional:
5705            self.raise_error("Expecting (")
5706        parse_result = parse_method()
5707        if wrapped:
5708            self._match_r_paren()
5709        return parse_result
5710
5711    def _parse_expressions(self) -> t.List[exp.Expression]:
5712        return self._parse_csv(self._parse_expression)
5713
5714    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5715        return self._parse_select() or self._parse_set_operations(
5716            self._parse_expression() if alias else self._parse_conjunction()
5717        )
5718
5719    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5720        return self._parse_query_modifiers(
5721            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5722        )
5723
5724    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5725        this = None
5726        if self._match_texts(self.TRANSACTION_KIND):
5727            this = self._prev.text
5728
5729        self._match_texts(("TRANSACTION", "WORK"))
5730
5731        modes = []
5732        while True:
5733            mode = []
5734            while self._match(TokenType.VAR):
5735                mode.append(self._prev.text)
5736
5737            if mode:
5738                modes.append(" ".join(mode))
5739            if not self._match(TokenType.COMMA):
5740                break
5741
5742        return self.expression(exp.Transaction, this=this, modes=modes)
5743
5744    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5745        chain = None
5746        savepoint = None
5747        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5748
5749        self._match_texts(("TRANSACTION", "WORK"))
5750
5751        if self._match_text_seq("TO"):
5752            self._match_text_seq("SAVEPOINT")
5753            savepoint = self._parse_id_var()
5754
5755        if self._match(TokenType.AND):
5756            chain = not self._match_text_seq("NO")
5757            self._match_text_seq("CHAIN")
5758
5759        if is_rollback:
5760            return self.expression(exp.Rollback, savepoint=savepoint)
5761
5762        return self.expression(exp.Commit, chain=chain)
5763
5764    def _parse_refresh(self) -> exp.Refresh:
5765        self._match(TokenType.TABLE)
5766        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5767
5768    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5769        if not self._match_text_seq("ADD"):
5770            return None
5771
5772        self._match(TokenType.COLUMN)
5773        exists_column = self._parse_exists(not_=True)
5774        expression = self._parse_field_def()
5775
5776        if expression:
5777            expression.set("exists", exists_column)
5778
5779            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5780            if self._match_texts(("FIRST", "AFTER")):
5781                position = self._prev.text
5782                column_position = self.expression(
5783                    exp.ColumnPosition, this=self._parse_column(), position=position
5784                )
5785                expression.set("position", column_position)
5786
5787        return expression
5788
5789    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5790        drop = self._match(TokenType.DROP) and self._parse_drop()
5791        if drop and not isinstance(drop, exp.Command):
5792            drop.set("kind", drop.args.get("kind", "COLUMN"))
5793        return drop
5794
5795    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5796    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5797        return self.expression(
5798            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5799        )
5800
5801    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5802        index = self._index - 1
5803
5804        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
5805            return self._parse_csv(
5806                lambda: self.expression(
5807                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
5808                )
5809            )
5810
5811        self._retreat(index)
5812        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5813            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5814        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5815
5816    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5817        self._match(TokenType.COLUMN)
5818        column = self._parse_field(any_token=True)
5819
5820        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5821            return self.expression(exp.AlterColumn, this=column, drop=True)
5822        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5823            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5824        if self._match(TokenType.COMMENT):
5825            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
5826
5827        self._match_text_seq("SET", "DATA")
5828        self._match_text_seq("TYPE")
5829        return self.expression(
5830            exp.AlterColumn,
5831            this=column,
5832            dtype=self._parse_types(),
5833            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5834            using=self._match(TokenType.USING) and self._parse_conjunction(),
5835        )
5836
5837    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5838        index = self._index - 1
5839
5840        partition_exists = self._parse_exists()
5841        if self._match(TokenType.PARTITION, advance=False):
5842            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5843
5844        self._retreat(index)
5845        return self._parse_csv(self._parse_drop_column)
5846
5847    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
5848        if self._match(TokenType.COLUMN):
5849            exists = self._parse_exists()
5850            old_column = self._parse_column()
5851            to = self._match_text_seq("TO")
5852            new_column = self._parse_column()
5853
5854            if old_column is None or to is None or new_column is None:
5855                return None
5856
5857            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
5858
5859        self._match_text_seq("TO")
5860        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5861
5862    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5863        start = self._prev
5864
5865        if not self._match(TokenType.TABLE):
5866            return self._parse_as_command(start)
5867
5868        exists = self._parse_exists()
5869        only = self._match_text_seq("ONLY")
5870        this = self._parse_table(schema=True)
5871
5872        if self._next:
5873            self._advance()
5874
5875        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5876        if parser:
5877            actions = ensure_list(parser(self))
5878            options = self._parse_csv(self._parse_property)
5879
5880            if not self._curr and actions:
5881                return self.expression(
5882                    exp.AlterTable,
5883                    this=this,
5884                    exists=exists,
5885                    actions=actions,
5886                    only=only,
5887                    options=options,
5888                )
5889
5890        return self._parse_as_command(start)
5891
5892    def _parse_merge(self) -> exp.Merge:
5893        self._match(TokenType.INTO)
5894        target = self._parse_table()
5895
5896        if target and self._match(TokenType.ALIAS, advance=False):
5897            target.set("alias", self._parse_table_alias())
5898
5899        self._match(TokenType.USING)
5900        using = self._parse_table()
5901
5902        self._match(TokenType.ON)
5903        on = self._parse_conjunction()
5904
5905        return self.expression(
5906            exp.Merge,
5907            this=target,
5908            using=using,
5909            on=on,
5910            expressions=self._parse_when_matched(),
5911        )
5912
5913    def _parse_when_matched(self) -> t.List[exp.When]:
5914        whens = []
5915
5916        while self._match(TokenType.WHEN):
5917            matched = not self._match(TokenType.NOT)
5918            self._match_text_seq("MATCHED")
5919            source = (
5920                False
5921                if self._match_text_seq("BY", "TARGET")
5922                else self._match_text_seq("BY", "SOURCE")
5923            )
5924            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5925
5926            self._match(TokenType.THEN)
5927
5928            if self._match(TokenType.INSERT):
5929                _this = self._parse_star()
5930                if _this:
5931                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5932                else:
5933                    then = self.expression(
5934                        exp.Insert,
5935                        this=self._parse_value(),
5936                        expression=self._match_text_seq("VALUES") and self._parse_value(),
5937                    )
5938            elif self._match(TokenType.UPDATE):
5939                expressions = self._parse_star()
5940                if expressions:
5941                    then = self.expression(exp.Update, expressions=expressions)
5942                else:
5943                    then = self.expression(
5944                        exp.Update,
5945                        expressions=self._match(TokenType.SET)
5946                        and self._parse_csv(self._parse_equality),
5947                    )
5948            elif self._match(TokenType.DELETE):
5949                then = self.expression(exp.Var, this=self._prev.text)
5950            else:
5951                then = None
5952
5953            whens.append(
5954                self.expression(
5955                    exp.When,
5956                    matched=matched,
5957                    source=source,
5958                    condition=condition,
5959                    then=then,
5960                )
5961            )
5962        return whens
5963
5964    def _parse_show(self) -> t.Optional[exp.Expression]:
5965        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5966        if parser:
5967            return parser(self)
5968        return self._parse_as_command(self._prev)
5969
5970    def _parse_set_item_assignment(
5971        self, kind: t.Optional[str] = None
5972    ) -> t.Optional[exp.Expression]:
5973        index = self._index
5974
5975        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5976            return self._parse_set_transaction(global_=kind == "GLOBAL")
5977
5978        left = self._parse_primary() or self._parse_id_var()
5979        assignment_delimiter = self._match_texts(("=", "TO"))
5980
5981        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5982            self._retreat(index)
5983            return None
5984
5985        right = self._parse_statement() or self._parse_id_var()
5986        this = self.expression(exp.EQ, this=left, expression=right)
5987
5988        return self.expression(exp.SetItem, this=this, kind=kind)
5989
5990    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5991        self._match_text_seq("TRANSACTION")
5992        characteristics = self._parse_csv(
5993            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5994        )
5995        return self.expression(
5996            exp.SetItem,
5997            expressions=characteristics,
5998            kind="TRANSACTION",
5999            **{"global": global_},  # type: ignore
6000        )
6001
6002    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6003        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6004        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6005
6006    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6007        index = self._index
6008        set_ = self.expression(
6009            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6010        )
6011
6012        if self._curr:
6013            self._retreat(index)
6014            return self._parse_as_command(self._prev)
6015
6016        return set_
6017
6018    def _parse_var_from_options(
6019        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6020    ) -> t.Optional[exp.Var]:
6021        start = self._curr
6022        if not start:
6023            return None
6024
6025        option = start.text.upper()
6026        continuations = options.get(option)
6027
6028        index = self._index
6029        self._advance()
6030        for keywords in continuations or []:
6031            if isinstance(keywords, str):
6032                keywords = (keywords,)
6033
6034            if self._match_text_seq(*keywords):
6035                option = f"{option} {' '.join(keywords)}"
6036                break
6037        else:
6038            if continuations or continuations is None:
6039                if raise_unmatched:
6040                    self.raise_error(f"Unknown option {option}")
6041
6042                self._retreat(index)
6043                return None
6044
6045        return exp.var(option)
6046
6047    def _parse_as_command(self, start: Token) -> exp.Command:
6048        while self._curr:
6049            self._advance()
6050        text = self._find_sql(start, self._prev)
6051        size = len(start.text)
6052        self._warn_unsupported()
6053        return exp.Command(this=text[:size], expression=text[size:])
6054
6055    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6056        settings = []
6057
6058        self._match_l_paren()
6059        kind = self._parse_id_var()
6060
6061        if self._match(TokenType.L_PAREN):
6062            while True:
6063                key = self._parse_id_var()
6064                value = self._parse_primary()
6065
6066                if not key and value is None:
6067                    break
6068                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6069            self._match(TokenType.R_PAREN)
6070
6071        self._match_r_paren()
6072
6073        return self.expression(
6074            exp.DictProperty,
6075            this=this,
6076            kind=kind.this if kind else None,
6077            settings=settings,
6078        )
6079
6080    def _parse_dict_range(self, this: str) -> exp.DictRange:
6081        self._match_l_paren()
6082        has_min = self._match_text_seq("MIN")
6083        if has_min:
6084            min = self._parse_var() or self._parse_primary()
6085            self._match_text_seq("MAX")
6086            max = self._parse_var() or self._parse_primary()
6087        else:
6088            max = self._parse_var() or self._parse_primary()
6089            min = exp.Literal.number(0)
6090        self._match_r_paren()
6091        return self.expression(exp.DictRange, this=this, min=min, max=max)
6092
6093    def _parse_comprehension(
6094        self, this: t.Optional[exp.Expression]
6095    ) -> t.Optional[exp.Comprehension]:
6096        index = self._index
6097        expression = self._parse_column()
6098        if not self._match(TokenType.IN):
6099            self._retreat(index - 1)
6100            return None
6101        iterator = self._parse_column()
6102        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
6103        return self.expression(
6104            exp.Comprehension,
6105            this=this,
6106            expression=expression,
6107            iterator=iterator,
6108            condition=condition,
6109        )
6110
6111    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6112        if self._match(TokenType.HEREDOC_STRING):
6113            return self.expression(exp.Heredoc, this=self._prev.text)
6114
6115        if not self._match_text_seq("$"):
6116            return None
6117
6118        tags = ["$"]
6119        tag_text = None
6120
6121        if self._is_connected():
6122            self._advance()
6123            tags.append(self._prev.text.upper())
6124        else:
6125            self.raise_error("No closing $ found")
6126
6127        if tags[-1] != "$":
6128            if self._is_connected() and self._match_text_seq("$"):
6129                tag_text = tags[-1]
6130                tags.append("$")
6131            else:
6132                self.raise_error("No closing $ found")
6133
6134        heredoc_start = self._curr
6135
6136        while self._curr:
6137            if self._match_text_seq(*tags, advance=False):
6138                this = self._find_sql(heredoc_start, self._prev)
6139                self._advance(len(tags))
6140                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6141
6142            self._advance()
6143
6144        self.raise_error(f"No closing {''.join(tags)} found")
6145        return None
6146
6147    def _find_parser(
6148        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6149    ) -> t.Optional[t.Callable]:
6150        if not self._curr:
6151            return None
6152
6153        index = self._index
6154        this = []
6155        while True:
6156            # The current token might be multiple words
6157            curr = self._curr.text.upper()
6158            key = curr.split(" ")
6159            this.append(curr)
6160
6161            self._advance()
6162            result, trie = in_trie(trie, key)
6163            if result == TrieResult.FAILED:
6164                break
6165
6166            if result == TrieResult.EXISTS:
6167                subparser = parsers[" ".join(this)]
6168                return subparser
6169
6170        self._retreat(index)
6171        return None
6172
6173    def _match(self, token_type, advance=True, expression=None):
6174        if not self._curr:
6175            return None
6176
6177        if self._curr.token_type == token_type:
6178            if advance:
6179                self._advance()
6180            self._add_comments(expression)
6181            return True
6182
6183        return None
6184
6185    def _match_set(self, types, advance=True):
6186        if not self._curr:
6187            return None
6188
6189        if self._curr.token_type in types:
6190            if advance:
6191                self._advance()
6192            return True
6193
6194        return None
6195
6196    def _match_pair(self, token_type_a, token_type_b, advance=True):
6197        if not self._curr or not self._next:
6198            return None
6199
6200        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6201            if advance:
6202                self._advance(2)
6203            return True
6204
6205        return None
6206
6207    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6208        if not self._match(TokenType.L_PAREN, expression=expression):
6209            self.raise_error("Expecting (")
6210
6211    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6212        if not self._match(TokenType.R_PAREN, expression=expression):
6213            self.raise_error("Expecting )")
6214
6215    def _match_texts(self, texts, advance=True):
6216        if self._curr and self._curr.text.upper() in texts:
6217            if advance:
6218                self._advance()
6219            return True
6220        return None
6221
6222    def _match_text_seq(self, *texts, advance=True):
6223        index = self._index
6224        for text in texts:
6225            if self._curr and self._curr.text.upper() == text:
6226                self._advance()
6227            else:
6228                self._retreat(index)
6229                return None
6230
6231        if not advance:
6232            self._retreat(index)
6233
6234        return True
6235
6236    def _replace_lambda(
6237        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
6238    ) -> t.Optional[exp.Expression]:
6239        if not node:
6240            return node
6241
6242        for column in node.find_all(exp.Column):
6243            if column.parts[0].name in lambda_variables:
6244                dot_or_id = column.to_dot() if column.table else column.this
6245                parent = column.parent
6246
6247                while isinstance(parent, exp.Dot):
6248                    if not isinstance(parent.parent, exp.Dot):
6249                        parent.replace(dot_or_id)
6250                        break
6251                    parent = parent.parent
6252                else:
6253                    if column is node:
6254                        node = dot_or_id
6255                    else:
6256                        column.replace(dot_or_id)
6257        return node
6258
6259    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6260        start = self._prev
6261
6262        # Not to be confused with TRUNCATE(number, decimals) function call
6263        if self._match(TokenType.L_PAREN):
6264            self._retreat(self._index - 2)
6265            return self._parse_function()
6266
6267        # Clickhouse supports TRUNCATE DATABASE as well
6268        is_database = self._match(TokenType.DATABASE)
6269
6270        self._match(TokenType.TABLE)
6271
6272        exists = self._parse_exists(not_=False)
6273
6274        expressions = self._parse_csv(
6275            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6276        )
6277
6278        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6279
6280        if self._match_text_seq("RESTART", "IDENTITY"):
6281            identity = "RESTART"
6282        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6283            identity = "CONTINUE"
6284        else:
6285            identity = None
6286
6287        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6288            option = self._prev.text
6289        else:
6290            option = None
6291
6292        partition = self._parse_partition()
6293
6294        # Fallback case
6295        if self._curr:
6296            return self._parse_as_command(start)
6297
6298        return self.expression(
6299            exp.TruncateTable,
6300            expressions=expressions,
6301            is_database=is_database,
6302            exists=exists,
6303            cluster=cluster,
6304            identity=identity,
6305            option=option,
6306            partition=partition,
6307        )
6308
6309    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6310        this = self._parse_ordered(self._parse_opclass)
6311
6312        if not self._match(TokenType.WITH):
6313            return this
6314
6315        op = self._parse_var(any_token=True)
6316
6317        return self.expression(exp.WithOperator, this=this, op=op)
6318
6319    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6320        opts = []
6321        self._match(TokenType.EQ)
6322        self._match(TokenType.L_PAREN)
6323        while self._curr and not self._match(TokenType.R_PAREN):
6324            opts.append(self._parse_conjunction())
6325            self._match(TokenType.COMMA)
6326        return opts
6327
6328    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6329        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6330
6331        options = []
6332        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6333            option = self._parse_unquoted_field()
6334            value = None
6335
6336            # Some options are defined as functions with the values as params
6337            if not isinstance(option, exp.Func):
6338                prev = self._prev.text.upper()
6339                # Different dialects might separate options and values by white space, "=" and "AS"
6340                self._match(TokenType.EQ)
6341                self._match(TokenType.ALIAS)
6342
6343                if prev == "FILE_FORMAT" and self._match(TokenType.L_PAREN):
6344                    # Snowflake FILE_FORMAT case
6345                    value = self._parse_wrapped_options()
6346                else:
6347                    value = self._parse_unquoted_field()
6348
6349            param = self.expression(exp.CopyParameter, this=option, expression=value)
6350            options.append(param)
6351
6352            if sep:
6353                self._match(sep)
6354
6355        return options
6356
6357    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6358        expr = self.expression(exp.Credentials)
6359
6360        if self._match_text_seq("STORAGE_INTEGRATION", advance=False):
6361            expr.set("storage", self._parse_conjunction())
6362        if self._match_text_seq("CREDENTIALS"):
6363            # Snowflake supports CREDENTIALS = (...), while Redshift CREDENTIALS <string>
6364            creds = (
6365                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6366            )
6367            expr.set("credentials", creds)
6368        if self._match_text_seq("ENCRYPTION"):
6369            expr.set("encryption", self._parse_wrapped_options())
6370        if self._match_text_seq("IAM_ROLE"):
6371            expr.set("iam_role", self._parse_field())
6372        if self._match_text_seq("REGION"):
6373            expr.set("region", self._parse_field())
6374
6375        return expr
6376
6377    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6378        return self._parse_field()
6379
6380    def _parse_copy(self) -> exp.Copy | exp.Command:
6381        start = self._prev
6382
6383        self._match(TokenType.INTO)
6384
6385        this = (
6386            self._parse_conjunction()
6387            if self._match(TokenType.L_PAREN, advance=False)
6388            else self._parse_table(schema=True)
6389        )
6390
6391        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
6392
6393        files = self._parse_csv(self._parse_file_location)
6394        credentials = self._parse_credentials()
6395
6396        self._match_text_seq("WITH")
6397
6398        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
6399
6400        # Fallback case
6401        if self._curr:
6402            return self._parse_as_command(start)
6403
6404        return self.expression(
6405            exp.Copy,
6406            this=this,
6407            kind=kind,
6408            credentials=credentials,
6409            files=files,
6410            params=params,
6411        )

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)
1139    def __init__(
1140        self,
1141        error_level: t.Optional[ErrorLevel] = None,
1142        error_message_context: int = 100,
1143        max_errors: int = 3,
1144        dialect: DialectType = None,
1145    ):
1146        from sqlglot.dialects import Dialect
1147
1148        self.error_level = error_level or ErrorLevel.IMMEDIATE
1149        self.error_message_context = error_message_context
1150        self.max_errors = max_errors
1151        self.dialect = Dialect.get_or_raise(dialect)
1152        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_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME_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_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <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>, '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'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, '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'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, '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>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'MOD': <function Parser.<lambda>>}
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.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MAP: 'MAP'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.BIT: 'BIT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT: 'INT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
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.AMP: 'AMP'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.CARET: 'CARET'>, <TokenType.EQ: 'EQ'>, <TokenType.LT: 'LT'>, <TokenType.DOT: 'DOT'>, <TokenType.STAR: 'STAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.HASH: 'HASH'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.PLUS: 'PLUS'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.COLON: 'COLON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.GT: 'GT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.NOT: 'NOT'>, <TokenType.TILDA: 'TILDA'>, <TokenType.MOD: 'MOD'>, <TokenType.DASH: 'DASH'>}
DB_CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.COLUMN: 'COLUMN'>}
ID_VAR_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
INTERVAL_VARS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
TABLE_ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
UPDATE_ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ANY: 'ANY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.GLOB: 'GLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.BIT: 'BIT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XOR: 'XOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INSERT: 'INSERT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT: 'INT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SOME: 'SOME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ALL: 'ALL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LIKE: 'LIKE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.POSITIONAL: 'POSITIONAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.ANTI: 'ANTI'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.INNER: 'INNER'>}
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.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>}
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>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, '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>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, '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>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PRIMARY KEY', 'UNIQUE', 'CHECK', 'FOREIGN KEY', 'LIKE', 'EXCLUDE', 'PERIOD'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
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.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
INSERT_ALTERNATIVES = {'REPLACE', 'FAIL', 'ABORT', 'IGNORE', 'ROLLBACK'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'OFFSET', 'STREAM', 'STATEMENT', 'TIMESTAMP'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'NULLS', 'DESC', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
VIEW_ATTRIBUTES = {'VIEW_METADATA', 'SCHEMABINDING', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.IPV6: 'IPV6'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NAME: 'NAME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ANY: 'ANY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.KILL: 'KILL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIT: 'BIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.IS: 'IS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TOP: 'TOP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE: 'DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT: 'INT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COPY: 'COPY'>, <TokenType.USE: 'USE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DELETE: 'DELETE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SOME: 'SOME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.FALSE: 'FALSE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROW: 'ROW'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INET: 'INET'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE32: 'DATE32'>}
SELECT_START_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'limit', 'offset', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1154    def reset(self):
1155        self.sql = ""
1156        self.errors = []
1157        self._tokens = []
1158        self._index = 0
1159        self._curr = None
1160        self._next = None
1161        self._prev = None
1162        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1164    def parse(
1165        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1166    ) -> t.List[t.Optional[exp.Expression]]:
1167        """
1168        Parses a list of tokens and returns a list of syntax trees, one tree
1169        per parsed SQL statement.
1170
1171        Args:
1172            raw_tokens: The list of tokens.
1173            sql: The original SQL string, used to produce helpful debug messages.
1174
1175        Returns:
1176            The list of the produced syntax trees.
1177        """
1178        return self._parse(
1179            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1180        )

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]]:
1182    def parse_into(
1183        self,
1184        expression_types: exp.IntoType,
1185        raw_tokens: t.List[Token],
1186        sql: t.Optional[str] = None,
1187    ) -> t.List[t.Optional[exp.Expression]]:
1188        """
1189        Parses a list of tokens into a given Expression type. If a collection of Expression
1190        types is given instead, this method will try to parse the token list into each one
1191        of them, stopping at the first for which the parsing succeeds.
1192
1193        Args:
1194            expression_types: The expression type(s) to try and parse the token list into.
1195            raw_tokens: The list of tokens.
1196            sql: The original SQL string, used to produce helpful debug messages.
1197
1198        Returns:
1199            The target Expression.
1200        """
1201        errors = []
1202        for expression_type in ensure_list(expression_types):
1203            parser = self.EXPRESSION_PARSERS.get(expression_type)
1204            if not parser:
1205                raise TypeError(f"No parser registered for {expression_type}")
1206
1207            try:
1208                return self._parse(parser, raw_tokens, sql)
1209            except ParseError as e:
1210                e.errors[0]["into_expression"] = expression_type
1211                errors.append(e)
1212
1213        raise ParseError(
1214            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1215            errors=merge_errors(errors),
1216        ) 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:
1253    def check_errors(self) -> None:
1254        """Logs or raises any found errors, depending on the chosen error level setting."""
1255        if self.error_level == ErrorLevel.WARN:
1256            for error in self.errors:
1257                logger.error(str(error))
1258        elif self.error_level == ErrorLevel.RAISE and self.errors:
1259            raise ParseError(
1260                concat_messages(self.errors, self.max_errors),
1261                errors=merge_errors(self.errors),
1262            )

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:
1264    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1265        """
1266        Appends an error in the list of recorded errors or raises it, depending on the chosen
1267        error level setting.
1268        """
1269        token = token or self._curr or self._prev or Token.string("")
1270        start = token.start
1271        end = token.end + 1
1272        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1273        highlight = self.sql[start:end]
1274        end_context = self.sql[end : end + self.error_message_context]
1275
1276        error = ParseError.new(
1277            f"{message}. Line {token.line}, Col: {token.col}.\n"
1278            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1279            description=message,
1280            line=token.line,
1281            col=token.col,
1282            start_context=start_context,
1283            highlight=highlight,
1284            end_context=end_context,
1285        )
1286
1287        if self.error_level == ErrorLevel.IMMEDIATE:
1288            raise error
1289
1290        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:
1292    def expression(
1293        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1294    ) -> E:
1295        """
1296        Creates a new, validated Expression.
1297
1298        Args:
1299            exp_class: The expression class to instantiate.
1300            comments: An optional list of comments to attach to the expression.
1301            kwargs: The arguments to set for the expression along with their respective values.
1302
1303        Returns:
1304            The target expression.
1305        """
1306        instance = exp_class(**kwargs)
1307        instance.add_comments(comments) if comments else self._add_comments(instance)
1308        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:
1315    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1316        """
1317        Validates an Expression, making sure that all its mandatory arguments are set.
1318
1319        Args:
1320            expression: The expression to validate.
1321            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1322
1323        Returns:
1324            The validated expression.
1325        """
1326        if self.error_level != ErrorLevel.IGNORE:
1327            for error_message in expression.error_messages(args):
1328                self.raise_error(error_message)
1329
1330        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