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

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

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