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

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]]:
882    def parse_into(
883        self,
884        expression_types: exp.IntoType,
885        raw_tokens: t.List[Token],
886        sql: t.Optional[str] = None,
887    ) -> t.List[t.Optional[exp.Expression]]:
888        """
889        Parses a list of tokens into a given Expression type. If a collection of Expression
890        types is given instead, this method will try to parse the token list into each one
891        of them, stopping at the first for which the parsing succeeds.
892
893        Args:
894            expression_types: The expression type(s) to try and parse the token list into.
895            raw_tokens: The list of tokens.
896            sql: The original SQL string, used to produce helpful debug messages.
897
898        Returns:
899            The target Expression.
900        """
901        errors = []
902        for expression_type in ensure_list(expression_types):
903            parser = self.EXPRESSION_PARSERS.get(expression_type)
904            if not parser:
905                raise TypeError(f"No parser registered for {expression_type}")
906
907            try:
908                return self._parse(parser, raw_tokens, sql)
909            except ParseError as e:
910                e.errors[0]["into_expression"] = expression_type
911                errors.append(e)
912
913        raise ParseError(
914            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
915            errors=merge_errors(errors),
916        ) 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:
953    def check_errors(self) -> None:
954        """Logs or raises any found errors, depending on the chosen error level setting."""
955        if self.error_level == ErrorLevel.WARN:
956            for error in self.errors:
957                logger.error(str(error))
958        elif self.error_level == ErrorLevel.RAISE and self.errors:
959            raise ParseError(
960                concat_messages(self.errors, self.max_errors),
961                errors=merge_errors(self.errors),
962            )

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:
964    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
965        """
966        Appends an error in the list of recorded errors or raises it, depending on the chosen
967        error level setting.
968        """
969        token = token or self._curr or self._prev or Token.string("")
970        start = token.start
971        end = token.end + 1
972        start_context = self.sql[max(start - self.error_message_context, 0) : start]
973        highlight = self.sql[start:end]
974        end_context = self.sql[end : end + self.error_message_context]
975
976        error = ParseError.new(
977            f"{message}. Line {token.line}, Col: {token.col}.\n"
978            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
979            description=message,
980            line=token.line,
981            col=token.col,
982            start_context=start_context,
983            highlight=highlight,
984            end_context=end_context,
985        )
986
987        if self.error_level == ErrorLevel.IMMEDIATE:
988            raise error
989
990        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:
 992    def expression(
 993        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
 994    ) -> E:
 995        """
 996        Creates a new, validated Expression.
 997
 998        Args:
 999            exp_class: The expression class to instantiate.
1000            comments: An optional list of comments to attach to the expression.
1001            kwargs: The arguments to set for the expression along with their respective values.
1002
1003        Returns:
1004            The target expression.
1005        """
1006        instance = exp_class(**kwargs)
1007        instance.add_comments(comments) if comments else self._add_comments(instance)
1008        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:
1015    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1016        """
1017        Validates an Expression, making sure that all its mandatory arguments are set.
1018
1019        Args:
1020            expression: The expression to validate.
1021            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1022
1023        Returns:
1024            The validated expression.
1025        """
1026        if self.error_level != ErrorLevel.IGNORE:
1027            for error_message in expression.error_messages(args):
1028                self.raise_error(error_message)
1029
1030        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