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

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

Arguments:
  • error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
  • error_message_context: Determines the amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
  • max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3
Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None)
974    def __init__(
975        self,
976        error_level: t.Optional[ErrorLevel] = None,
977        error_message_context: int = 100,
978        max_errors: int = 3,
979        dialect: DialectType = None,
980    ):
981        from sqlglot.dialects import Dialect
982
983        self.error_level = error_level or ErrorLevel.IMMEDIATE
984        self.error_message_context = error_message_context
985        self.max_errors = max_errors
986        self.dialect = Dialect.get_or_raise(dialect)
987        self.reset()
FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, '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'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hex'>>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DATE_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDateOfMonth'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function parse_logarithm>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, '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_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'LIKE': <function parse_like>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MAP: 'MAP'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT: 'INT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>}
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.L_PAREN: 'L_PAREN'>, <TokenType.NOT: 'NOT'>, <TokenType.AMP: 'AMP'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.STAR: 'STAR'>, <TokenType.SLASH: 'SLASH'>, <TokenType.COLON: 'COLON'>, <TokenType.GT: 'GT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.COMMA: 'COMMA'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.MOD: 'MOD'>, <TokenType.PLUS: 'PLUS'>, <TokenType.EQ: 'EQ'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.DASH: 'DASH'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PIPE: 'PIPE'>, <TokenType.DOT: 'DOT'>, <TokenType.HASH: 'HASH'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.CARET: 'CARET'>, <TokenType.LT: 'LT'>, <TokenType.R_PAREN: 'R_PAREN'>}
DB_CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>}
CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INDEX: 'INDEX'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
ID_VAR_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
INTERVAL_VARS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
TABLE_ALIAS_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.USMALLINT: 'USMALLINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.USMALLINT: 'USMALLINT'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.GLOB: 'GLOB'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SOME: 'SOME'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INSERT: 'INSERT'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.XOR: 'XOR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT: 'INT'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.USMALLINT: 'USMALLINT'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.INNER: 'INNER'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>}
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.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, '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>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PERIOD', 'UNIQUE', 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', 'LIKE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL REPEATABLE READ', 'READ ONLY', 'ISOLATION LEVEL READ UNCOMMITTED', 'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL READ COMMITTED', 'READ WRITE'}
INSERT_ALTERNATIVES = {'REPLACE', 'FAIL', 'IGNORE', 'ABORT', 'ROLLBACK'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'STREAM', 'STATEMENT', 'TIMESTAMP', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'NULLS'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
FETCH_TOKENS = {<TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
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.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.VAR: 'VAR'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.CASE: 'CASE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TEXT: 'TEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.UUID: 'UUID'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT128: 'INT128'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NULL: 'NULL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROW: 'ROW'>, <TokenType.BIT: 'BIT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.ASC: 'ASC'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.XML: 'XML'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.JSON: 'JSON'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UINT: 'UINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USE: 'USE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESC: 'DESC'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MAP: 'MAP'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DIV: 'DIV'>, <TokenType.IS: 'IS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.END: 'END'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TOP: 'TOP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
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
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'limit', 'order', 'offset'}
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):
989    def reset(self):
990        self.sql = ""
991        self.errors = []
992        self._tokens = []
993        self._index = 0
994        self._curr = None
995        self._next = None
996        self._prev = None
997        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
 999    def parse(
1000        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1001    ) -> t.List[t.Optional[exp.Expression]]:
1002        """
1003        Parses a list of tokens and returns a list of syntax trees, one tree
1004        per parsed SQL statement.
1005
1006        Args:
1007            raw_tokens: The list of tokens.
1008            sql: The original SQL string, used to produce helpful debug messages.
1009
1010        Returns:
1011            The list of the produced syntax trees.
1012        """
1013        return self._parse(
1014            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1015        )

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]]:
1017    def parse_into(
1018        self,
1019        expression_types: exp.IntoType,
1020        raw_tokens: t.List[Token],
1021        sql: t.Optional[str] = None,
1022    ) -> t.List[t.Optional[exp.Expression]]:
1023        """
1024        Parses a list of tokens into a given Expression type. If a collection of Expression
1025        types is given instead, this method will try to parse the token list into each one
1026        of them, stopping at the first for which the parsing succeeds.
1027
1028        Args:
1029            expression_types: The expression type(s) to try and parse the token list into.
1030            raw_tokens: The list of tokens.
1031            sql: The original SQL string, used to produce helpful debug messages.
1032
1033        Returns:
1034            The target Expression.
1035        """
1036        errors = []
1037        for expression_type in ensure_list(expression_types):
1038            parser = self.EXPRESSION_PARSERS.get(expression_type)
1039            if not parser:
1040                raise TypeError(f"No parser registered for {expression_type}")
1041
1042            try:
1043                return self._parse(parser, raw_tokens, sql)
1044            except ParseError as e:
1045                e.errors[0]["into_expression"] = expression_type
1046                errors.append(e)
1047
1048        raise ParseError(
1049            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1050            errors=merge_errors(errors),
1051        ) 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:
1088    def check_errors(self) -> None:
1089        """Logs or raises any found errors, depending on the chosen error level setting."""
1090        if self.error_level == ErrorLevel.WARN:
1091            for error in self.errors:
1092                logger.error(str(error))
1093        elif self.error_level == ErrorLevel.RAISE and self.errors:
1094            raise ParseError(
1095                concat_messages(self.errors, self.max_errors),
1096                errors=merge_errors(self.errors),
1097            )

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:
1099    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1100        """
1101        Appends an error in the list of recorded errors or raises it, depending on the chosen
1102        error level setting.
1103        """
1104        token = token or self._curr or self._prev or Token.string("")
1105        start = token.start
1106        end = token.end + 1
1107        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1108        highlight = self.sql[start:end]
1109        end_context = self.sql[end : end + self.error_message_context]
1110
1111        error = ParseError.new(
1112            f"{message}. Line {token.line}, Col: {token.col}.\n"
1113            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1114            description=message,
1115            line=token.line,
1116            col=token.col,
1117            start_context=start_context,
1118            highlight=highlight,
1119            end_context=end_context,
1120        )
1121
1122        if self.error_level == ErrorLevel.IMMEDIATE:
1123            raise error
1124
1125        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:
1127    def expression(
1128        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1129    ) -> E:
1130        """
1131        Creates a new, validated Expression.
1132
1133        Args:
1134            exp_class: The expression class to instantiate.
1135            comments: An optional list of comments to attach to the expression.
1136            kwargs: The arguments to set for the expression along with their respective values.
1137
1138        Returns:
1139            The target expression.
1140        """
1141        instance = exp_class(**kwargs)
1142        instance.add_comments(comments) if comments else self._add_comments(instance)
1143        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:
1150    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1151        """
1152        Validates an Expression, making sure that all its mandatory arguments are set.
1153
1154        Args:
1155            expression: The expression to validate.
1156            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1157
1158        Returns:
1159            The validated expression.
1160        """
1161        if self.error_level != ErrorLevel.IGNORE:
1162            for error_message in expression.error_messages(args):
1163                self.raise_error(error_message)
1164
1165        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