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

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]]:
871    def parse_into(
872        self,
873        expression_types: exp.IntoType,
874        raw_tokens: t.List[Token],
875        sql: t.Optional[str] = None,
876    ) -> t.List[t.Optional[exp.Expression]]:
877        """
878        Parses a list of tokens into a given Expression type. If a collection of Expression
879        types is given instead, this method will try to parse the token list into each one
880        of them, stopping at the first for which the parsing succeeds.
881
882        Args:
883            expression_types: The expression type(s) to try and parse the token list into.
884            raw_tokens: The list of tokens.
885            sql: The original SQL string, used to produce helpful debug messages.
886
887        Returns:
888            The target Expression.
889        """
890        errors = []
891        for expression_type in ensure_list(expression_types):
892            parser = self.EXPRESSION_PARSERS.get(expression_type)
893            if not parser:
894                raise TypeError(f"No parser registered for {expression_type}")
895
896            try:
897                return self._parse(parser, raw_tokens, sql)
898            except ParseError as e:
899                e.errors[0]["into_expression"] = expression_type
900                errors.append(e)
901
902        raise ParseError(
903            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
904            errors=merge_errors(errors),
905        ) 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:
942    def check_errors(self) -> None:
943        """Logs or raises any found errors, depending on the chosen error level setting."""
944        if self.error_level == ErrorLevel.WARN:
945            for error in self.errors:
946                logger.error(str(error))
947        elif self.error_level == ErrorLevel.RAISE and self.errors:
948            raise ParseError(
949                concat_messages(self.errors, self.max_errors),
950                errors=merge_errors(self.errors),
951            )

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