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

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]]:
929    def parse_into(
930        self,
931        expression_types: exp.IntoType,
932        raw_tokens: t.List[Token],
933        sql: t.Optional[str] = None,
934    ) -> t.List[t.Optional[exp.Expression]]:
935        """
936        Parses a list of tokens into a given Expression type. If a collection of Expression
937        types is given instead, this method will try to parse the token list into each one
938        of them, stopping at the first for which the parsing succeeds.
939
940        Args:
941            expression_types: The expression type(s) to try and parse the token list into.
942            raw_tokens: The list of tokens.
943            sql: The original SQL string, used to produce helpful debug messages.
944
945        Returns:
946            The target Expression.
947        """
948        errors = []
949        for expression_type in ensure_list(expression_types):
950            parser = self.EXPRESSION_PARSERS.get(expression_type)
951            if not parser:
952                raise TypeError(f"No parser registered for {expression_type}")
953
954            try:
955                return self._parse(parser, raw_tokens, sql)
956            except ParseError as e:
957                e.errors[0]["into_expression"] = expression_type
958                errors.append(e)
959
960        raise ParseError(
961            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
962            errors=merge_errors(errors),
963        ) 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:
1000    def check_errors(self) -> None:
1001        """Logs or raises any found errors, depending on the chosen error level setting."""
1002        if self.error_level == ErrorLevel.WARN:
1003            for error in self.errors:
1004                logger.error(str(error))
1005        elif self.error_level == ErrorLevel.RAISE and self.errors:
1006            raise ParseError(
1007                concat_messages(self.errors, self.max_errors),
1008                errors=merge_errors(self.errors),
1009            )

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:
1011    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1012        """
1013        Appends an error in the list of recorded errors or raises it, depending on the chosen
1014        error level setting.
1015        """
1016        token = token or self._curr or self._prev or Token.string("")
1017        start = token.start
1018        end = token.end + 1
1019        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1020        highlight = self.sql[start:end]
1021        end_context = self.sql[end : end + self.error_message_context]
1022
1023        error = ParseError.new(
1024            f"{message}. Line {token.line}, Col: {token.col}.\n"
1025            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1026            description=message,
1027            line=token.line,
1028            col=token.col,
1029            start_context=start_context,
1030            highlight=highlight,
1031            end_context=end_context,
1032        )
1033
1034        if self.error_level == ErrorLevel.IMMEDIATE:
1035            raise error
1036
1037        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:
1039    def expression(
1040        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1041    ) -> E:
1042        """
1043        Creates a new, validated Expression.
1044
1045        Args:
1046            exp_class: The expression class to instantiate.
1047            comments: An optional list of comments to attach to the expression.
1048            kwargs: The arguments to set for the expression along with their respective values.
1049
1050        Returns:
1051            The target expression.
1052        """
1053        instance = exp_class(**kwargs)
1054        instance.add_comments(comments) if comments else self._add_comments(instance)
1055        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:
1062    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1063        """
1064        Validates an Expression, making sure that all its mandatory arguments are set.
1065
1066        Args:
1067            expression: The expression to validate.
1068            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1069
1070        Returns:
1071            The validated expression.
1072        """
1073        if self.error_level != ErrorLevel.IGNORE:
1074            for error_message in expression.error_messages(args):
1075                self.raise_error(error_message)
1076
1077        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