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, Lit
  16    from sqlglot.dialects.dialect import Dialect, DialectType
  17
  18    T = t.TypeVar("T")
  19
  20logger = logging.getLogger("sqlglot")
  21
  22OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
  23
  24
  25def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  26    if len(args) == 1 and args[0].is_star:
  27        return exp.StarMap(this=args[0])
  28
  29    keys = []
  30    values = []
  31    for i in range(0, len(args), 2):
  32        keys.append(args[i])
  33        values.append(args[i + 1])
  34
  35    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
  36
  37
  38def build_like(args: t.List) -> exp.Escape | exp.Like:
  39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  41
  42
  43def binary_range_parser(
  44    expr_type: t.Type[exp.Expression], reverse_args: bool = False
  45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  46    def _parse_binary_range(
  47        self: Parser, this: t.Optional[exp.Expression]
  48    ) -> t.Optional[exp.Expression]:
  49        expression = self._parse_bitwise()
  50        if reverse_args:
  51            this, expression = expression, this
  52        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
  53
  54    return _parse_binary_range
  55
  56
  57def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  58    # Default argument order is base, expression
  59    this = seq_get(args, 0)
  60    expression = seq_get(args, 1)
  61
  62    if expression:
  63        if not dialect.LOG_BASE_FIRST:
  64            this, expression = expression, this
  65        return exp.Log(this=this, expression=expression)
  66
  67    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  68
  69
  70def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
  71    arg = seq_get(args, 0)
  72    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
  73
  74
  75def build_lower(args: t.List) -> exp.Lower | exp.Hex:
  76    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
  77    arg = seq_get(args, 0)
  78    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
  79
  80
  81def build_upper(args: t.List) -> exp.Upper | exp.Hex:
  82    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
  83    arg = seq_get(args, 0)
  84    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
  85
  86
  87def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
  88    def _builder(args: t.List, dialect: Dialect) -> E:
  89        expression = expr_type(
  90            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
  91        )
  92        if len(args) > 2 and expr_type is exp.JSONExtract:
  93            expression.set("expressions", args[2:])
  94
  95        return expression
  96
  97    return _builder
  98
  99
 100def build_mod(args: t.List) -> exp.Mod:
 101    this = seq_get(args, 0)
 102    expression = seq_get(args, 1)
 103
 104    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
 105    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
 106    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
 107
 108    return exp.Mod(this=this, expression=expression)
 109
 110
 111class _Parser(type):
 112    def __new__(cls, clsname, bases, attrs):
 113        klass = super().__new__(cls, clsname, bases, attrs)
 114
 115        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
 116        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
 117
 118        return klass
 119
 120
 121class Parser(metaclass=_Parser):
 122    """
 123    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 124
 125    Args:
 126        error_level: The desired error level.
 127            Default: ErrorLevel.IMMEDIATE
 128        error_message_context: The amount of context to capture from a query string when displaying
 129            the error message (in number of characters).
 130            Default: 100
 131        max_errors: Maximum number of error messages to include in a raised ParseError.
 132            This is only relevant if error_level is ErrorLevel.RAISE.
 133            Default: 3
 134    """
 135
 136    FUNCTIONS: t.Dict[str, t.Callable] = {
 137        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 138        "CONCAT": lambda args, dialect: exp.Concat(
 139            expressions=args,
 140            safe=not dialect.STRICT_STRING_CONCAT,
 141            coalesce=dialect.CONCAT_COALESCE,
 142        ),
 143        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 144            expressions=args,
 145            safe=not dialect.STRICT_STRING_CONCAT,
 146            coalesce=dialect.CONCAT_COALESCE,
 147        ),
 148        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 149            this=seq_get(args, 0),
 150            to=exp.DataType(this=exp.DataType.Type.TEXT),
 151        ),
 152        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 153        "HEX": build_hex,
 154        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 155        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 156        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 157        "LIKE": build_like,
 158        "LOG": build_logarithm,
 159        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 160        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 161        "LOWER": build_lower,
 162        "MOD": build_mod,
 163        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 164            this=seq_get(args, 0),
 165            to=exp.DataType(this=exp.DataType.Type.TEXT),
 166        ),
 167        "TO_HEX": build_hex,
 168        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 169            this=exp.Cast(
 170                this=seq_get(args, 0),
 171                to=exp.DataType(this=exp.DataType.Type.TEXT),
 172            ),
 173            start=exp.Literal.number(1),
 174            length=exp.Literal.number(10),
 175        ),
 176        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 177        "UPPER": build_upper,
 178        "VAR_MAP": build_var_map,
 179    }
 180
 181    NO_PAREN_FUNCTIONS = {
 182        TokenType.CURRENT_DATE: exp.CurrentDate,
 183        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 184        TokenType.CURRENT_TIME: exp.CurrentTime,
 185        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 186        TokenType.CURRENT_USER: exp.CurrentUser,
 187    }
 188
 189    STRUCT_TYPE_TOKENS = {
 190        TokenType.NESTED,
 191        TokenType.OBJECT,
 192        TokenType.STRUCT,
 193    }
 194
 195    NESTED_TYPE_TOKENS = {
 196        TokenType.ARRAY,
 197        TokenType.LIST,
 198        TokenType.LOWCARDINALITY,
 199        TokenType.MAP,
 200        TokenType.NULLABLE,
 201        *STRUCT_TYPE_TOKENS,
 202    }
 203
 204    ENUM_TYPE_TOKENS = {
 205        TokenType.ENUM,
 206        TokenType.ENUM8,
 207        TokenType.ENUM16,
 208    }
 209
 210    AGGREGATE_TYPE_TOKENS = {
 211        TokenType.AGGREGATEFUNCTION,
 212        TokenType.SIMPLEAGGREGATEFUNCTION,
 213    }
 214
 215    TYPE_TOKENS = {
 216        TokenType.BIT,
 217        TokenType.BOOLEAN,
 218        TokenType.TINYINT,
 219        TokenType.UTINYINT,
 220        TokenType.SMALLINT,
 221        TokenType.USMALLINT,
 222        TokenType.INT,
 223        TokenType.UINT,
 224        TokenType.BIGINT,
 225        TokenType.UBIGINT,
 226        TokenType.INT128,
 227        TokenType.UINT128,
 228        TokenType.INT256,
 229        TokenType.UINT256,
 230        TokenType.MEDIUMINT,
 231        TokenType.UMEDIUMINT,
 232        TokenType.FIXEDSTRING,
 233        TokenType.FLOAT,
 234        TokenType.DOUBLE,
 235        TokenType.CHAR,
 236        TokenType.NCHAR,
 237        TokenType.VARCHAR,
 238        TokenType.NVARCHAR,
 239        TokenType.BPCHAR,
 240        TokenType.TEXT,
 241        TokenType.MEDIUMTEXT,
 242        TokenType.LONGTEXT,
 243        TokenType.MEDIUMBLOB,
 244        TokenType.LONGBLOB,
 245        TokenType.BINARY,
 246        TokenType.VARBINARY,
 247        TokenType.JSON,
 248        TokenType.JSONB,
 249        TokenType.INTERVAL,
 250        TokenType.TINYBLOB,
 251        TokenType.TINYTEXT,
 252        TokenType.TIME,
 253        TokenType.TIMETZ,
 254        TokenType.TIMESTAMP,
 255        TokenType.TIMESTAMP_S,
 256        TokenType.TIMESTAMP_MS,
 257        TokenType.TIMESTAMP_NS,
 258        TokenType.TIMESTAMPTZ,
 259        TokenType.TIMESTAMPLTZ,
 260        TokenType.TIMESTAMPNTZ,
 261        TokenType.DATETIME,
 262        TokenType.DATETIME64,
 263        TokenType.DATE,
 264        TokenType.DATE32,
 265        TokenType.INT4RANGE,
 266        TokenType.INT4MULTIRANGE,
 267        TokenType.INT8RANGE,
 268        TokenType.INT8MULTIRANGE,
 269        TokenType.NUMRANGE,
 270        TokenType.NUMMULTIRANGE,
 271        TokenType.TSRANGE,
 272        TokenType.TSMULTIRANGE,
 273        TokenType.TSTZRANGE,
 274        TokenType.TSTZMULTIRANGE,
 275        TokenType.DATERANGE,
 276        TokenType.DATEMULTIRANGE,
 277        TokenType.DECIMAL,
 278        TokenType.UDECIMAL,
 279        TokenType.BIGDECIMAL,
 280        TokenType.UUID,
 281        TokenType.GEOGRAPHY,
 282        TokenType.GEOMETRY,
 283        TokenType.HLLSKETCH,
 284        TokenType.HSTORE,
 285        TokenType.PSEUDO_TYPE,
 286        TokenType.SUPER,
 287        TokenType.SERIAL,
 288        TokenType.SMALLSERIAL,
 289        TokenType.BIGSERIAL,
 290        TokenType.XML,
 291        TokenType.YEAR,
 292        TokenType.UNIQUEIDENTIFIER,
 293        TokenType.USERDEFINED,
 294        TokenType.MONEY,
 295        TokenType.SMALLMONEY,
 296        TokenType.ROWVERSION,
 297        TokenType.IMAGE,
 298        TokenType.VARIANT,
 299        TokenType.OBJECT,
 300        TokenType.OBJECT_IDENTIFIER,
 301        TokenType.INET,
 302        TokenType.IPADDRESS,
 303        TokenType.IPPREFIX,
 304        TokenType.IPV4,
 305        TokenType.IPV6,
 306        TokenType.UNKNOWN,
 307        TokenType.NULL,
 308        TokenType.NAME,
 309        TokenType.TDIGEST,
 310        *ENUM_TYPE_TOKENS,
 311        *NESTED_TYPE_TOKENS,
 312        *AGGREGATE_TYPE_TOKENS,
 313    }
 314
 315    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 316        TokenType.BIGINT: TokenType.UBIGINT,
 317        TokenType.INT: TokenType.UINT,
 318        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 319        TokenType.SMALLINT: TokenType.USMALLINT,
 320        TokenType.TINYINT: TokenType.UTINYINT,
 321        TokenType.DECIMAL: TokenType.UDECIMAL,
 322    }
 323
 324    SUBQUERY_PREDICATES = {
 325        TokenType.ANY: exp.Any,
 326        TokenType.ALL: exp.All,
 327        TokenType.EXISTS: exp.Exists,
 328        TokenType.SOME: exp.Any,
 329    }
 330
 331    RESERVED_TOKENS = {
 332        *Tokenizer.SINGLE_TOKENS.values(),
 333        TokenType.SELECT,
 334    } - {TokenType.IDENTIFIER}
 335
 336    DB_CREATABLES = {
 337        TokenType.DATABASE,
 338        TokenType.DICTIONARY,
 339        TokenType.MODEL,
 340        TokenType.SCHEMA,
 341        TokenType.SEQUENCE,
 342        TokenType.STORAGE_INTEGRATION,
 343        TokenType.TABLE,
 344        TokenType.TAG,
 345        TokenType.VIEW,
 346        TokenType.WAREHOUSE,
 347        TokenType.STREAMLIT,
 348    }
 349
 350    CREATABLES = {
 351        TokenType.COLUMN,
 352        TokenType.CONSTRAINT,
 353        TokenType.FOREIGN_KEY,
 354        TokenType.FUNCTION,
 355        TokenType.INDEX,
 356        TokenType.PROCEDURE,
 357        *DB_CREATABLES,
 358    }
 359
 360    # Tokens that can represent identifiers
 361    ID_VAR_TOKENS = {
 362        TokenType.VAR,
 363        TokenType.ANTI,
 364        TokenType.APPLY,
 365        TokenType.ASC,
 366        TokenType.ASOF,
 367        TokenType.AUTO_INCREMENT,
 368        TokenType.BEGIN,
 369        TokenType.BPCHAR,
 370        TokenType.CACHE,
 371        TokenType.CASE,
 372        TokenType.COLLATE,
 373        TokenType.COMMAND,
 374        TokenType.COMMENT,
 375        TokenType.COMMIT,
 376        TokenType.CONSTRAINT,
 377        TokenType.COPY,
 378        TokenType.DEFAULT,
 379        TokenType.DELETE,
 380        TokenType.DESC,
 381        TokenType.DESCRIBE,
 382        TokenType.DICTIONARY,
 383        TokenType.DIV,
 384        TokenType.END,
 385        TokenType.EXECUTE,
 386        TokenType.ESCAPE,
 387        TokenType.FALSE,
 388        TokenType.FIRST,
 389        TokenType.FILTER,
 390        TokenType.FINAL,
 391        TokenType.FORMAT,
 392        TokenType.FULL,
 393        TokenType.IDENTIFIER,
 394        TokenType.IS,
 395        TokenType.ISNULL,
 396        TokenType.INTERVAL,
 397        TokenType.KEEP,
 398        TokenType.KILL,
 399        TokenType.LEFT,
 400        TokenType.LOAD,
 401        TokenType.MERGE,
 402        TokenType.NATURAL,
 403        TokenType.NEXT,
 404        TokenType.OFFSET,
 405        TokenType.OPERATOR,
 406        TokenType.ORDINALITY,
 407        TokenType.OVERLAPS,
 408        TokenType.OVERWRITE,
 409        TokenType.PARTITION,
 410        TokenType.PERCENT,
 411        TokenType.PIVOT,
 412        TokenType.PRAGMA,
 413        TokenType.RANGE,
 414        TokenType.RECURSIVE,
 415        TokenType.REFERENCES,
 416        TokenType.REFRESH,
 417        TokenType.REPLACE,
 418        TokenType.RIGHT,
 419        TokenType.ROLLUP,
 420        TokenType.ROW,
 421        TokenType.ROWS,
 422        TokenType.SEMI,
 423        TokenType.SET,
 424        TokenType.SETTINGS,
 425        TokenType.SHOW,
 426        TokenType.TEMPORARY,
 427        TokenType.TOP,
 428        TokenType.TRUE,
 429        TokenType.TRUNCATE,
 430        TokenType.UNIQUE,
 431        TokenType.UNNEST,
 432        TokenType.UNPIVOT,
 433        TokenType.UPDATE,
 434        TokenType.USE,
 435        TokenType.VOLATILE,
 436        TokenType.WINDOW,
 437        *CREATABLES,
 438        *SUBQUERY_PREDICATES,
 439        *TYPE_TOKENS,
 440        *NO_PAREN_FUNCTIONS,
 441    }
 442
 443    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 444
 445    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 446        TokenType.ANTI,
 447        TokenType.APPLY,
 448        TokenType.ASOF,
 449        TokenType.FULL,
 450        TokenType.LEFT,
 451        TokenType.LOCK,
 452        TokenType.NATURAL,
 453        TokenType.OFFSET,
 454        TokenType.RIGHT,
 455        TokenType.SEMI,
 456        TokenType.WINDOW,
 457    }
 458
 459    ALIAS_TOKENS = ID_VAR_TOKENS
 460
 461    ARRAY_CONSTRUCTORS = {
 462        "ARRAY": exp.Array,
 463        "LIST": exp.List,
 464    }
 465
 466    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 467
 468    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 469
 470    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 471
 472    FUNC_TOKENS = {
 473        TokenType.COLLATE,
 474        TokenType.COMMAND,
 475        TokenType.CURRENT_DATE,
 476        TokenType.CURRENT_DATETIME,
 477        TokenType.CURRENT_TIMESTAMP,
 478        TokenType.CURRENT_TIME,
 479        TokenType.CURRENT_USER,
 480        TokenType.FILTER,
 481        TokenType.FIRST,
 482        TokenType.FORMAT,
 483        TokenType.GLOB,
 484        TokenType.IDENTIFIER,
 485        TokenType.INDEX,
 486        TokenType.ISNULL,
 487        TokenType.ILIKE,
 488        TokenType.INSERT,
 489        TokenType.LIKE,
 490        TokenType.MERGE,
 491        TokenType.OFFSET,
 492        TokenType.PRIMARY_KEY,
 493        TokenType.RANGE,
 494        TokenType.REPLACE,
 495        TokenType.RLIKE,
 496        TokenType.ROW,
 497        TokenType.UNNEST,
 498        TokenType.VAR,
 499        TokenType.LEFT,
 500        TokenType.RIGHT,
 501        TokenType.SEQUENCE,
 502        TokenType.DATE,
 503        TokenType.DATETIME,
 504        TokenType.TABLE,
 505        TokenType.TIMESTAMP,
 506        TokenType.TIMESTAMPTZ,
 507        TokenType.TRUNCATE,
 508        TokenType.WINDOW,
 509        TokenType.XOR,
 510        *TYPE_TOKENS,
 511        *SUBQUERY_PREDICATES,
 512    }
 513
 514    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 515        TokenType.AND: exp.And,
 516    }
 517
 518    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 519        TokenType.COLON_EQ: exp.PropertyEQ,
 520    }
 521
 522    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 523        TokenType.OR: exp.Or,
 524    }
 525
 526    EQUALITY = {
 527        TokenType.EQ: exp.EQ,
 528        TokenType.NEQ: exp.NEQ,
 529        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 530    }
 531
 532    COMPARISON = {
 533        TokenType.GT: exp.GT,
 534        TokenType.GTE: exp.GTE,
 535        TokenType.LT: exp.LT,
 536        TokenType.LTE: exp.LTE,
 537    }
 538
 539    BITWISE = {
 540        TokenType.AMP: exp.BitwiseAnd,
 541        TokenType.CARET: exp.BitwiseXor,
 542        TokenType.PIPE: exp.BitwiseOr,
 543    }
 544
 545    TERM = {
 546        TokenType.DASH: exp.Sub,
 547        TokenType.PLUS: exp.Add,
 548        TokenType.MOD: exp.Mod,
 549        TokenType.COLLATE: exp.Collate,
 550    }
 551
 552    FACTOR = {
 553        TokenType.DIV: exp.IntDiv,
 554        TokenType.LR_ARROW: exp.Distance,
 555        TokenType.SLASH: exp.Div,
 556        TokenType.STAR: exp.Mul,
 557    }
 558
 559    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 560
 561    TIMES = {
 562        TokenType.TIME,
 563        TokenType.TIMETZ,
 564    }
 565
 566    TIMESTAMPS = {
 567        TokenType.TIMESTAMP,
 568        TokenType.TIMESTAMPTZ,
 569        TokenType.TIMESTAMPLTZ,
 570        *TIMES,
 571    }
 572
 573    SET_OPERATIONS = {
 574        TokenType.UNION,
 575        TokenType.INTERSECT,
 576        TokenType.EXCEPT,
 577    }
 578
 579    JOIN_METHODS = {
 580        TokenType.ASOF,
 581        TokenType.NATURAL,
 582        TokenType.POSITIONAL,
 583    }
 584
 585    JOIN_SIDES = {
 586        TokenType.LEFT,
 587        TokenType.RIGHT,
 588        TokenType.FULL,
 589    }
 590
 591    JOIN_KINDS = {
 592        TokenType.ANTI,
 593        TokenType.CROSS,
 594        TokenType.INNER,
 595        TokenType.OUTER,
 596        TokenType.SEMI,
 597        TokenType.STRAIGHT_JOIN,
 598    }
 599
 600    JOIN_HINTS: t.Set[str] = set()
 601
 602    LAMBDAS = {
 603        TokenType.ARROW: lambda self, expressions: self.expression(
 604            exp.Lambda,
 605            this=self._replace_lambda(
 606                self._parse_assignment(),
 607                expressions,
 608            ),
 609            expressions=expressions,
 610        ),
 611        TokenType.FARROW: lambda self, expressions: self.expression(
 612            exp.Kwarg,
 613            this=exp.var(expressions[0].name),
 614            expression=self._parse_assignment(),
 615        ),
 616    }
 617
 618    COLUMN_OPERATORS = {
 619        TokenType.DOT: None,
 620        TokenType.DCOLON: lambda self, this, to: self.expression(
 621            exp.Cast if self.STRICT_CAST else exp.TryCast,
 622            this=this,
 623            to=to,
 624        ),
 625        TokenType.ARROW: lambda self, this, path: self.expression(
 626            exp.JSONExtract,
 627            this=this,
 628            expression=self.dialect.to_json_path(path),
 629            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 630        ),
 631        TokenType.DARROW: lambda self, this, path: self.expression(
 632            exp.JSONExtractScalar,
 633            this=this,
 634            expression=self.dialect.to_json_path(path),
 635            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 636        ),
 637        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 638            exp.JSONBExtract,
 639            this=this,
 640            expression=path,
 641        ),
 642        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 643            exp.JSONBExtractScalar,
 644            this=this,
 645            expression=path,
 646        ),
 647        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 648            exp.JSONBContains,
 649            this=this,
 650            expression=key,
 651        ),
 652    }
 653
 654    EXPRESSION_PARSERS = {
 655        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 656        exp.Column: lambda self: self._parse_column(),
 657        exp.Condition: lambda self: self._parse_assignment(),
 658        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 659        exp.Expression: lambda self: self._parse_expression(),
 660        exp.From: lambda self: self._parse_from(joins=True),
 661        exp.Group: lambda self: self._parse_group(),
 662        exp.Having: lambda self: self._parse_having(),
 663        exp.Identifier: lambda self: self._parse_id_var(),
 664        exp.Join: lambda self: self._parse_join(),
 665        exp.Lambda: lambda self: self._parse_lambda(),
 666        exp.Lateral: lambda self: self._parse_lateral(),
 667        exp.Limit: lambda self: self._parse_limit(),
 668        exp.Offset: lambda self: self._parse_offset(),
 669        exp.Order: lambda self: self._parse_order(),
 670        exp.Ordered: lambda self: self._parse_ordered(),
 671        exp.Properties: lambda self: self._parse_properties(),
 672        exp.Qualify: lambda self: self._parse_qualify(),
 673        exp.Returning: lambda self: self._parse_returning(),
 674        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 675        exp.Table: lambda self: self._parse_table_parts(),
 676        exp.TableAlias: lambda self: self._parse_table_alias(),
 677        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 678        exp.Where: lambda self: self._parse_where(),
 679        exp.Window: lambda self: self._parse_named_window(),
 680        exp.With: lambda self: self._parse_with(),
 681        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 682    }
 683
 684    STATEMENT_PARSERS = {
 685        TokenType.ALTER: lambda self: self._parse_alter(),
 686        TokenType.BEGIN: lambda self: self._parse_transaction(),
 687        TokenType.CACHE: lambda self: self._parse_cache(),
 688        TokenType.COMMENT: lambda self: self._parse_comment(),
 689        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 690        TokenType.COPY: lambda self: self._parse_copy(),
 691        TokenType.CREATE: lambda self: self._parse_create(),
 692        TokenType.DELETE: lambda self: self._parse_delete(),
 693        TokenType.DESC: lambda self: self._parse_describe(),
 694        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 695        TokenType.DROP: lambda self: self._parse_drop(),
 696        TokenType.INSERT: lambda self: self._parse_insert(),
 697        TokenType.KILL: lambda self: self._parse_kill(),
 698        TokenType.LOAD: lambda self: self._parse_load(),
 699        TokenType.MERGE: lambda self: self._parse_merge(),
 700        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 701        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 702        TokenType.REFRESH: lambda self: self._parse_refresh(),
 703        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 704        TokenType.SET: lambda self: self._parse_set(),
 705        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 706        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 707        TokenType.UPDATE: lambda self: self._parse_update(),
 708        TokenType.USE: lambda self: self.expression(
 709            exp.Use,
 710            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 711            this=self._parse_table(schema=False),
 712        ),
 713        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 714    }
 715
 716    UNARY_PARSERS = {
 717        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 718        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 719        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 720        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 721        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 722        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 723    }
 724
 725    STRING_PARSERS = {
 726        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 727            exp.RawString, this=token.text
 728        ),
 729        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 730            exp.National, this=token.text
 731        ),
 732        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 733        TokenType.STRING: lambda self, token: self.expression(
 734            exp.Literal, this=token.text, is_string=True
 735        ),
 736        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 737            exp.UnicodeString,
 738            this=token.text,
 739            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 740        ),
 741    }
 742
 743    NUMERIC_PARSERS = {
 744        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 745        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 746        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 747        TokenType.NUMBER: lambda self, token: self.expression(
 748            exp.Literal, this=token.text, is_string=False
 749        ),
 750    }
 751
 752    PRIMARY_PARSERS = {
 753        **STRING_PARSERS,
 754        **NUMERIC_PARSERS,
 755        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 756        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 757        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 758        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 759        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 760        TokenType.STAR: lambda self, _: self.expression(
 761            exp.Star,
 762            **{
 763                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
 764                "replace": self._parse_star_op("REPLACE"),
 765                "rename": self._parse_star_op("RENAME"),
 766            },
 767        ),
 768    }
 769
 770    PLACEHOLDER_PARSERS = {
 771        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 772        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 773        TokenType.COLON: lambda self: (
 774            self.expression(exp.Placeholder, this=self._prev.text)
 775            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 776            else None
 777        ),
 778    }
 779
 780    RANGE_PARSERS = {
 781        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 782        TokenType.GLOB: binary_range_parser(exp.Glob),
 783        TokenType.ILIKE: binary_range_parser(exp.ILike),
 784        TokenType.IN: lambda self, this: self._parse_in(this),
 785        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 786        TokenType.IS: lambda self, this: self._parse_is(this),
 787        TokenType.LIKE: binary_range_parser(exp.Like),
 788        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 789        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 790        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 791        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 792    }
 793
 794    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 795        "ALLOWED_VALUES": lambda self: self.expression(
 796            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 797        ),
 798        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 799        "AUTO": lambda self: self._parse_auto_property(),
 800        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 801        "BACKUP": lambda self: self.expression(
 802            exp.BackupProperty, this=self._parse_var(any_token=True)
 803        ),
 804        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 805        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 806        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 807        "CHECKSUM": lambda self: self._parse_checksum(),
 808        "CLUSTER BY": lambda self: self._parse_cluster(),
 809        "CLUSTERED": lambda self: self._parse_clustered_by(),
 810        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 811            exp.CollateProperty, **kwargs
 812        ),
 813        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 814        "CONTAINS": lambda self: self._parse_contains_property(),
 815        "COPY": lambda self: self._parse_copy_property(),
 816        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 817        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 818        "DEFINER": lambda self: self._parse_definer(),
 819        "DETERMINISTIC": lambda self: self.expression(
 820            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 821        ),
 822        "DISTKEY": lambda self: self._parse_distkey(),
 823        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 824        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 825        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 826        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 827        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 828        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 829        "FREESPACE": lambda self: self._parse_freespace(),
 830        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 831        "HEAP": lambda self: self.expression(exp.HeapProperty),
 832        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 833        "IMMUTABLE": lambda self: self.expression(
 834            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 835        ),
 836        "INHERITS": lambda self: self.expression(
 837            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 838        ),
 839        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 840        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 841        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 842        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 843        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 844        "LIKE": lambda self: self._parse_create_like(),
 845        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 846        "LOCK": lambda self: self._parse_locking(),
 847        "LOCKING": lambda self: self._parse_locking(),
 848        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 849        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 850        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 851        "MODIFIES": lambda self: self._parse_modifies_property(),
 852        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 853        "NO": lambda self: self._parse_no_property(),
 854        "ON": lambda self: self._parse_on_property(),
 855        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 856        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 857        "PARTITION": lambda self: self._parse_partitioned_of(),
 858        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 859        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 860        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 861        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 862        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 863        "READS": lambda self: self._parse_reads_property(),
 864        "REMOTE": lambda self: self._parse_remote_with_connection(),
 865        "RETURNS": lambda self: self._parse_returns(),
 866        "STRICT": lambda self: self.expression(exp.StrictProperty),
 867        "ROW": lambda self: self._parse_row(),
 868        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 869        "SAMPLE": lambda self: self.expression(
 870            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 871        ),
 872        "SECURE": lambda self: self.expression(exp.SecureProperty),
 873        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 874        "SETTINGS": lambda self: self.expression(
 875            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 876        ),
 877        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 878        "SORTKEY": lambda self: self._parse_sortkey(),
 879        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 880        "STABLE": lambda self: self.expression(
 881            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 882        ),
 883        "STORED": lambda self: self._parse_stored(),
 884        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 885        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 886        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 887        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 888        "TO": lambda self: self._parse_to_table(),
 889        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 890        "TRANSFORM": lambda self: self.expression(
 891            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 892        ),
 893        "TTL": lambda self: self._parse_ttl(),
 894        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 895        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 896        "VOLATILE": lambda self: self._parse_volatile_property(),
 897        "WITH": lambda self: self._parse_with_property(),
 898    }
 899
 900    CONSTRAINT_PARSERS = {
 901        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 902        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 903        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 904        "CHARACTER SET": lambda self: self.expression(
 905            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 906        ),
 907        "CHECK": lambda self: self.expression(
 908            exp.CheckColumnConstraint,
 909            this=self._parse_wrapped(self._parse_assignment),
 910            enforced=self._match_text_seq("ENFORCED"),
 911        ),
 912        "COLLATE": lambda self: self.expression(
 913            exp.CollateColumnConstraint, this=self._parse_var(any_token=True)
 914        ),
 915        "COMMENT": lambda self: self.expression(
 916            exp.CommentColumnConstraint, this=self._parse_string()
 917        ),
 918        "COMPRESS": lambda self: self._parse_compress(),
 919        "CLUSTERED": lambda self: self.expression(
 920            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 921        ),
 922        "NONCLUSTERED": lambda self: self.expression(
 923            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 924        ),
 925        "DEFAULT": lambda self: self.expression(
 926            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 927        ),
 928        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 929        "EPHEMERAL": lambda self: self.expression(
 930            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 931        ),
 932        "EXCLUDE": lambda self: self.expression(
 933            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 934        ),
 935        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 936        "FORMAT": lambda self: self.expression(
 937            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 938        ),
 939        "GENERATED": lambda self: self._parse_generated_as_identity(),
 940        "IDENTITY": lambda self: self._parse_auto_increment(),
 941        "INLINE": lambda self: self._parse_inline(),
 942        "LIKE": lambda self: self._parse_create_like(),
 943        "NOT": lambda self: self._parse_not_constraint(),
 944        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 945        "ON": lambda self: (
 946            self._match(TokenType.UPDATE)
 947            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 948        )
 949        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 950        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 951        "PERIOD": lambda self: self._parse_period_for_system_time(),
 952        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 953        "REFERENCES": lambda self: self._parse_references(match=False),
 954        "TITLE": lambda self: self.expression(
 955            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 956        ),
 957        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 958        "UNIQUE": lambda self: self._parse_unique(),
 959        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 960        "WITH": lambda self: self.expression(
 961            exp.Properties, expressions=self._parse_wrapped_properties()
 962        ),
 963    }
 964
 965    ALTER_PARSERS = {
 966        "ADD": lambda self: self._parse_alter_table_add(),
 967        "ALTER": lambda self: self._parse_alter_table_alter(),
 968        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 969        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 970        "DROP": lambda self: self._parse_alter_table_drop(),
 971        "RENAME": lambda self: self._parse_alter_table_rename(),
 972        "SET": lambda self: self._parse_alter_table_set(),
 973    }
 974
 975    ALTER_ALTER_PARSERS = {
 976        "DISTKEY": lambda self: self._parse_alter_diststyle(),
 977        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
 978        "SORTKEY": lambda self: self._parse_alter_sortkey(),
 979        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
 980    }
 981
 982    SCHEMA_UNNAMED_CONSTRAINTS = {
 983        "CHECK",
 984        "EXCLUDE",
 985        "FOREIGN KEY",
 986        "LIKE",
 987        "PERIOD",
 988        "PRIMARY KEY",
 989        "UNIQUE",
 990    }
 991
 992    NO_PAREN_FUNCTION_PARSERS = {
 993        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 994        "CASE": lambda self: self._parse_case(),
 995        "IF": lambda self: self._parse_if(),
 996        "NEXT": lambda self: self._parse_next_value_for(),
 997    }
 998
 999    INVALID_FUNC_NAME_TOKENS = {
1000        TokenType.IDENTIFIER,
1001        TokenType.STRING,
1002    }
1003
1004    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1005
1006    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1007
1008    FUNCTION_PARSERS = {
1009        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1010        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1011        "DECODE": lambda self: self._parse_decode(),
1012        "EXTRACT": lambda self: self._parse_extract(),
1013        "GAP_FILL": lambda self: self._parse_gap_fill(),
1014        "JSON_OBJECT": lambda self: self._parse_json_object(),
1015        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1016        "JSON_TABLE": lambda self: self._parse_json_table(),
1017        "MATCH": lambda self: self._parse_match_against(),
1018        "OPENJSON": lambda self: self._parse_open_json(),
1019        "POSITION": lambda self: self._parse_position(),
1020        "PREDICT": lambda self: self._parse_predict(),
1021        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1022        "STRING_AGG": lambda self: self._parse_string_agg(),
1023        "SUBSTRING": lambda self: self._parse_substring(),
1024        "TRIM": lambda self: self._parse_trim(),
1025        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1026        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1027    }
1028
1029    QUERY_MODIFIER_PARSERS = {
1030        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1031        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1032        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1033        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1034        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1035        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1036        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1037        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1038        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1039        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1040        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1041        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1042        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1043        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1044        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1045        TokenType.CLUSTER_BY: lambda self: (
1046            "cluster",
1047            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1048        ),
1049        TokenType.DISTRIBUTE_BY: lambda self: (
1050            "distribute",
1051            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1052        ),
1053        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1054        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1055        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1056    }
1057
1058    SET_PARSERS = {
1059        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1060        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1061        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1062        "TRANSACTION": lambda self: self._parse_set_transaction(),
1063    }
1064
1065    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1066
1067    TYPE_LITERAL_PARSERS = {
1068        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1069    }
1070
1071    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1072
1073    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1074
1075    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1076
1077    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1078    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1079        "ISOLATION": (
1080            ("LEVEL", "REPEATABLE", "READ"),
1081            ("LEVEL", "READ", "COMMITTED"),
1082            ("LEVEL", "READ", "UNCOMITTED"),
1083            ("LEVEL", "SERIALIZABLE"),
1084        ),
1085        "READ": ("WRITE", "ONLY"),
1086    }
1087
1088    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1089        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1090    )
1091    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1092
1093    CREATE_SEQUENCE: OPTIONS_TYPE = {
1094        "SCALE": ("EXTEND", "NOEXTEND"),
1095        "SHARD": ("EXTEND", "NOEXTEND"),
1096        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1097        **dict.fromkeys(
1098            (
1099                "SESSION",
1100                "GLOBAL",
1101                "KEEP",
1102                "NOKEEP",
1103                "ORDER",
1104                "NOORDER",
1105                "NOCACHE",
1106                "CYCLE",
1107                "NOCYCLE",
1108                "NOMINVALUE",
1109                "NOMAXVALUE",
1110                "NOSCALE",
1111                "NOSHARD",
1112            ),
1113            tuple(),
1114        ),
1115    }
1116
1117    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1118
1119    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
1120
1121    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1122
1123    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1124
1125    CLONE_KEYWORDS = {"CLONE", "COPY"}
1126    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1127
1128    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1129
1130    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1131
1132    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1133
1134    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1135
1136    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1137    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1138    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1139
1140    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1141
1142    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1143
1144    ADD_CONSTRAINT_TOKENS = {
1145        TokenType.CONSTRAINT,
1146        TokenType.FOREIGN_KEY,
1147        TokenType.INDEX,
1148        TokenType.KEY,
1149        TokenType.PRIMARY_KEY,
1150        TokenType.UNIQUE,
1151    }
1152
1153    DISTINCT_TOKENS = {TokenType.DISTINCT}
1154
1155    NULL_TOKENS = {TokenType.NULL}
1156
1157    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1158
1159    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1160
1161    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1162
1163    STRICT_CAST = True
1164
1165    PREFIXED_PIVOT_COLUMNS = False
1166    IDENTIFY_PIVOT_STRINGS = False
1167
1168    LOG_DEFAULTS_TO_LN = False
1169
1170    # Whether ADD is present for each column added by ALTER TABLE
1171    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1172
1173    # Whether the table sample clause expects CSV syntax
1174    TABLESAMPLE_CSV = False
1175
1176    # The default method used for table sampling
1177    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1178
1179    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1180    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1181
1182    # Whether the TRIM function expects the characters to trim as its first argument
1183    TRIM_PATTERN_FIRST = False
1184
1185    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1186    STRING_ALIASES = False
1187
1188    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1189    MODIFIERS_ATTACHED_TO_SET_OP = True
1190    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1191
1192    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1193    NO_PAREN_IF_COMMANDS = True
1194
1195    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1196    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1197
1198    # Whether the `:` operator is used to extract a value from a JSON document
1199    COLON_IS_JSON_EXTRACT = False
1200
1201    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1202    # If this is True and '(' is not found, the keyword will be treated as an identifier
1203    VALUES_FOLLOWED_BY_PAREN = True
1204
1205    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1206    SUPPORTS_IMPLICIT_UNNEST = False
1207
1208    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1209    INTERVAL_SPANS = True
1210
1211    # Whether a PARTITION clause can follow a table reference
1212    SUPPORTS_PARTITION_SELECTION = False
1213
1214    __slots__ = (
1215        "error_level",
1216        "error_message_context",
1217        "max_errors",
1218        "dialect",
1219        "sql",
1220        "errors",
1221        "_tokens",
1222        "_index",
1223        "_curr",
1224        "_next",
1225        "_prev",
1226        "_prev_comments",
1227    )
1228
1229    # Autofilled
1230    SHOW_TRIE: t.Dict = {}
1231    SET_TRIE: t.Dict = {}
1232
1233    def __init__(
1234        self,
1235        error_level: t.Optional[ErrorLevel] = None,
1236        error_message_context: int = 100,
1237        max_errors: int = 3,
1238        dialect: DialectType = None,
1239    ):
1240        from sqlglot.dialects import Dialect
1241
1242        self.error_level = error_level or ErrorLevel.IMMEDIATE
1243        self.error_message_context = error_message_context
1244        self.max_errors = max_errors
1245        self.dialect = Dialect.get_or_raise(dialect)
1246        self.reset()
1247
1248    def reset(self):
1249        self.sql = ""
1250        self.errors = []
1251        self._tokens = []
1252        self._index = 0
1253        self._curr = None
1254        self._next = None
1255        self._prev = None
1256        self._prev_comments = None
1257
1258    def parse(
1259        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1260    ) -> t.List[t.Optional[exp.Expression]]:
1261        """
1262        Parses a list of tokens and returns a list of syntax trees, one tree
1263        per parsed SQL statement.
1264
1265        Args:
1266            raw_tokens: The list of tokens.
1267            sql: The original SQL string, used to produce helpful debug messages.
1268
1269        Returns:
1270            The list of the produced syntax trees.
1271        """
1272        return self._parse(
1273            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1274        )
1275
1276    def parse_into(
1277        self,
1278        expression_types: exp.IntoType,
1279        raw_tokens: t.List[Token],
1280        sql: t.Optional[str] = None,
1281    ) -> t.List[t.Optional[exp.Expression]]:
1282        """
1283        Parses a list of tokens into a given Expression type. If a collection of Expression
1284        types is given instead, this method will try to parse the token list into each one
1285        of them, stopping at the first for which the parsing succeeds.
1286
1287        Args:
1288            expression_types: The expression type(s) to try and parse the token list into.
1289            raw_tokens: The list of tokens.
1290            sql: The original SQL string, used to produce helpful debug messages.
1291
1292        Returns:
1293            The target Expression.
1294        """
1295        errors = []
1296        for expression_type in ensure_list(expression_types):
1297            parser = self.EXPRESSION_PARSERS.get(expression_type)
1298            if not parser:
1299                raise TypeError(f"No parser registered for {expression_type}")
1300
1301            try:
1302                return self._parse(parser, raw_tokens, sql)
1303            except ParseError as e:
1304                e.errors[0]["into_expression"] = expression_type
1305                errors.append(e)
1306
1307        raise ParseError(
1308            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1309            errors=merge_errors(errors),
1310        ) from errors[-1]
1311
1312    def _parse(
1313        self,
1314        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1315        raw_tokens: t.List[Token],
1316        sql: t.Optional[str] = None,
1317    ) -> t.List[t.Optional[exp.Expression]]:
1318        self.reset()
1319        self.sql = sql or ""
1320
1321        total = len(raw_tokens)
1322        chunks: t.List[t.List[Token]] = [[]]
1323
1324        for i, token in enumerate(raw_tokens):
1325            if token.token_type == TokenType.SEMICOLON:
1326                if token.comments:
1327                    chunks.append([token])
1328
1329                if i < total - 1:
1330                    chunks.append([])
1331            else:
1332                chunks[-1].append(token)
1333
1334        expressions = []
1335
1336        for tokens in chunks:
1337            self._index = -1
1338            self._tokens = tokens
1339            self._advance()
1340
1341            expressions.append(parse_method(self))
1342
1343            if self._index < len(self._tokens):
1344                self.raise_error("Invalid expression / Unexpected token")
1345
1346            self.check_errors()
1347
1348        return expressions
1349
1350    def check_errors(self) -> None:
1351        """Logs or raises any found errors, depending on the chosen error level setting."""
1352        if self.error_level == ErrorLevel.WARN:
1353            for error in self.errors:
1354                logger.error(str(error))
1355        elif self.error_level == ErrorLevel.RAISE and self.errors:
1356            raise ParseError(
1357                concat_messages(self.errors, self.max_errors),
1358                errors=merge_errors(self.errors),
1359            )
1360
1361    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1362        """
1363        Appends an error in the list of recorded errors or raises it, depending on the chosen
1364        error level setting.
1365        """
1366        token = token or self._curr or self._prev or Token.string("")
1367        start = token.start
1368        end = token.end + 1
1369        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1370        highlight = self.sql[start:end]
1371        end_context = self.sql[end : end + self.error_message_context]
1372
1373        error = ParseError.new(
1374            f"{message}. Line {token.line}, Col: {token.col}.\n"
1375            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1376            description=message,
1377            line=token.line,
1378            col=token.col,
1379            start_context=start_context,
1380            highlight=highlight,
1381            end_context=end_context,
1382        )
1383
1384        if self.error_level == ErrorLevel.IMMEDIATE:
1385            raise error
1386
1387        self.errors.append(error)
1388
1389    def expression(
1390        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1391    ) -> E:
1392        """
1393        Creates a new, validated Expression.
1394
1395        Args:
1396            exp_class: The expression class to instantiate.
1397            comments: An optional list of comments to attach to the expression.
1398            kwargs: The arguments to set for the expression along with their respective values.
1399
1400        Returns:
1401            The target expression.
1402        """
1403        instance = exp_class(**kwargs)
1404        instance.add_comments(comments) if comments else self._add_comments(instance)
1405        return self.validate_expression(instance)
1406
1407    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1408        if expression and self._prev_comments:
1409            expression.add_comments(self._prev_comments)
1410            self._prev_comments = None
1411
1412    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1413        """
1414        Validates an Expression, making sure that all its mandatory arguments are set.
1415
1416        Args:
1417            expression: The expression to validate.
1418            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1419
1420        Returns:
1421            The validated expression.
1422        """
1423        if self.error_level != ErrorLevel.IGNORE:
1424            for error_message in expression.error_messages(args):
1425                self.raise_error(error_message)
1426
1427        return expression
1428
1429    def _find_sql(self, start: Token, end: Token) -> str:
1430        return self.sql[start.start : end.end + 1]
1431
1432    def _is_connected(self) -> bool:
1433        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1434
1435    def _advance(self, times: int = 1) -> None:
1436        self._index += times
1437        self._curr = seq_get(self._tokens, self._index)
1438        self._next = seq_get(self._tokens, self._index + 1)
1439
1440        if self._index > 0:
1441            self._prev = self._tokens[self._index - 1]
1442            self._prev_comments = self._prev.comments
1443        else:
1444            self._prev = None
1445            self._prev_comments = None
1446
1447    def _retreat(self, index: int) -> None:
1448        if index != self._index:
1449            self._advance(index - self._index)
1450
1451    def _warn_unsupported(self) -> None:
1452        if len(self._tokens) <= 1:
1453            return
1454
1455        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1456        # interested in emitting a warning for the one being currently processed.
1457        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1458
1459        logger.warning(
1460            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1461        )
1462
1463    def _parse_command(self) -> exp.Command:
1464        self._warn_unsupported()
1465        return self.expression(
1466            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1467        )
1468
1469    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1470        """
1471        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
1472        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
1473        the parser state accordingly
1474        """
1475        index = self._index
1476        error_level = self.error_level
1477
1478        self.error_level = ErrorLevel.IMMEDIATE
1479        try:
1480            this = parse_method()
1481        except ParseError:
1482            this = None
1483        finally:
1484            if not this or retreat:
1485                self._retreat(index)
1486            self.error_level = error_level
1487
1488        return this
1489
1490    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1491        start = self._prev
1492        exists = self._parse_exists() if allow_exists else None
1493
1494        self._match(TokenType.ON)
1495
1496        materialized = self._match_text_seq("MATERIALIZED")
1497        kind = self._match_set(self.CREATABLES) and self._prev
1498        if not kind:
1499            return self._parse_as_command(start)
1500
1501        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1502            this = self._parse_user_defined_function(kind=kind.token_type)
1503        elif kind.token_type == TokenType.TABLE:
1504            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1505        elif kind.token_type == TokenType.COLUMN:
1506            this = self._parse_column()
1507        else:
1508            this = self._parse_id_var()
1509
1510        self._match(TokenType.IS)
1511
1512        return self.expression(
1513            exp.Comment,
1514            this=this,
1515            kind=kind.text,
1516            expression=self._parse_string(),
1517            exists=exists,
1518            materialized=materialized,
1519        )
1520
1521    def _parse_to_table(
1522        self,
1523    ) -> exp.ToTableProperty:
1524        table = self._parse_table_parts(schema=True)
1525        return self.expression(exp.ToTableProperty, this=table)
1526
1527    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1528    def _parse_ttl(self) -> exp.Expression:
1529        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1530            this = self._parse_bitwise()
1531
1532            if self._match_text_seq("DELETE"):
1533                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1534            if self._match_text_seq("RECOMPRESS"):
1535                return self.expression(
1536                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1537                )
1538            if self._match_text_seq("TO", "DISK"):
1539                return self.expression(
1540                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1541                )
1542            if self._match_text_seq("TO", "VOLUME"):
1543                return self.expression(
1544                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1545                )
1546
1547            return this
1548
1549        expressions = self._parse_csv(_parse_ttl_action)
1550        where = self._parse_where()
1551        group = self._parse_group()
1552
1553        aggregates = None
1554        if group and self._match(TokenType.SET):
1555            aggregates = self._parse_csv(self._parse_set_item)
1556
1557        return self.expression(
1558            exp.MergeTreeTTL,
1559            expressions=expressions,
1560            where=where,
1561            group=group,
1562            aggregates=aggregates,
1563        )
1564
1565    def _parse_statement(self) -> t.Optional[exp.Expression]:
1566        if self._curr is None:
1567            return None
1568
1569        if self._match_set(self.STATEMENT_PARSERS):
1570            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1571
1572        if self._match_set(self.dialect.tokenizer.COMMANDS):
1573            return self._parse_command()
1574
1575        expression = self._parse_expression()
1576        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1577        return self._parse_query_modifiers(expression)
1578
1579    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1580        start = self._prev
1581        temporary = self._match(TokenType.TEMPORARY)
1582        materialized = self._match_text_seq("MATERIALIZED")
1583
1584        kind = self._match_set(self.CREATABLES) and self._prev.text
1585        if not kind:
1586            return self._parse_as_command(start)
1587
1588        if_exists = exists or self._parse_exists()
1589        table = self._parse_table_parts(
1590            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1591        )
1592
1593        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1594
1595        if self._match(TokenType.L_PAREN, advance=False):
1596            expressions = self._parse_wrapped_csv(self._parse_types)
1597        else:
1598            expressions = None
1599
1600        return self.expression(
1601            exp.Drop,
1602            comments=start.comments,
1603            exists=if_exists,
1604            this=table,
1605            expressions=expressions,
1606            kind=kind.upper(),
1607            temporary=temporary,
1608            materialized=materialized,
1609            cascade=self._match_text_seq("CASCADE"),
1610            constraints=self._match_text_seq("CONSTRAINTS"),
1611            purge=self._match_text_seq("PURGE"),
1612            cluster=cluster,
1613        )
1614
1615    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1616        return (
1617            self._match_text_seq("IF")
1618            and (not not_ or self._match(TokenType.NOT))
1619            and self._match(TokenType.EXISTS)
1620        )
1621
1622    def _parse_create(self) -> exp.Create | exp.Command:
1623        # Note: this can't be None because we've matched a statement parser
1624        start = self._prev
1625        comments = self._prev_comments
1626
1627        replace = (
1628            start.token_type == TokenType.REPLACE
1629            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1630            or self._match_pair(TokenType.OR, TokenType.ALTER)
1631        )
1632
1633        unique = self._match(TokenType.UNIQUE)
1634
1635        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1636            self._advance()
1637
1638        properties = None
1639        create_token = self._match_set(self.CREATABLES) and self._prev
1640
1641        if not create_token:
1642            # exp.Properties.Location.POST_CREATE
1643            properties = self._parse_properties()
1644            create_token = self._match_set(self.CREATABLES) and self._prev
1645
1646            if not properties or not create_token:
1647                return self._parse_as_command(start)
1648
1649        exists = self._parse_exists(not_=True)
1650        this = None
1651        expression: t.Optional[exp.Expression] = None
1652        indexes = None
1653        no_schema_binding = None
1654        begin = None
1655        end = None
1656        clone = None
1657
1658        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1659            nonlocal properties
1660            if properties and temp_props:
1661                properties.expressions.extend(temp_props.expressions)
1662            elif temp_props:
1663                properties = temp_props
1664
1665        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1666            this = self._parse_user_defined_function(kind=create_token.token_type)
1667
1668            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1669            extend_props(self._parse_properties())
1670
1671            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1672            extend_props(self._parse_properties())
1673
1674            if not expression:
1675                if self._match(TokenType.COMMAND):
1676                    expression = self._parse_as_command(self._prev)
1677                else:
1678                    begin = self._match(TokenType.BEGIN)
1679                    return_ = self._match_text_seq("RETURN")
1680
1681                    if self._match(TokenType.STRING, advance=False):
1682                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1683                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1684                        expression = self._parse_string()
1685                        extend_props(self._parse_properties())
1686                    else:
1687                        expression = self._parse_statement()
1688
1689                    end = self._match_text_seq("END")
1690
1691                    if return_:
1692                        expression = self.expression(exp.Return, this=expression)
1693        elif create_token.token_type == TokenType.INDEX:
1694            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1695            if not self._match(TokenType.ON):
1696                index = self._parse_id_var()
1697                anonymous = False
1698            else:
1699                index = None
1700                anonymous = True
1701
1702            this = self._parse_index(index=index, anonymous=anonymous)
1703        elif create_token.token_type in self.DB_CREATABLES:
1704            table_parts = self._parse_table_parts(
1705                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1706            )
1707
1708            # exp.Properties.Location.POST_NAME
1709            self._match(TokenType.COMMA)
1710            extend_props(self._parse_properties(before=True))
1711
1712            this = self._parse_schema(this=table_parts)
1713
1714            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1715            extend_props(self._parse_properties())
1716
1717            self._match(TokenType.ALIAS)
1718            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1719                # exp.Properties.Location.POST_ALIAS
1720                extend_props(self._parse_properties())
1721
1722            if create_token.token_type == TokenType.SEQUENCE:
1723                expression = self._parse_types()
1724                extend_props(self._parse_properties())
1725            else:
1726                expression = self._parse_ddl_select()
1727
1728            if create_token.token_type == TokenType.TABLE:
1729                # exp.Properties.Location.POST_EXPRESSION
1730                extend_props(self._parse_properties())
1731
1732                indexes = []
1733                while True:
1734                    index = self._parse_index()
1735
1736                    # exp.Properties.Location.POST_INDEX
1737                    extend_props(self._parse_properties())
1738
1739                    if not index:
1740                        break
1741                    else:
1742                        self._match(TokenType.COMMA)
1743                        indexes.append(index)
1744            elif create_token.token_type == TokenType.VIEW:
1745                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1746                    no_schema_binding = True
1747
1748            shallow = self._match_text_seq("SHALLOW")
1749
1750            if self._match_texts(self.CLONE_KEYWORDS):
1751                copy = self._prev.text.lower() == "copy"
1752                clone = self.expression(
1753                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1754                )
1755
1756        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1757            return self._parse_as_command(start)
1758
1759        return self.expression(
1760            exp.Create,
1761            comments=comments,
1762            this=this,
1763            kind=create_token.text.upper(),
1764            replace=replace,
1765            unique=unique,
1766            expression=expression,
1767            exists=exists,
1768            properties=properties,
1769            indexes=indexes,
1770            no_schema_binding=no_schema_binding,
1771            begin=begin,
1772            end=end,
1773            clone=clone,
1774        )
1775
1776    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1777        seq = exp.SequenceProperties()
1778
1779        options = []
1780        index = self._index
1781
1782        while self._curr:
1783            self._match(TokenType.COMMA)
1784            if self._match_text_seq("INCREMENT"):
1785                self._match_text_seq("BY")
1786                self._match_text_seq("=")
1787                seq.set("increment", self._parse_term())
1788            elif self._match_text_seq("MINVALUE"):
1789                seq.set("minvalue", self._parse_term())
1790            elif self._match_text_seq("MAXVALUE"):
1791                seq.set("maxvalue", self._parse_term())
1792            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1793                self._match_text_seq("=")
1794                seq.set("start", self._parse_term())
1795            elif self._match_text_seq("CACHE"):
1796                # T-SQL allows empty CACHE which is initialized dynamically
1797                seq.set("cache", self._parse_number() or True)
1798            elif self._match_text_seq("OWNED", "BY"):
1799                # "OWNED BY NONE" is the default
1800                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1801            else:
1802                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1803                if opt:
1804                    options.append(opt)
1805                else:
1806                    break
1807
1808        seq.set("options", options if options else None)
1809        return None if self._index == index else seq
1810
1811    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1812        # only used for teradata currently
1813        self._match(TokenType.COMMA)
1814
1815        kwargs = {
1816            "no": self._match_text_seq("NO"),
1817            "dual": self._match_text_seq("DUAL"),
1818            "before": self._match_text_seq("BEFORE"),
1819            "default": self._match_text_seq("DEFAULT"),
1820            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1821            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1822            "after": self._match_text_seq("AFTER"),
1823            "minimum": self._match_texts(("MIN", "MINIMUM")),
1824            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1825        }
1826
1827        if self._match_texts(self.PROPERTY_PARSERS):
1828            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1829            try:
1830                return parser(self, **{k: v for k, v in kwargs.items() if v})
1831            except TypeError:
1832                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1833
1834        return None
1835
1836    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1837        return self._parse_wrapped_csv(self._parse_property)
1838
1839    def _parse_property(self) -> t.Optional[exp.Expression]:
1840        if self._match_texts(self.PROPERTY_PARSERS):
1841            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1842
1843        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1844            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1845
1846        if self._match_text_seq("COMPOUND", "SORTKEY"):
1847            return self._parse_sortkey(compound=True)
1848
1849        if self._match_text_seq("SQL", "SECURITY"):
1850            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1851
1852        index = self._index
1853        key = self._parse_column()
1854
1855        if not self._match(TokenType.EQ):
1856            self._retreat(index)
1857            return self._parse_sequence_properties()
1858
1859        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
1860        if isinstance(key, exp.Column):
1861            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
1862
1863        value = self._parse_bitwise() or self._parse_var(any_token=True)
1864
1865        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
1866        if isinstance(value, exp.Column):
1867            value = exp.var(value.name)
1868
1869        return self.expression(exp.Property, this=key, value=value)
1870
1871    def _parse_stored(self) -> exp.FileFormatProperty:
1872        self._match(TokenType.ALIAS)
1873
1874        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1875        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1876
1877        return self.expression(
1878            exp.FileFormatProperty,
1879            this=(
1880                self.expression(
1881                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1882                )
1883                if input_format or output_format
1884                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1885            ),
1886        )
1887
1888    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
1889        field = self._parse_field()
1890        if isinstance(field, exp.Identifier) and not field.quoted:
1891            field = exp.var(field)
1892
1893        return field
1894
1895    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1896        self._match(TokenType.EQ)
1897        self._match(TokenType.ALIAS)
1898
1899        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1900
1901    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1902        properties = []
1903        while True:
1904            if before:
1905                prop = self._parse_property_before()
1906            else:
1907                prop = self._parse_property()
1908            if not prop:
1909                break
1910            for p in ensure_list(prop):
1911                properties.append(p)
1912
1913        if properties:
1914            return self.expression(exp.Properties, expressions=properties)
1915
1916        return None
1917
1918    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1919        return self.expression(
1920            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1921        )
1922
1923    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1924        if self._index >= 2:
1925            pre_volatile_token = self._tokens[self._index - 2]
1926        else:
1927            pre_volatile_token = None
1928
1929        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1930            return exp.VolatileProperty()
1931
1932        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1933
1934    def _parse_retention_period(self) -> exp.Var:
1935        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
1936        number = self._parse_number()
1937        number_str = f"{number} " if number else ""
1938        unit = self._parse_var(any_token=True)
1939        return exp.var(f"{number_str}{unit}")
1940
1941    def _parse_system_versioning_property(
1942        self, with_: bool = False
1943    ) -> exp.WithSystemVersioningProperty:
1944        self._match(TokenType.EQ)
1945        prop = self.expression(
1946            exp.WithSystemVersioningProperty,
1947            **{  # type: ignore
1948                "on": True,
1949                "with": with_,
1950            },
1951        )
1952
1953        if self._match_text_seq("OFF"):
1954            prop.set("on", False)
1955            return prop
1956
1957        self._match(TokenType.ON)
1958        if self._match(TokenType.L_PAREN):
1959            while self._curr and not self._match(TokenType.R_PAREN):
1960                if self._match_text_seq("HISTORY_TABLE", "="):
1961                    prop.set("this", self._parse_table_parts())
1962                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
1963                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
1964                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
1965                    prop.set("retention_period", self._parse_retention_period())
1966
1967                self._match(TokenType.COMMA)
1968
1969        return prop
1970
1971    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
1972        self._match(TokenType.EQ)
1973        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
1974        prop = self.expression(exp.DataDeletionProperty, on=on)
1975
1976        if self._match(TokenType.L_PAREN):
1977            while self._curr and not self._match(TokenType.R_PAREN):
1978                if self._match_text_seq("FILTER_COLUMN", "="):
1979                    prop.set("filter_column", self._parse_column())
1980                elif self._match_text_seq("RETENTION_PERIOD", "="):
1981                    prop.set("retention_period", self._parse_retention_period())
1982
1983                self._match(TokenType.COMMA)
1984
1985        return prop
1986
1987    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1988        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
1989            prop = self._parse_system_versioning_property(with_=True)
1990            self._match_r_paren()
1991            return prop
1992
1993        if self._match(TokenType.L_PAREN, advance=False):
1994            return self._parse_wrapped_properties()
1995
1996        if self._match_text_seq("JOURNAL"):
1997            return self._parse_withjournaltable()
1998
1999        if self._match_texts(self.VIEW_ATTRIBUTES):
2000            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2001
2002        if self._match_text_seq("DATA"):
2003            return self._parse_withdata(no=False)
2004        elif self._match_text_seq("NO", "DATA"):
2005            return self._parse_withdata(no=True)
2006
2007        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2008            return self._parse_serde_properties(with_=True)
2009
2010        if not self._next:
2011            return None
2012
2013        return self._parse_withisolatedloading()
2014
2015    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2016    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2017        self._match(TokenType.EQ)
2018
2019        user = self._parse_id_var()
2020        self._match(TokenType.PARAMETER)
2021        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2022
2023        if not user or not host:
2024            return None
2025
2026        return exp.DefinerProperty(this=f"{user}@{host}")
2027
2028    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2029        self._match(TokenType.TABLE)
2030        self._match(TokenType.EQ)
2031        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2032
2033    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2034        return self.expression(exp.LogProperty, no=no)
2035
2036    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2037        return self.expression(exp.JournalProperty, **kwargs)
2038
2039    def _parse_checksum(self) -> exp.ChecksumProperty:
2040        self._match(TokenType.EQ)
2041
2042        on = None
2043        if self._match(TokenType.ON):
2044            on = True
2045        elif self._match_text_seq("OFF"):
2046            on = False
2047
2048        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2049
2050    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2051        return self.expression(
2052            exp.Cluster,
2053            expressions=(
2054                self._parse_wrapped_csv(self._parse_ordered)
2055                if wrapped
2056                else self._parse_csv(self._parse_ordered)
2057            ),
2058        )
2059
2060    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2061        self._match_text_seq("BY")
2062
2063        self._match_l_paren()
2064        expressions = self._parse_csv(self._parse_column)
2065        self._match_r_paren()
2066
2067        if self._match_text_seq("SORTED", "BY"):
2068            self._match_l_paren()
2069            sorted_by = self._parse_csv(self._parse_ordered)
2070            self._match_r_paren()
2071        else:
2072            sorted_by = None
2073
2074        self._match(TokenType.INTO)
2075        buckets = self._parse_number()
2076        self._match_text_seq("BUCKETS")
2077
2078        return self.expression(
2079            exp.ClusteredByProperty,
2080            expressions=expressions,
2081            sorted_by=sorted_by,
2082            buckets=buckets,
2083        )
2084
2085    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2086        if not self._match_text_seq("GRANTS"):
2087            self._retreat(self._index - 1)
2088            return None
2089
2090        return self.expression(exp.CopyGrantsProperty)
2091
2092    def _parse_freespace(self) -> exp.FreespaceProperty:
2093        self._match(TokenType.EQ)
2094        return self.expression(
2095            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2096        )
2097
2098    def _parse_mergeblockratio(
2099        self, no: bool = False, default: bool = False
2100    ) -> exp.MergeBlockRatioProperty:
2101        if self._match(TokenType.EQ):
2102            return self.expression(
2103                exp.MergeBlockRatioProperty,
2104                this=self._parse_number(),
2105                percent=self._match(TokenType.PERCENT),
2106            )
2107
2108        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2109
2110    def _parse_datablocksize(
2111        self,
2112        default: t.Optional[bool] = None,
2113        minimum: t.Optional[bool] = None,
2114        maximum: t.Optional[bool] = None,
2115    ) -> exp.DataBlocksizeProperty:
2116        self._match(TokenType.EQ)
2117        size = self._parse_number()
2118
2119        units = None
2120        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2121            units = self._prev.text
2122
2123        return self.expression(
2124            exp.DataBlocksizeProperty,
2125            size=size,
2126            units=units,
2127            default=default,
2128            minimum=minimum,
2129            maximum=maximum,
2130        )
2131
2132    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2133        self._match(TokenType.EQ)
2134        always = self._match_text_seq("ALWAYS")
2135        manual = self._match_text_seq("MANUAL")
2136        never = self._match_text_seq("NEVER")
2137        default = self._match_text_seq("DEFAULT")
2138
2139        autotemp = None
2140        if self._match_text_seq("AUTOTEMP"):
2141            autotemp = self._parse_schema()
2142
2143        return self.expression(
2144            exp.BlockCompressionProperty,
2145            always=always,
2146            manual=manual,
2147            never=never,
2148            default=default,
2149            autotemp=autotemp,
2150        )
2151
2152    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2153        index = self._index
2154        no = self._match_text_seq("NO")
2155        concurrent = self._match_text_seq("CONCURRENT")
2156
2157        if not self._match_text_seq("ISOLATED", "LOADING"):
2158            self._retreat(index)
2159            return None
2160
2161        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2162        return self.expression(
2163            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2164        )
2165
2166    def _parse_locking(self) -> exp.LockingProperty:
2167        if self._match(TokenType.TABLE):
2168            kind = "TABLE"
2169        elif self._match(TokenType.VIEW):
2170            kind = "VIEW"
2171        elif self._match(TokenType.ROW):
2172            kind = "ROW"
2173        elif self._match_text_seq("DATABASE"):
2174            kind = "DATABASE"
2175        else:
2176            kind = None
2177
2178        if kind in ("DATABASE", "TABLE", "VIEW"):
2179            this = self._parse_table_parts()
2180        else:
2181            this = None
2182
2183        if self._match(TokenType.FOR):
2184            for_or_in = "FOR"
2185        elif self._match(TokenType.IN):
2186            for_or_in = "IN"
2187        else:
2188            for_or_in = None
2189
2190        if self._match_text_seq("ACCESS"):
2191            lock_type = "ACCESS"
2192        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2193            lock_type = "EXCLUSIVE"
2194        elif self._match_text_seq("SHARE"):
2195            lock_type = "SHARE"
2196        elif self._match_text_seq("READ"):
2197            lock_type = "READ"
2198        elif self._match_text_seq("WRITE"):
2199            lock_type = "WRITE"
2200        elif self._match_text_seq("CHECKSUM"):
2201            lock_type = "CHECKSUM"
2202        else:
2203            lock_type = None
2204
2205        override = self._match_text_seq("OVERRIDE")
2206
2207        return self.expression(
2208            exp.LockingProperty,
2209            this=this,
2210            kind=kind,
2211            for_or_in=for_or_in,
2212            lock_type=lock_type,
2213            override=override,
2214        )
2215
2216    def _parse_partition_by(self) -> t.List[exp.Expression]:
2217        if self._match(TokenType.PARTITION_BY):
2218            return self._parse_csv(self._parse_assignment)
2219        return []
2220
2221    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2222        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2223            if self._match_text_seq("MINVALUE"):
2224                return exp.var("MINVALUE")
2225            if self._match_text_seq("MAXVALUE"):
2226                return exp.var("MAXVALUE")
2227            return self._parse_bitwise()
2228
2229        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2230        expression = None
2231        from_expressions = None
2232        to_expressions = None
2233
2234        if self._match(TokenType.IN):
2235            this = self._parse_wrapped_csv(self._parse_bitwise)
2236        elif self._match(TokenType.FROM):
2237            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2238            self._match_text_seq("TO")
2239            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2240        elif self._match_text_seq("WITH", "(", "MODULUS"):
2241            this = self._parse_number()
2242            self._match_text_seq(",", "REMAINDER")
2243            expression = self._parse_number()
2244            self._match_r_paren()
2245        else:
2246            self.raise_error("Failed to parse partition bound spec.")
2247
2248        return self.expression(
2249            exp.PartitionBoundSpec,
2250            this=this,
2251            expression=expression,
2252            from_expressions=from_expressions,
2253            to_expressions=to_expressions,
2254        )
2255
2256    # https://www.postgresql.org/docs/current/sql-createtable.html
2257    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2258        if not self._match_text_seq("OF"):
2259            self._retreat(self._index - 1)
2260            return None
2261
2262        this = self._parse_table(schema=True)
2263
2264        if self._match(TokenType.DEFAULT):
2265            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2266        elif self._match_text_seq("FOR", "VALUES"):
2267            expression = self._parse_partition_bound_spec()
2268        else:
2269            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2270
2271        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2272
2273    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2274        self._match(TokenType.EQ)
2275        return self.expression(
2276            exp.PartitionedByProperty,
2277            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2278        )
2279
2280    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2281        if self._match_text_seq("AND", "STATISTICS"):
2282            statistics = True
2283        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2284            statistics = False
2285        else:
2286            statistics = None
2287
2288        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2289
2290    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2291        if self._match_text_seq("SQL"):
2292            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2293        return None
2294
2295    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2296        if self._match_text_seq("SQL", "DATA"):
2297            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2298        return None
2299
2300    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2301        if self._match_text_seq("PRIMARY", "INDEX"):
2302            return exp.NoPrimaryIndexProperty()
2303        if self._match_text_seq("SQL"):
2304            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2305        return None
2306
2307    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2308        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2309            return exp.OnCommitProperty()
2310        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2311            return exp.OnCommitProperty(delete=True)
2312        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2313
2314    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2315        if self._match_text_seq("SQL", "DATA"):
2316            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2317        return None
2318
2319    def _parse_distkey(self) -> exp.DistKeyProperty:
2320        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2321
2322    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2323        table = self._parse_table(schema=True)
2324
2325        options = []
2326        while self._match_texts(("INCLUDING", "EXCLUDING")):
2327            this = self._prev.text.upper()
2328
2329            id_var = self._parse_id_var()
2330            if not id_var:
2331                return None
2332
2333            options.append(
2334                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2335            )
2336
2337        return self.expression(exp.LikeProperty, this=table, expressions=options)
2338
2339    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2340        return self.expression(
2341            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2342        )
2343
2344    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2345        self._match(TokenType.EQ)
2346        return self.expression(
2347            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2348        )
2349
2350    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2351        self._match_text_seq("WITH", "CONNECTION")
2352        return self.expression(
2353            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2354        )
2355
2356    def _parse_returns(self) -> exp.ReturnsProperty:
2357        value: t.Optional[exp.Expression]
2358        null = None
2359        is_table = self._match(TokenType.TABLE)
2360
2361        if is_table:
2362            if self._match(TokenType.LT):
2363                value = self.expression(
2364                    exp.Schema,
2365                    this="TABLE",
2366                    expressions=self._parse_csv(self._parse_struct_types),
2367                )
2368                if not self._match(TokenType.GT):
2369                    self.raise_error("Expecting >")
2370            else:
2371                value = self._parse_schema(exp.var("TABLE"))
2372        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2373            null = True
2374            value = None
2375        else:
2376            value = self._parse_types()
2377
2378        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2379
2380    def _parse_describe(self) -> exp.Describe:
2381        kind = self._match_set(self.CREATABLES) and self._prev.text
2382        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2383        if self._match(TokenType.DOT):
2384            style = None
2385            self._retreat(self._index - 2)
2386        this = self._parse_table(schema=True)
2387        properties = self._parse_properties()
2388        expressions = properties.expressions if properties else None
2389        return self.expression(
2390            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2391        )
2392
2393    def _parse_insert(self) -> exp.Insert:
2394        comments = ensure_list(self._prev_comments)
2395        hint = self._parse_hint()
2396        overwrite = self._match(TokenType.OVERWRITE)
2397        ignore = self._match(TokenType.IGNORE)
2398        local = self._match_text_seq("LOCAL")
2399        alternative = None
2400        is_function = None
2401
2402        if self._match_text_seq("DIRECTORY"):
2403            this: t.Optional[exp.Expression] = self.expression(
2404                exp.Directory,
2405                this=self._parse_var_or_string(),
2406                local=local,
2407                row_format=self._parse_row_format(match_row=True),
2408            )
2409        else:
2410            if self._match(TokenType.OR):
2411                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2412
2413            self._match(TokenType.INTO)
2414            comments += ensure_list(self._prev_comments)
2415            self._match(TokenType.TABLE)
2416            is_function = self._match(TokenType.FUNCTION)
2417
2418            this = (
2419                self._parse_table(schema=True, parse_partition=True)
2420                if not is_function
2421                else self._parse_function()
2422            )
2423
2424        returning = self._parse_returning()
2425
2426        return self.expression(
2427            exp.Insert,
2428            comments=comments,
2429            hint=hint,
2430            is_function=is_function,
2431            this=this,
2432            stored=self._match_text_seq("STORED") and self._parse_stored(),
2433            by_name=self._match_text_seq("BY", "NAME"),
2434            exists=self._parse_exists(),
2435            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2436            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2437            conflict=self._parse_on_conflict(),
2438            returning=returning or self._parse_returning(),
2439            overwrite=overwrite,
2440            alternative=alternative,
2441            ignore=ignore,
2442        )
2443
2444    def _parse_kill(self) -> exp.Kill:
2445        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2446
2447        return self.expression(
2448            exp.Kill,
2449            this=self._parse_primary(),
2450            kind=kind,
2451        )
2452
2453    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2454        conflict = self._match_text_seq("ON", "CONFLICT")
2455        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2456
2457        if not conflict and not duplicate:
2458            return None
2459
2460        conflict_keys = None
2461        constraint = None
2462
2463        if conflict:
2464            if self._match_text_seq("ON", "CONSTRAINT"):
2465                constraint = self._parse_id_var()
2466            elif self._match(TokenType.L_PAREN):
2467                conflict_keys = self._parse_csv(self._parse_id_var)
2468                self._match_r_paren()
2469
2470        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2471        if self._prev.token_type == TokenType.UPDATE:
2472            self._match(TokenType.SET)
2473            expressions = self._parse_csv(self._parse_equality)
2474        else:
2475            expressions = None
2476
2477        return self.expression(
2478            exp.OnConflict,
2479            duplicate=duplicate,
2480            expressions=expressions,
2481            action=action,
2482            conflict_keys=conflict_keys,
2483            constraint=constraint,
2484        )
2485
2486    def _parse_returning(self) -> t.Optional[exp.Returning]:
2487        if not self._match(TokenType.RETURNING):
2488            return None
2489        return self.expression(
2490            exp.Returning,
2491            expressions=self._parse_csv(self._parse_expression),
2492            into=self._match(TokenType.INTO) and self._parse_table_part(),
2493        )
2494
2495    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2496        if not self._match(TokenType.FORMAT):
2497            return None
2498        return self._parse_row_format()
2499
2500    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2501        index = self._index
2502        with_ = with_ or self._match_text_seq("WITH")
2503
2504        if not self._match(TokenType.SERDE_PROPERTIES):
2505            self._retreat(index)
2506            return None
2507        return self.expression(
2508            exp.SerdeProperties,
2509            **{  # type: ignore
2510                "expressions": self._parse_wrapped_properties(),
2511                "with": with_,
2512            },
2513        )
2514
2515    def _parse_row_format(
2516        self, match_row: bool = False
2517    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2518        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2519            return None
2520
2521        if self._match_text_seq("SERDE"):
2522            this = self._parse_string()
2523
2524            serde_properties = self._parse_serde_properties()
2525
2526            return self.expression(
2527                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2528            )
2529
2530        self._match_text_seq("DELIMITED")
2531
2532        kwargs = {}
2533
2534        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2535            kwargs["fields"] = self._parse_string()
2536            if self._match_text_seq("ESCAPED", "BY"):
2537                kwargs["escaped"] = self._parse_string()
2538        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2539            kwargs["collection_items"] = self._parse_string()
2540        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2541            kwargs["map_keys"] = self._parse_string()
2542        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2543            kwargs["lines"] = self._parse_string()
2544        if self._match_text_seq("NULL", "DEFINED", "AS"):
2545            kwargs["null"] = self._parse_string()
2546
2547        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2548
2549    def _parse_load(self) -> exp.LoadData | exp.Command:
2550        if self._match_text_seq("DATA"):
2551            local = self._match_text_seq("LOCAL")
2552            self._match_text_seq("INPATH")
2553            inpath = self._parse_string()
2554            overwrite = self._match(TokenType.OVERWRITE)
2555            self._match_pair(TokenType.INTO, TokenType.TABLE)
2556
2557            return self.expression(
2558                exp.LoadData,
2559                this=self._parse_table(schema=True),
2560                local=local,
2561                overwrite=overwrite,
2562                inpath=inpath,
2563                partition=self._parse_partition(),
2564                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2565                serde=self._match_text_seq("SERDE") and self._parse_string(),
2566            )
2567        return self._parse_as_command(self._prev)
2568
2569    def _parse_delete(self) -> exp.Delete:
2570        # This handles MySQL's "Multiple-Table Syntax"
2571        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2572        tables = None
2573        comments = self._prev_comments
2574        if not self._match(TokenType.FROM, advance=False):
2575            tables = self._parse_csv(self._parse_table) or None
2576
2577        returning = self._parse_returning()
2578
2579        return self.expression(
2580            exp.Delete,
2581            comments=comments,
2582            tables=tables,
2583            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2584            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2585            where=self._parse_where(),
2586            returning=returning or self._parse_returning(),
2587            limit=self._parse_limit(),
2588        )
2589
2590    def _parse_update(self) -> exp.Update:
2591        comments = self._prev_comments
2592        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2593        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2594        returning = self._parse_returning()
2595        return self.expression(
2596            exp.Update,
2597            comments=comments,
2598            **{  # type: ignore
2599                "this": this,
2600                "expressions": expressions,
2601                "from": self._parse_from(joins=True),
2602                "where": self._parse_where(),
2603                "returning": returning or self._parse_returning(),
2604                "order": self._parse_order(),
2605                "limit": self._parse_limit(),
2606            },
2607        )
2608
2609    def _parse_uncache(self) -> exp.Uncache:
2610        if not self._match(TokenType.TABLE):
2611            self.raise_error("Expecting TABLE after UNCACHE")
2612
2613        return self.expression(
2614            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2615        )
2616
2617    def _parse_cache(self) -> exp.Cache:
2618        lazy = self._match_text_seq("LAZY")
2619        self._match(TokenType.TABLE)
2620        table = self._parse_table(schema=True)
2621
2622        options = []
2623        if self._match_text_seq("OPTIONS"):
2624            self._match_l_paren()
2625            k = self._parse_string()
2626            self._match(TokenType.EQ)
2627            v = self._parse_string()
2628            options = [k, v]
2629            self._match_r_paren()
2630
2631        self._match(TokenType.ALIAS)
2632        return self.expression(
2633            exp.Cache,
2634            this=table,
2635            lazy=lazy,
2636            options=options,
2637            expression=self._parse_select(nested=True),
2638        )
2639
2640    def _parse_partition(self) -> t.Optional[exp.Partition]:
2641        if not self._match(TokenType.PARTITION):
2642            return None
2643
2644        return self.expression(
2645            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2646        )
2647
2648    def _parse_value(self) -> t.Optional[exp.Tuple]:
2649        if self._match(TokenType.L_PAREN):
2650            expressions = self._parse_csv(self._parse_expression)
2651            self._match_r_paren()
2652            return self.expression(exp.Tuple, expressions=expressions)
2653
2654        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2655        expression = self._parse_expression()
2656        if expression:
2657            return self.expression(exp.Tuple, expressions=[expression])
2658        return None
2659
2660    def _parse_projections(self) -> t.List[exp.Expression]:
2661        return self._parse_expressions()
2662
2663    def _parse_select(
2664        self,
2665        nested: bool = False,
2666        table: bool = False,
2667        parse_subquery_alias: bool = True,
2668        parse_set_operation: bool = True,
2669    ) -> t.Optional[exp.Expression]:
2670        cte = self._parse_with()
2671
2672        if cte:
2673            this = self._parse_statement()
2674
2675            if not this:
2676                self.raise_error("Failed to parse any statement following CTE")
2677                return cte
2678
2679            if "with" in this.arg_types:
2680                this.set("with", cte)
2681            else:
2682                self.raise_error(f"{this.key} does not support CTE")
2683                this = cte
2684
2685            return this
2686
2687        # duckdb supports leading with FROM x
2688        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2689
2690        if self._match(TokenType.SELECT):
2691            comments = self._prev_comments
2692
2693            hint = self._parse_hint()
2694            all_ = self._match(TokenType.ALL)
2695            distinct = self._match_set(self.DISTINCT_TOKENS)
2696
2697            kind = (
2698                self._match(TokenType.ALIAS)
2699                and self._match_texts(("STRUCT", "VALUE"))
2700                and self._prev.text.upper()
2701            )
2702
2703            if distinct:
2704                distinct = self.expression(
2705                    exp.Distinct,
2706                    on=self._parse_value() if self._match(TokenType.ON) else None,
2707                )
2708
2709            if all_ and distinct:
2710                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2711
2712            limit = self._parse_limit(top=True)
2713            projections = self._parse_projections()
2714
2715            this = self.expression(
2716                exp.Select,
2717                kind=kind,
2718                hint=hint,
2719                distinct=distinct,
2720                expressions=projections,
2721                limit=limit,
2722            )
2723            this.comments = comments
2724
2725            into = self._parse_into()
2726            if into:
2727                this.set("into", into)
2728
2729            if not from_:
2730                from_ = self._parse_from()
2731
2732            if from_:
2733                this.set("from", from_)
2734
2735            this = self._parse_query_modifiers(this)
2736        elif (table or nested) and self._match(TokenType.L_PAREN):
2737            if self._match(TokenType.PIVOT):
2738                this = self._parse_simplified_pivot()
2739            elif self._match(TokenType.FROM):
2740                this = exp.select("*").from_(
2741                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2742                )
2743            else:
2744                this = (
2745                    self._parse_table()
2746                    if table
2747                    else self._parse_select(nested=True, parse_set_operation=False)
2748                )
2749                this = self._parse_query_modifiers(self._parse_set_operations(this))
2750
2751            self._match_r_paren()
2752
2753            # We return early here so that the UNION isn't attached to the subquery by the
2754            # following call to _parse_set_operations, but instead becomes the parent node
2755            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2756        elif self._match(TokenType.VALUES, advance=False):
2757            this = self._parse_derived_table_values()
2758        elif from_:
2759            this = exp.select("*").from_(from_.this, copy=False)
2760        else:
2761            this = None
2762
2763        if parse_set_operation:
2764            return self._parse_set_operations(this)
2765        return this
2766
2767    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2768        if not skip_with_token and not self._match(TokenType.WITH):
2769            return None
2770
2771        comments = self._prev_comments
2772        recursive = self._match(TokenType.RECURSIVE)
2773
2774        expressions = []
2775        while True:
2776            expressions.append(self._parse_cte())
2777
2778            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2779                break
2780            else:
2781                self._match(TokenType.WITH)
2782
2783        return self.expression(
2784            exp.With, comments=comments, expressions=expressions, recursive=recursive
2785        )
2786
2787    def _parse_cte(self) -> exp.CTE:
2788        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2789        if not alias or not alias.this:
2790            self.raise_error("Expected CTE to have alias")
2791
2792        self._match(TokenType.ALIAS)
2793
2794        if self._match_text_seq("NOT", "MATERIALIZED"):
2795            materialized = False
2796        elif self._match_text_seq("MATERIALIZED"):
2797            materialized = True
2798        else:
2799            materialized = None
2800
2801        return self.expression(
2802            exp.CTE,
2803            this=self._parse_wrapped(self._parse_statement),
2804            alias=alias,
2805            materialized=materialized,
2806        )
2807
2808    def _parse_table_alias(
2809        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2810    ) -> t.Optional[exp.TableAlias]:
2811        any_token = self._match(TokenType.ALIAS)
2812        alias = (
2813            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2814            or self._parse_string_as_identifier()
2815        )
2816
2817        index = self._index
2818        if self._match(TokenType.L_PAREN):
2819            columns = self._parse_csv(self._parse_function_parameter)
2820            self._match_r_paren() if columns else self._retreat(index)
2821        else:
2822            columns = None
2823
2824        if not alias and not columns:
2825            return None
2826
2827        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
2828
2829        # We bubble up comments from the Identifier to the TableAlias
2830        if isinstance(alias, exp.Identifier):
2831            table_alias.add_comments(alias.pop_comments())
2832
2833        return table_alias
2834
2835    def _parse_subquery(
2836        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2837    ) -> t.Optional[exp.Subquery]:
2838        if not this:
2839            return None
2840
2841        return self.expression(
2842            exp.Subquery,
2843            this=this,
2844            pivots=self._parse_pivots(),
2845            alias=self._parse_table_alias() if parse_alias else None,
2846        )
2847
2848    def _implicit_unnests_to_explicit(self, this: E) -> E:
2849        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
2850
2851        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2852        for i, join in enumerate(this.args.get("joins") or []):
2853            table = join.this
2854            normalized_table = table.copy()
2855            normalized_table.meta["maybe_column"] = True
2856            normalized_table = _norm(normalized_table, dialect=self.dialect)
2857
2858            if isinstance(table, exp.Table) and not join.args.get("on"):
2859                if normalized_table.parts[0].name in refs:
2860                    table_as_column = table.to_column()
2861                    unnest = exp.Unnest(expressions=[table_as_column])
2862
2863                    # Table.to_column creates a parent Alias node that we want to convert to
2864                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2865                    if isinstance(table.args.get("alias"), exp.TableAlias):
2866                        table_as_column.replace(table_as_column.this)
2867                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2868
2869                    table.replace(unnest)
2870
2871            refs.add(normalized_table.alias_or_name)
2872
2873        return this
2874
2875    def _parse_query_modifiers(
2876        self, this: t.Optional[exp.Expression]
2877    ) -> t.Optional[exp.Expression]:
2878        if isinstance(this, (exp.Query, exp.Table)):
2879            for join in self._parse_joins():
2880                this.append("joins", join)
2881            for lateral in iter(self._parse_lateral, None):
2882                this.append("laterals", lateral)
2883
2884            while True:
2885                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2886                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2887                    key, expression = parser(self)
2888
2889                    if expression:
2890                        this.set(key, expression)
2891                        if key == "limit":
2892                            offset = expression.args.pop("offset", None)
2893
2894                            if offset:
2895                                offset = exp.Offset(expression=offset)
2896                                this.set("offset", offset)
2897
2898                                limit_by_expressions = expression.expressions
2899                                expression.set("expressions", None)
2900                                offset.set("expressions", limit_by_expressions)
2901                        continue
2902                break
2903
2904        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
2905            this = self._implicit_unnests_to_explicit(this)
2906
2907        return this
2908
2909    def _parse_hint(self) -> t.Optional[exp.Hint]:
2910        if self._match(TokenType.HINT):
2911            hints = []
2912            for hint in iter(
2913                lambda: self._parse_csv(
2914                    lambda: self._parse_function() or self._parse_var(upper=True)
2915                ),
2916                [],
2917            ):
2918                hints.extend(hint)
2919
2920            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2921                self.raise_error("Expected */ after HINT")
2922
2923            return self.expression(exp.Hint, expressions=hints)
2924
2925        return None
2926
2927    def _parse_into(self) -> t.Optional[exp.Into]:
2928        if not self._match(TokenType.INTO):
2929            return None
2930
2931        temp = self._match(TokenType.TEMPORARY)
2932        unlogged = self._match_text_seq("UNLOGGED")
2933        self._match(TokenType.TABLE)
2934
2935        return self.expression(
2936            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2937        )
2938
2939    def _parse_from(
2940        self, joins: bool = False, skip_from_token: bool = False
2941    ) -> t.Optional[exp.From]:
2942        if not skip_from_token and not self._match(TokenType.FROM):
2943            return None
2944
2945        return self.expression(
2946            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2947        )
2948
2949    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
2950        return self.expression(
2951            exp.MatchRecognizeMeasure,
2952            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
2953            this=self._parse_expression(),
2954        )
2955
2956    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2957        if not self._match(TokenType.MATCH_RECOGNIZE):
2958            return None
2959
2960        self._match_l_paren()
2961
2962        partition = self._parse_partition_by()
2963        order = self._parse_order()
2964
2965        measures = (
2966            self._parse_csv(self._parse_match_recognize_measure)
2967            if self._match_text_seq("MEASURES")
2968            else None
2969        )
2970
2971        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2972            rows = exp.var("ONE ROW PER MATCH")
2973        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2974            text = "ALL ROWS PER MATCH"
2975            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2976                text += " SHOW EMPTY MATCHES"
2977            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2978                text += " OMIT EMPTY MATCHES"
2979            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2980                text += " WITH UNMATCHED ROWS"
2981            rows = exp.var(text)
2982        else:
2983            rows = None
2984
2985        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2986            text = "AFTER MATCH SKIP"
2987            if self._match_text_seq("PAST", "LAST", "ROW"):
2988                text += " PAST LAST ROW"
2989            elif self._match_text_seq("TO", "NEXT", "ROW"):
2990                text += " TO NEXT ROW"
2991            elif self._match_text_seq("TO", "FIRST"):
2992                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2993            elif self._match_text_seq("TO", "LAST"):
2994                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2995            after = exp.var(text)
2996        else:
2997            after = None
2998
2999        if self._match_text_seq("PATTERN"):
3000            self._match_l_paren()
3001
3002            if not self._curr:
3003                self.raise_error("Expecting )", self._curr)
3004
3005            paren = 1
3006            start = self._curr
3007
3008            while self._curr and paren > 0:
3009                if self._curr.token_type == TokenType.L_PAREN:
3010                    paren += 1
3011                if self._curr.token_type == TokenType.R_PAREN:
3012                    paren -= 1
3013
3014                end = self._prev
3015                self._advance()
3016
3017            if paren > 0:
3018                self.raise_error("Expecting )", self._curr)
3019
3020            pattern = exp.var(self._find_sql(start, end))
3021        else:
3022            pattern = None
3023
3024        define = (
3025            self._parse_csv(self._parse_name_as_expression)
3026            if self._match_text_seq("DEFINE")
3027            else None
3028        )
3029
3030        self._match_r_paren()
3031
3032        return self.expression(
3033            exp.MatchRecognize,
3034            partition_by=partition,
3035            order=order,
3036            measures=measures,
3037            rows=rows,
3038            after=after,
3039            pattern=pattern,
3040            define=define,
3041            alias=self._parse_table_alias(),
3042        )
3043
3044    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3045        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3046        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3047            cross_apply = False
3048
3049        if cross_apply is not None:
3050            this = self._parse_select(table=True)
3051            view = None
3052            outer = None
3053        elif self._match(TokenType.LATERAL):
3054            this = self._parse_select(table=True)
3055            view = self._match(TokenType.VIEW)
3056            outer = self._match(TokenType.OUTER)
3057        else:
3058            return None
3059
3060        if not this:
3061            this = (
3062                self._parse_unnest()
3063                or self._parse_function()
3064                or self._parse_id_var(any_token=False)
3065            )
3066
3067            while self._match(TokenType.DOT):
3068                this = exp.Dot(
3069                    this=this,
3070                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3071                )
3072
3073        if view:
3074            table = self._parse_id_var(any_token=False)
3075            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3076            table_alias: t.Optional[exp.TableAlias] = self.expression(
3077                exp.TableAlias, this=table, columns=columns
3078            )
3079        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3080            # We move the alias from the lateral's child node to the lateral itself
3081            table_alias = this.args["alias"].pop()
3082        else:
3083            table_alias = self._parse_table_alias()
3084
3085        return self.expression(
3086            exp.Lateral,
3087            this=this,
3088            view=view,
3089            outer=outer,
3090            alias=table_alias,
3091            cross_apply=cross_apply,
3092        )
3093
3094    def _parse_join_parts(
3095        self,
3096    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3097        return (
3098            self._match_set(self.JOIN_METHODS) and self._prev,
3099            self._match_set(self.JOIN_SIDES) and self._prev,
3100            self._match_set(self.JOIN_KINDS) and self._prev,
3101        )
3102
3103    def _parse_join(
3104        self, skip_join_token: bool = False, parse_bracket: bool = False
3105    ) -> t.Optional[exp.Join]:
3106        if self._match(TokenType.COMMA):
3107            return self.expression(exp.Join, this=self._parse_table())
3108
3109        index = self._index
3110        method, side, kind = self._parse_join_parts()
3111        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3112        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3113
3114        if not skip_join_token and not join:
3115            self._retreat(index)
3116            kind = None
3117            method = None
3118            side = None
3119
3120        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3121        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3122
3123        if not skip_join_token and not join and not outer_apply and not cross_apply:
3124            return None
3125
3126        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3127
3128        if method:
3129            kwargs["method"] = method.text
3130        if side:
3131            kwargs["side"] = side.text
3132        if kind:
3133            kwargs["kind"] = kind.text
3134        if hint:
3135            kwargs["hint"] = hint
3136
3137        if self._match(TokenType.MATCH_CONDITION):
3138            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3139
3140        if self._match(TokenType.ON):
3141            kwargs["on"] = self._parse_assignment()
3142        elif self._match(TokenType.USING):
3143            kwargs["using"] = self._parse_wrapped_id_vars()
3144        elif not isinstance(kwargs["this"], exp.Unnest) and not (
3145            kind and kind.token_type == TokenType.CROSS
3146        ):
3147            index = self._index
3148            joins: t.Optional[list] = list(self._parse_joins())
3149
3150            if joins and self._match(TokenType.ON):
3151                kwargs["on"] = self._parse_assignment()
3152            elif joins and self._match(TokenType.USING):
3153                kwargs["using"] = self._parse_wrapped_id_vars()
3154            else:
3155                joins = None
3156                self._retreat(index)
3157
3158            kwargs["this"].set("joins", joins if joins else None)
3159
3160        comments = [c for token in (method, side, kind) if token for c in token.comments]
3161        return self.expression(exp.Join, comments=comments, **kwargs)
3162
3163    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3164        this = self._parse_assignment()
3165
3166        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3167            return this
3168
3169        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3170            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3171
3172        return this
3173
3174    def _parse_index_params(self) -> exp.IndexParameters:
3175        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3176
3177        if self._match(TokenType.L_PAREN, advance=False):
3178            columns = self._parse_wrapped_csv(self._parse_with_operator)
3179        else:
3180            columns = None
3181
3182        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3183        partition_by = self._parse_partition_by()
3184        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3185        tablespace = (
3186            self._parse_var(any_token=True)
3187            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3188            else None
3189        )
3190        where = self._parse_where()
3191
3192        on = self._parse_field() if self._match(TokenType.ON) else None
3193
3194        return self.expression(
3195            exp.IndexParameters,
3196            using=using,
3197            columns=columns,
3198            include=include,
3199            partition_by=partition_by,
3200            where=where,
3201            with_storage=with_storage,
3202            tablespace=tablespace,
3203            on=on,
3204        )
3205
3206    def _parse_index(
3207        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3208    ) -> t.Optional[exp.Index]:
3209        if index or anonymous:
3210            unique = None
3211            primary = None
3212            amp = None
3213
3214            self._match(TokenType.ON)
3215            self._match(TokenType.TABLE)  # hive
3216            table = self._parse_table_parts(schema=True)
3217        else:
3218            unique = self._match(TokenType.UNIQUE)
3219            primary = self._match_text_seq("PRIMARY")
3220            amp = self._match_text_seq("AMP")
3221
3222            if not self._match(TokenType.INDEX):
3223                return None
3224
3225            index = self._parse_id_var()
3226            table = None
3227
3228        params = self._parse_index_params()
3229
3230        return self.expression(
3231            exp.Index,
3232            this=index,
3233            table=table,
3234            unique=unique,
3235            primary=primary,
3236            amp=amp,
3237            params=params,
3238        )
3239
3240    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3241        hints: t.List[exp.Expression] = []
3242        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3243            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3244            hints.append(
3245                self.expression(
3246                    exp.WithTableHint,
3247                    expressions=self._parse_csv(
3248                        lambda: self._parse_function() or self._parse_var(any_token=True)
3249                    ),
3250                )
3251            )
3252            self._match_r_paren()
3253        else:
3254            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3255            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3256                hint = exp.IndexTableHint(this=self._prev.text.upper())
3257
3258                self._match_set((TokenType.INDEX, TokenType.KEY))
3259                if self._match(TokenType.FOR):
3260                    hint.set("target", self._advance_any() and self._prev.text.upper())
3261
3262                hint.set("expressions", self._parse_wrapped_id_vars())
3263                hints.append(hint)
3264
3265        return hints or None
3266
3267    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3268        return (
3269            (not schema and self._parse_function(optional_parens=False))
3270            or self._parse_id_var(any_token=False)
3271            or self._parse_string_as_identifier()
3272            or self._parse_placeholder()
3273        )
3274
3275    def _parse_table_parts(
3276        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3277    ) -> exp.Table:
3278        catalog = None
3279        db = None
3280        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3281
3282        while self._match(TokenType.DOT):
3283            if catalog:
3284                # This allows nesting the table in arbitrarily many dot expressions if needed
3285                table = self.expression(
3286                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3287                )
3288            else:
3289                catalog = db
3290                db = table
3291                # "" used for tsql FROM a..b case
3292                table = self._parse_table_part(schema=schema) or ""
3293
3294        if (
3295            wildcard
3296            and self._is_connected()
3297            and (isinstance(table, exp.Identifier) or not table)
3298            and self._match(TokenType.STAR)
3299        ):
3300            if isinstance(table, exp.Identifier):
3301                table.args["this"] += "*"
3302            else:
3303                table = exp.Identifier(this="*")
3304
3305        # We bubble up comments from the Identifier to the Table
3306        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3307
3308        if is_db_reference:
3309            catalog = db
3310            db = table
3311            table = None
3312
3313        if not table and not is_db_reference:
3314            self.raise_error(f"Expected table name but got {self._curr}")
3315        if not db and is_db_reference:
3316            self.raise_error(f"Expected database name but got {self._curr}")
3317
3318        return self.expression(
3319            exp.Table,
3320            comments=comments,
3321            this=table,
3322            db=db,
3323            catalog=catalog,
3324            pivots=self._parse_pivots(),
3325        )
3326
3327    def _parse_table(
3328        self,
3329        schema: bool = False,
3330        joins: bool = False,
3331        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3332        parse_bracket: bool = False,
3333        is_db_reference: bool = False,
3334        parse_partition: bool = False,
3335    ) -> t.Optional[exp.Expression]:
3336        lateral = self._parse_lateral()
3337        if lateral:
3338            return lateral
3339
3340        unnest = self._parse_unnest()
3341        if unnest:
3342            return unnest
3343
3344        values = self._parse_derived_table_values()
3345        if values:
3346            return values
3347
3348        subquery = self._parse_select(table=True)
3349        if subquery:
3350            if not subquery.args.get("pivots"):
3351                subquery.set("pivots", self._parse_pivots())
3352            return subquery
3353
3354        bracket = parse_bracket and self._parse_bracket(None)
3355        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3356
3357        only = self._match(TokenType.ONLY)
3358
3359        this = t.cast(
3360            exp.Expression,
3361            bracket
3362            or self._parse_bracket(
3363                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3364            ),
3365        )
3366
3367        if only:
3368            this.set("only", only)
3369
3370        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3371        self._match_text_seq("*")
3372
3373        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3374        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3375            this.set("partition", self._parse_partition())
3376
3377        if schema:
3378            return self._parse_schema(this=this)
3379
3380        version = self._parse_version()
3381
3382        if version:
3383            this.set("version", version)
3384
3385        if self.dialect.ALIAS_POST_TABLESAMPLE:
3386            table_sample = self._parse_table_sample()
3387
3388        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3389        if alias:
3390            this.set("alias", alias)
3391
3392        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3393            return self.expression(
3394                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3395            )
3396
3397        this.set("hints", self._parse_table_hints())
3398
3399        if not this.args.get("pivots"):
3400            this.set("pivots", self._parse_pivots())
3401
3402        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3403            table_sample = self._parse_table_sample()
3404
3405        if table_sample:
3406            table_sample.set("this", this)
3407            this = table_sample
3408
3409        if joins:
3410            for join in self._parse_joins():
3411                this.append("joins", join)
3412
3413        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3414            this.set("ordinality", True)
3415            this.set("alias", self._parse_table_alias())
3416
3417        return this
3418
3419    def _parse_version(self) -> t.Optional[exp.Version]:
3420        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3421            this = "TIMESTAMP"
3422        elif self._match(TokenType.VERSION_SNAPSHOT):
3423            this = "VERSION"
3424        else:
3425            return None
3426
3427        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3428            kind = self._prev.text.upper()
3429            start = self._parse_bitwise()
3430            self._match_texts(("TO", "AND"))
3431            end = self._parse_bitwise()
3432            expression: t.Optional[exp.Expression] = self.expression(
3433                exp.Tuple, expressions=[start, end]
3434            )
3435        elif self._match_text_seq("CONTAINED", "IN"):
3436            kind = "CONTAINED IN"
3437            expression = self.expression(
3438                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3439            )
3440        elif self._match(TokenType.ALL):
3441            kind = "ALL"
3442            expression = None
3443        else:
3444            self._match_text_seq("AS", "OF")
3445            kind = "AS OF"
3446            expression = self._parse_type()
3447
3448        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3449
3450    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3451        if not self._match(TokenType.UNNEST):
3452            return None
3453
3454        expressions = self._parse_wrapped_csv(self._parse_equality)
3455        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3456
3457        alias = self._parse_table_alias() if with_alias else None
3458
3459        if alias:
3460            if self.dialect.UNNEST_COLUMN_ONLY:
3461                if alias.args.get("columns"):
3462                    self.raise_error("Unexpected extra column alias in unnest.")
3463
3464                alias.set("columns", [alias.this])
3465                alias.set("this", None)
3466
3467            columns = alias.args.get("columns") or []
3468            if offset and len(expressions) < len(columns):
3469                offset = columns.pop()
3470
3471        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3472            self._match(TokenType.ALIAS)
3473            offset = self._parse_id_var(
3474                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3475            ) or exp.to_identifier("offset")
3476
3477        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3478
3479    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3480        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3481        if not is_derived and not self._match_text_seq("VALUES"):
3482            return None
3483
3484        expressions = self._parse_csv(self._parse_value)
3485        alias = self._parse_table_alias()
3486
3487        if is_derived:
3488            self._match_r_paren()
3489
3490        return self.expression(
3491            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3492        )
3493
3494    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3495        if not self._match(TokenType.TABLE_SAMPLE) and not (
3496            as_modifier and self._match_text_seq("USING", "SAMPLE")
3497        ):
3498            return None
3499
3500        bucket_numerator = None
3501        bucket_denominator = None
3502        bucket_field = None
3503        percent = None
3504        size = None
3505        seed = None
3506
3507        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3508        matched_l_paren = self._match(TokenType.L_PAREN)
3509
3510        if self.TABLESAMPLE_CSV:
3511            num = None
3512            expressions = self._parse_csv(self._parse_primary)
3513        else:
3514            expressions = None
3515            num = (
3516                self._parse_factor()
3517                if self._match(TokenType.NUMBER, advance=False)
3518                else self._parse_primary() or self._parse_placeholder()
3519            )
3520
3521        if self._match_text_seq("BUCKET"):
3522            bucket_numerator = self._parse_number()
3523            self._match_text_seq("OUT", "OF")
3524            bucket_denominator = bucket_denominator = self._parse_number()
3525            self._match(TokenType.ON)
3526            bucket_field = self._parse_field()
3527        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3528            percent = num
3529        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3530            size = num
3531        else:
3532            percent = num
3533
3534        if matched_l_paren:
3535            self._match_r_paren()
3536
3537        if self._match(TokenType.L_PAREN):
3538            method = self._parse_var(upper=True)
3539            seed = self._match(TokenType.COMMA) and self._parse_number()
3540            self._match_r_paren()
3541        elif self._match_texts(("SEED", "REPEATABLE")):
3542            seed = self._parse_wrapped(self._parse_number)
3543
3544        if not method and self.DEFAULT_SAMPLING_METHOD:
3545            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3546
3547        return self.expression(
3548            exp.TableSample,
3549            expressions=expressions,
3550            method=method,
3551            bucket_numerator=bucket_numerator,
3552            bucket_denominator=bucket_denominator,
3553            bucket_field=bucket_field,
3554            percent=percent,
3555            size=size,
3556            seed=seed,
3557        )
3558
3559    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3560        return list(iter(self._parse_pivot, None)) or None
3561
3562    def _parse_joins(self) -> t.Iterator[exp.Join]:
3563        return iter(self._parse_join, None)
3564
3565    # https://duckdb.org/docs/sql/statements/pivot
3566    def _parse_simplified_pivot(self) -> exp.Pivot:
3567        def _parse_on() -> t.Optional[exp.Expression]:
3568            this = self._parse_bitwise()
3569            return self._parse_in(this) if self._match(TokenType.IN) else this
3570
3571        this = self._parse_table()
3572        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3573        using = self._match(TokenType.USING) and self._parse_csv(
3574            lambda: self._parse_alias(self._parse_function())
3575        )
3576        group = self._parse_group()
3577        return self.expression(
3578            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3579        )
3580
3581    def _parse_pivot_in(self) -> exp.In:
3582        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3583            this = self._parse_assignment()
3584
3585            self._match(TokenType.ALIAS)
3586            alias = self._parse_field()
3587            if alias:
3588                return self.expression(exp.PivotAlias, this=this, alias=alias)
3589
3590            return this
3591
3592        value = self._parse_column()
3593
3594        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3595            self.raise_error("Expecting IN (")
3596
3597        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3598
3599        self._match_r_paren()
3600        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3601
3602    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3603        index = self._index
3604        include_nulls = None
3605
3606        if self._match(TokenType.PIVOT):
3607            unpivot = False
3608        elif self._match(TokenType.UNPIVOT):
3609            unpivot = True
3610
3611            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3612            if self._match_text_seq("INCLUDE", "NULLS"):
3613                include_nulls = True
3614            elif self._match_text_seq("EXCLUDE", "NULLS"):
3615                include_nulls = False
3616        else:
3617            return None
3618
3619        expressions = []
3620
3621        if not self._match(TokenType.L_PAREN):
3622            self._retreat(index)
3623            return None
3624
3625        if unpivot:
3626            expressions = self._parse_csv(self._parse_column)
3627        else:
3628            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3629
3630        if not expressions:
3631            self.raise_error("Failed to parse PIVOT's aggregation list")
3632
3633        if not self._match(TokenType.FOR):
3634            self.raise_error("Expecting FOR")
3635
3636        field = self._parse_pivot_in()
3637
3638        self._match_r_paren()
3639
3640        pivot = self.expression(
3641            exp.Pivot,
3642            expressions=expressions,
3643            field=field,
3644            unpivot=unpivot,
3645            include_nulls=include_nulls,
3646        )
3647
3648        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3649            pivot.set("alias", self._parse_table_alias())
3650
3651        if not unpivot:
3652            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3653
3654            columns: t.List[exp.Expression] = []
3655            for fld in pivot.args["field"].expressions:
3656                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3657                for name in names:
3658                    if self.PREFIXED_PIVOT_COLUMNS:
3659                        name = f"{name}_{field_name}" if name else field_name
3660                    else:
3661                        name = f"{field_name}_{name}" if name else field_name
3662
3663                    columns.append(exp.to_identifier(name))
3664
3665            pivot.set("columns", columns)
3666
3667        return pivot
3668
3669    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3670        return [agg.alias for agg in aggregations]
3671
3672    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3673        if not skip_where_token and not self._match(TokenType.PREWHERE):
3674            return None
3675
3676        return self.expression(
3677            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
3678        )
3679
3680    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3681        if not skip_where_token and not self._match(TokenType.WHERE):
3682            return None
3683
3684        return self.expression(
3685            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
3686        )
3687
3688    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3689        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3690            return None
3691
3692        elements: t.Dict[str, t.Any] = defaultdict(list)
3693
3694        if self._match(TokenType.ALL):
3695            elements["all"] = True
3696        elif self._match(TokenType.DISTINCT):
3697            elements["all"] = False
3698
3699        while True:
3700            expressions = self._parse_csv(
3701                lambda: None
3702                if self._match(TokenType.ROLLUP, advance=False)
3703                else self._parse_assignment()
3704            )
3705            if expressions:
3706                elements["expressions"].extend(expressions)
3707
3708            grouping_sets = self._parse_grouping_sets()
3709            if grouping_sets:
3710                elements["grouping_sets"].extend(grouping_sets)
3711
3712            rollup = None
3713            cube = None
3714            totals = None
3715
3716            index = self._index
3717            with_ = self._match(TokenType.WITH)
3718            if self._match(TokenType.ROLLUP):
3719                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3720                elements["rollup"].extend(ensure_list(rollup))
3721
3722            if self._match(TokenType.CUBE):
3723                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3724                elements["cube"].extend(ensure_list(cube))
3725
3726            if self._match_text_seq("TOTALS"):
3727                totals = True
3728                elements["totals"] = True  # type: ignore
3729
3730            if not (grouping_sets or rollup or cube or totals):
3731                if with_:
3732                    self._retreat(index)
3733                break
3734
3735        return self.expression(exp.Group, **elements)  # type: ignore
3736
3737    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3738        if not self._match(TokenType.GROUPING_SETS):
3739            return None
3740
3741        return self._parse_wrapped_csv(self._parse_grouping_set)
3742
3743    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3744        if self._match(TokenType.L_PAREN):
3745            grouping_set = self._parse_csv(self._parse_column)
3746            self._match_r_paren()
3747            return self.expression(exp.Tuple, expressions=grouping_set)
3748
3749        return self._parse_column()
3750
3751    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3752        if not skip_having_token and not self._match(TokenType.HAVING):
3753            return None
3754        return self.expression(exp.Having, this=self._parse_assignment())
3755
3756    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3757        if not self._match(TokenType.QUALIFY):
3758            return None
3759        return self.expression(exp.Qualify, this=self._parse_assignment())
3760
3761    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3762        if skip_start_token:
3763            start = None
3764        elif self._match(TokenType.START_WITH):
3765            start = self._parse_assignment()
3766        else:
3767            return None
3768
3769        self._match(TokenType.CONNECT_BY)
3770        nocycle = self._match_text_seq("NOCYCLE")
3771        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3772            exp.Prior, this=self._parse_bitwise()
3773        )
3774        connect = self._parse_assignment()
3775        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3776
3777        if not start and self._match(TokenType.START_WITH):
3778            start = self._parse_assignment()
3779
3780        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3781
3782    def _parse_name_as_expression(self) -> exp.Alias:
3783        return self.expression(
3784            exp.Alias,
3785            alias=self._parse_id_var(any_token=True),
3786            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
3787        )
3788
3789    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3790        if self._match_text_seq("INTERPOLATE"):
3791            return self._parse_wrapped_csv(self._parse_name_as_expression)
3792        return None
3793
3794    def _parse_order(
3795        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3796    ) -> t.Optional[exp.Expression]:
3797        siblings = None
3798        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3799            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3800                return this
3801
3802            siblings = True
3803
3804        return self.expression(
3805            exp.Order,
3806            this=this,
3807            expressions=self._parse_csv(self._parse_ordered),
3808            interpolate=self._parse_interpolate(),
3809            siblings=siblings,
3810        )
3811
3812    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3813        if not self._match(token):
3814            return None
3815        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3816
3817    def _parse_ordered(
3818        self, parse_method: t.Optional[t.Callable] = None
3819    ) -> t.Optional[exp.Ordered]:
3820        this = parse_method() if parse_method else self._parse_assignment()
3821        if not this:
3822            return None
3823
3824        asc = self._match(TokenType.ASC)
3825        desc = self._match(TokenType.DESC) or (asc and False)
3826
3827        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3828        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3829
3830        nulls_first = is_nulls_first or False
3831        explicitly_null_ordered = is_nulls_first or is_nulls_last
3832
3833        if (
3834            not explicitly_null_ordered
3835            and (
3836                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3837                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3838            )
3839            and self.dialect.NULL_ORDERING != "nulls_are_last"
3840        ):
3841            nulls_first = True
3842
3843        if self._match_text_seq("WITH", "FILL"):
3844            with_fill = self.expression(
3845                exp.WithFill,
3846                **{  # type: ignore
3847                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3848                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3849                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3850                },
3851            )
3852        else:
3853            with_fill = None
3854
3855        return self.expression(
3856            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3857        )
3858
3859    def _parse_limit(
3860        self,
3861        this: t.Optional[exp.Expression] = None,
3862        top: bool = False,
3863        skip_limit_token: bool = False,
3864    ) -> t.Optional[exp.Expression]:
3865        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3866            comments = self._prev_comments
3867            if top:
3868                limit_paren = self._match(TokenType.L_PAREN)
3869                expression = self._parse_term() if limit_paren else self._parse_number()
3870
3871                if limit_paren:
3872                    self._match_r_paren()
3873            else:
3874                expression = self._parse_term()
3875
3876            if self._match(TokenType.COMMA):
3877                offset = expression
3878                expression = self._parse_term()
3879            else:
3880                offset = None
3881
3882            limit_exp = self.expression(
3883                exp.Limit,
3884                this=this,
3885                expression=expression,
3886                offset=offset,
3887                comments=comments,
3888                expressions=self._parse_limit_by(),
3889            )
3890
3891            return limit_exp
3892
3893        if self._match(TokenType.FETCH):
3894            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3895            direction = self._prev.text.upper() if direction else "FIRST"
3896
3897            count = self._parse_field(tokens=self.FETCH_TOKENS)
3898            percent = self._match(TokenType.PERCENT)
3899
3900            self._match_set((TokenType.ROW, TokenType.ROWS))
3901
3902            only = self._match_text_seq("ONLY")
3903            with_ties = self._match_text_seq("WITH", "TIES")
3904
3905            if only and with_ties:
3906                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3907
3908            return self.expression(
3909                exp.Fetch,
3910                direction=direction,
3911                count=count,
3912                percent=percent,
3913                with_ties=with_ties,
3914            )
3915
3916        return this
3917
3918    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3919        if not self._match(TokenType.OFFSET):
3920            return this
3921
3922        count = self._parse_term()
3923        self._match_set((TokenType.ROW, TokenType.ROWS))
3924
3925        return self.expression(
3926            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
3927        )
3928
3929    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
3930        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
3931
3932    def _parse_locks(self) -> t.List[exp.Lock]:
3933        locks = []
3934        while True:
3935            if self._match_text_seq("FOR", "UPDATE"):
3936                update = True
3937            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3938                "LOCK", "IN", "SHARE", "MODE"
3939            ):
3940                update = False
3941            else:
3942                break
3943
3944            expressions = None
3945            if self._match_text_seq("OF"):
3946                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3947
3948            wait: t.Optional[bool | exp.Expression] = None
3949            if self._match_text_seq("NOWAIT"):
3950                wait = True
3951            elif self._match_text_seq("WAIT"):
3952                wait = self._parse_primary()
3953            elif self._match_text_seq("SKIP", "LOCKED"):
3954                wait = False
3955
3956            locks.append(
3957                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3958            )
3959
3960        return locks
3961
3962    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3963        while this and self._match_set(self.SET_OPERATIONS):
3964            token_type = self._prev.token_type
3965
3966            if token_type == TokenType.UNION:
3967                operation: t.Type[exp.SetOperation] = exp.Union
3968            elif token_type == TokenType.EXCEPT:
3969                operation = exp.Except
3970            else:
3971                operation = exp.Intersect
3972
3973            comments = self._prev.comments
3974            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3975            by_name = self._match_text_seq("BY", "NAME")
3976            expression = self._parse_select(nested=True, parse_set_operation=False)
3977
3978            this = self.expression(
3979                operation,
3980                comments=comments,
3981                this=this,
3982                distinct=distinct,
3983                by_name=by_name,
3984                expression=expression,
3985            )
3986
3987        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
3988            expression = this.expression
3989
3990            if expression:
3991                for arg in self.SET_OP_MODIFIERS:
3992                    expr = expression.args.get(arg)
3993                    if expr:
3994                        this.set(arg, expr.pop())
3995
3996        return this
3997
3998    def _parse_expression(self) -> t.Optional[exp.Expression]:
3999        return self._parse_alias(self._parse_assignment())
4000
4001    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4002        this = self._parse_disjunction()
4003
4004        while self._match_set(self.ASSIGNMENT):
4005            this = self.expression(
4006                self.ASSIGNMENT[self._prev.token_type],
4007                this=this,
4008                comments=self._prev_comments,
4009                expression=self._parse_assignment(),
4010            )
4011
4012        return this
4013
4014    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4015        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4016
4017    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4018        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4019
4020    def _parse_equality(self) -> t.Optional[exp.Expression]:
4021        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4022
4023    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4024        return self._parse_tokens(self._parse_range, self.COMPARISON)
4025
4026    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4027        this = this or self._parse_bitwise()
4028        negate = self._match(TokenType.NOT)
4029
4030        if self._match_set(self.RANGE_PARSERS):
4031            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4032            if not expression:
4033                return this
4034
4035            this = expression
4036        elif self._match(TokenType.ISNULL):
4037            this = self.expression(exp.Is, this=this, expression=exp.Null())
4038
4039        # Postgres supports ISNULL and NOTNULL for conditions.
4040        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4041        if self._match(TokenType.NOTNULL):
4042            this = self.expression(exp.Is, this=this, expression=exp.Null())
4043            this = self.expression(exp.Not, this=this)
4044
4045        if negate:
4046            this = self.expression(exp.Not, this=this)
4047
4048        if self._match(TokenType.IS):
4049            this = self._parse_is(this)
4050
4051        return this
4052
4053    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4054        index = self._index - 1
4055        negate = self._match(TokenType.NOT)
4056
4057        if self._match_text_seq("DISTINCT", "FROM"):
4058            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4059            return self.expression(klass, this=this, expression=self._parse_bitwise())
4060
4061        expression = self._parse_null() or self._parse_boolean()
4062        if not expression:
4063            self._retreat(index)
4064            return None
4065
4066        this = self.expression(exp.Is, this=this, expression=expression)
4067        return self.expression(exp.Not, this=this) if negate else this
4068
4069    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4070        unnest = self._parse_unnest(with_alias=False)
4071        if unnest:
4072            this = self.expression(exp.In, this=this, unnest=unnest)
4073        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4074            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4075            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4076
4077            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4078                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4079            else:
4080                this = self.expression(exp.In, this=this, expressions=expressions)
4081
4082            if matched_l_paren:
4083                self._match_r_paren(this)
4084            elif not self._match(TokenType.R_BRACKET, expression=this):
4085                self.raise_error("Expecting ]")
4086        else:
4087            this = self.expression(exp.In, this=this, field=self._parse_field())
4088
4089        return this
4090
4091    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4092        low = self._parse_bitwise()
4093        self._match(TokenType.AND)
4094        high = self._parse_bitwise()
4095        return self.expression(exp.Between, this=this, low=low, high=high)
4096
4097    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4098        if not self._match(TokenType.ESCAPE):
4099            return this
4100        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4101
4102    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4103        index = self._index
4104
4105        if not self._match(TokenType.INTERVAL) and match_interval:
4106            return None
4107
4108        if self._match(TokenType.STRING, advance=False):
4109            this = self._parse_primary()
4110        else:
4111            this = self._parse_term()
4112
4113        if not this or (
4114            isinstance(this, exp.Column)
4115            and not this.table
4116            and not this.this.quoted
4117            and this.name.upper() == "IS"
4118        ):
4119            self._retreat(index)
4120            return None
4121
4122        unit = self._parse_function() or (
4123            not self._match(TokenType.ALIAS, advance=False)
4124            and self._parse_var(any_token=True, upper=True)
4125        )
4126
4127        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4128        # each INTERVAL expression into this canonical form so it's easy to transpile
4129        if this and this.is_number:
4130            this = exp.Literal.string(this.name)
4131        elif this and this.is_string:
4132            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4133            if len(parts) == 1:
4134                if unit:
4135                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4136                    self._retreat(self._index - 1)
4137
4138                this = exp.Literal.string(parts[0][0])
4139                unit = self.expression(exp.Var, this=parts[0][1].upper())
4140
4141        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4142            unit = self.expression(
4143                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4144            )
4145
4146        interval = self.expression(exp.Interval, this=this, unit=unit)
4147
4148        index = self._index
4149        self._match(TokenType.PLUS)
4150
4151        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4152        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4153            return self.expression(
4154                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4155            )
4156
4157        self._retreat(index)
4158        return interval
4159
4160    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4161        this = self._parse_term()
4162
4163        while True:
4164            if self._match_set(self.BITWISE):
4165                this = self.expression(
4166                    self.BITWISE[self._prev.token_type],
4167                    this=this,
4168                    expression=self._parse_term(),
4169                )
4170            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4171                this = self.expression(
4172                    exp.DPipe,
4173                    this=this,
4174                    expression=self._parse_term(),
4175                    safe=not self.dialect.STRICT_STRING_CONCAT,
4176                )
4177            elif self._match(TokenType.DQMARK):
4178                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
4179            elif self._match_pair(TokenType.LT, TokenType.LT):
4180                this = self.expression(
4181                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4182                )
4183            elif self._match_pair(TokenType.GT, TokenType.GT):
4184                this = self.expression(
4185                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4186                )
4187            else:
4188                break
4189
4190        return this
4191
4192    def _parse_term(self) -> t.Optional[exp.Expression]:
4193        return self._parse_tokens(self._parse_factor, self.TERM)
4194
4195    def _parse_factor(self) -> t.Optional[exp.Expression]:
4196        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4197        this = parse_method()
4198
4199        while self._match_set(self.FACTOR):
4200            klass = self.FACTOR[self._prev.token_type]
4201            comments = self._prev_comments
4202            expression = parse_method()
4203
4204            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4205                self._retreat(self._index - 1)
4206                return this
4207
4208            this = self.expression(klass, this=this, comments=comments, expression=expression)
4209
4210            if isinstance(this, exp.Div):
4211                this.args["typed"] = self.dialect.TYPED_DIVISION
4212                this.args["safe"] = self.dialect.SAFE_DIVISION
4213
4214        return this
4215
4216    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4217        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4218
4219    def _parse_unary(self) -> t.Optional[exp.Expression]:
4220        if self._match_set(self.UNARY_PARSERS):
4221            return self.UNARY_PARSERS[self._prev.token_type](self)
4222        return self._parse_at_time_zone(self._parse_type())
4223
4224    def _parse_type(
4225        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4226    ) -> t.Optional[exp.Expression]:
4227        interval = parse_interval and self._parse_interval()
4228        if interval:
4229            return interval
4230
4231        index = self._index
4232        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4233
4234        if data_type:
4235            index2 = self._index
4236            this = self._parse_primary()
4237
4238            if isinstance(this, exp.Literal):
4239                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4240                if parser:
4241                    return parser(self, this, data_type)
4242
4243                return self.expression(exp.Cast, this=this, to=data_type)
4244
4245            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4246            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4247            #
4248            # If the index difference here is greater than 1, that means the parser itself must have
4249            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4250            #
4251            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4252            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4253            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4254            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4255            #
4256            # In these cases, we don't really want to return the converted type, but instead retreat
4257            # and try to parse a Column or Identifier in the section below.
4258            if data_type.expressions and index2 - index > 1:
4259                self._retreat(index2)
4260                return self._parse_column_ops(data_type)
4261
4262            self._retreat(index)
4263
4264        if fallback_to_identifier:
4265            return self._parse_id_var()
4266
4267        this = self._parse_column()
4268        return this and self._parse_column_ops(this)
4269
4270    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4271        this = self._parse_type()
4272        if not this:
4273            return None
4274
4275        if isinstance(this, exp.Column) and not this.table:
4276            this = exp.var(this.name.upper())
4277
4278        return self.expression(
4279            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4280        )
4281
4282    def _parse_types(
4283        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4284    ) -> t.Optional[exp.Expression]:
4285        index = self._index
4286
4287        this: t.Optional[exp.Expression] = None
4288        prefix = self._match_text_seq("SYSUDTLIB", ".")
4289
4290        if not self._match_set(self.TYPE_TOKENS):
4291            identifier = allow_identifiers and self._parse_id_var(
4292                any_token=False, tokens=(TokenType.VAR,)
4293            )
4294            if identifier:
4295                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4296
4297                if len(tokens) != 1:
4298                    self.raise_error("Unexpected identifier", self._prev)
4299
4300                if tokens[0].token_type in self.TYPE_TOKENS:
4301                    self._prev = tokens[0]
4302                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4303                    type_name = identifier.name
4304
4305                    while self._match(TokenType.DOT):
4306                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4307
4308                    this = exp.DataType.build(type_name, udt=True)
4309                else:
4310                    self._retreat(self._index - 1)
4311                    return None
4312            else:
4313                return None
4314
4315        type_token = self._prev.token_type
4316
4317        if type_token == TokenType.PSEUDO_TYPE:
4318            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4319
4320        if type_token == TokenType.OBJECT_IDENTIFIER:
4321            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4322
4323        # https://materialize.com/docs/sql/types/map/
4324        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4325            key_type = self._parse_types(
4326                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4327            )
4328            if not self._match(TokenType.FARROW):
4329                self._retreat(index)
4330                return None
4331
4332            value_type = self._parse_types(
4333                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4334            )
4335            if not self._match(TokenType.R_BRACKET):
4336                self._retreat(index)
4337                return None
4338
4339            return exp.DataType(
4340                this=exp.DataType.Type.MAP,
4341                expressions=[key_type, value_type],
4342                nested=True,
4343                prefix=prefix,
4344            )
4345
4346        nested = type_token in self.NESTED_TYPE_TOKENS
4347        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4348        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4349        expressions = None
4350        maybe_func = False
4351
4352        if self._match(TokenType.L_PAREN):
4353            if is_struct:
4354                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4355            elif nested:
4356                expressions = self._parse_csv(
4357                    lambda: self._parse_types(
4358                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4359                    )
4360                )
4361            elif type_token in self.ENUM_TYPE_TOKENS:
4362                expressions = self._parse_csv(self._parse_equality)
4363            elif is_aggregate:
4364                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4365                    any_token=False, tokens=(TokenType.VAR,)
4366                )
4367                if not func_or_ident or not self._match(TokenType.COMMA):
4368                    return None
4369                expressions = self._parse_csv(
4370                    lambda: self._parse_types(
4371                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4372                    )
4373                )
4374                expressions.insert(0, func_or_ident)
4375            else:
4376                expressions = self._parse_csv(self._parse_type_size)
4377
4378            if not expressions or not self._match(TokenType.R_PAREN):
4379                self._retreat(index)
4380                return None
4381
4382            maybe_func = True
4383
4384        values: t.Optional[t.List[exp.Expression]] = None
4385
4386        if nested and self._match(TokenType.LT):
4387            if is_struct:
4388                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4389            else:
4390                expressions = self._parse_csv(
4391                    lambda: self._parse_types(
4392                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4393                    )
4394                )
4395
4396            if not self._match(TokenType.GT):
4397                self.raise_error("Expecting >")
4398
4399            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4400                values = self._parse_csv(self._parse_assignment)
4401                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4402
4403        if type_token in self.TIMESTAMPS:
4404            if self._match_text_seq("WITH", "TIME", "ZONE"):
4405                maybe_func = False
4406                tz_type = (
4407                    exp.DataType.Type.TIMETZ
4408                    if type_token in self.TIMES
4409                    else exp.DataType.Type.TIMESTAMPTZ
4410                )
4411                this = exp.DataType(this=tz_type, expressions=expressions)
4412            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4413                maybe_func = False
4414                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4415            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4416                maybe_func = False
4417        elif type_token == TokenType.INTERVAL:
4418            unit = self._parse_var(upper=True)
4419            if unit:
4420                if self._match_text_seq("TO"):
4421                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4422
4423                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4424            else:
4425                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4426
4427        if maybe_func and check_func:
4428            index2 = self._index
4429            peek = self._parse_string()
4430
4431            if not peek:
4432                self._retreat(index)
4433                return None
4434
4435            self._retreat(index2)
4436
4437        if not this:
4438            if self._match_text_seq("UNSIGNED"):
4439                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4440                if not unsigned_type_token:
4441                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4442
4443                type_token = unsigned_type_token or type_token
4444
4445            this = exp.DataType(
4446                this=exp.DataType.Type[type_token.value],
4447                expressions=expressions,
4448                nested=nested,
4449                values=values,
4450                prefix=prefix,
4451            )
4452        elif expressions:
4453            this.set("expressions", expressions)
4454
4455        # https://materialize.com/docs/sql/types/list/#type-name
4456        while self._match(TokenType.LIST):
4457            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4458
4459        index = self._index
4460
4461        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4462        matched_array = self._match(TokenType.ARRAY)
4463
4464        while self._curr:
4465            matched_l_bracket = self._match(TokenType.L_BRACKET)
4466            if not matched_l_bracket and not matched_array:
4467                break
4468
4469            matched_array = False
4470            values = self._parse_csv(self._parse_assignment) or None
4471            if values and not schema:
4472                self._retreat(index)
4473                break
4474
4475            this = exp.DataType(
4476                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4477            )
4478            self._match(TokenType.R_BRACKET)
4479
4480        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4481            converter = self.TYPE_CONVERTERS.get(this.this)
4482            if converter:
4483                this = converter(t.cast(exp.DataType, this))
4484
4485        return this
4486
4487    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4488        index = self._index
4489
4490        if (
4491            self._curr
4492            and self._next
4493            and self._curr.token_type in self.TYPE_TOKENS
4494            and self._next.token_type in self.TYPE_TOKENS
4495        ):
4496            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4497            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4498            this = self._parse_id_var()
4499        else:
4500            this = (
4501                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4502                or self._parse_id_var()
4503            )
4504
4505        self._match(TokenType.COLON)
4506
4507        if (
4508            type_required
4509            and not isinstance(this, exp.DataType)
4510            and not self._match_set(self.TYPE_TOKENS, advance=False)
4511        ):
4512            self._retreat(index)
4513            return self._parse_types()
4514
4515        return self._parse_column_def(this)
4516
4517    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4518        if not self._match_text_seq("AT", "TIME", "ZONE"):
4519            return this
4520        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4521
4522    def _parse_column(self) -> t.Optional[exp.Expression]:
4523        this = self._parse_column_reference()
4524        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
4525
4526        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
4527            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
4528
4529        return column
4530
4531    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4532        this = self._parse_field()
4533        if (
4534            not this
4535            and self._match(TokenType.VALUES, advance=False)
4536            and self.VALUES_FOLLOWED_BY_PAREN
4537            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4538        ):
4539            this = self._parse_id_var()
4540
4541        if isinstance(this, exp.Identifier):
4542            # We bubble up comments from the Identifier to the Column
4543            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4544
4545        return this
4546
4547    def _parse_colon_as_json_extract(
4548        self, this: t.Optional[exp.Expression]
4549    ) -> t.Optional[exp.Expression]:
4550        casts = []
4551        json_path = []
4552
4553        while self._match(TokenType.COLON):
4554            start_index = self._index
4555
4556            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
4557            path = self._parse_column_ops(
4558                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
4559            )
4560
4561            # The cast :: operator has a lower precedence than the extraction operator :, so
4562            # we rearrange the AST appropriately to avoid casting the JSON path
4563            while isinstance(path, exp.Cast):
4564                casts.append(path.to)
4565                path = path.this
4566
4567            if casts:
4568                dcolon_offset = next(
4569                    i
4570                    for i, t in enumerate(self._tokens[start_index:])
4571                    if t.token_type == TokenType.DCOLON
4572                )
4573                end_token = self._tokens[start_index + dcolon_offset - 1]
4574            else:
4575                end_token = self._prev
4576
4577            if path:
4578                json_path.append(self._find_sql(self._tokens[start_index], end_token))
4579
4580        if json_path:
4581            this = self.expression(
4582                exp.JSONExtract,
4583                this=this,
4584                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
4585            )
4586
4587            while casts:
4588                this = self.expression(exp.Cast, this=this, to=casts.pop())
4589
4590        return this
4591
4592    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4593        this = self._parse_bracket(this)
4594
4595        while self._match_set(self.COLUMN_OPERATORS):
4596            op_token = self._prev.token_type
4597            op = self.COLUMN_OPERATORS.get(op_token)
4598
4599            if op_token == TokenType.DCOLON:
4600                field = self._parse_types()
4601                if not field:
4602                    self.raise_error("Expected type")
4603            elif op and self._curr:
4604                field = self._parse_column_reference()
4605            else:
4606                field = self._parse_field(any_token=True, anonymous_func=True)
4607
4608            if isinstance(field, exp.Func) and this:
4609                # bigquery allows function calls like x.y.count(...)
4610                # SAFE.SUBSTR(...)
4611                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4612                this = exp.replace_tree(
4613                    this,
4614                    lambda n: (
4615                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4616                        if n.table
4617                        else n.this
4618                    )
4619                    if isinstance(n, exp.Column)
4620                    else n,
4621                )
4622
4623            if op:
4624                this = op(self, this, field)
4625            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4626                this = self.expression(
4627                    exp.Column,
4628                    this=field,
4629                    table=this.this,
4630                    db=this.args.get("table"),
4631                    catalog=this.args.get("db"),
4632                )
4633            else:
4634                this = self.expression(exp.Dot, this=this, expression=field)
4635
4636            this = self._parse_bracket(this)
4637
4638        return self._parse_colon_as_json_extract(this) if self.COLON_IS_JSON_EXTRACT else this
4639
4640    def _parse_primary(self) -> t.Optional[exp.Expression]:
4641        if self._match_set(self.PRIMARY_PARSERS):
4642            token_type = self._prev.token_type
4643            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4644
4645            if token_type == TokenType.STRING:
4646                expressions = [primary]
4647                while self._match(TokenType.STRING):
4648                    expressions.append(exp.Literal.string(self._prev.text))
4649
4650                if len(expressions) > 1:
4651                    return self.expression(exp.Concat, expressions=expressions)
4652
4653            return primary
4654
4655        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4656            return exp.Literal.number(f"0.{self._prev.text}")
4657
4658        if self._match(TokenType.L_PAREN):
4659            comments = self._prev_comments
4660            query = self._parse_select()
4661
4662            if query:
4663                expressions = [query]
4664            else:
4665                expressions = self._parse_expressions()
4666
4667            this = self._parse_query_modifiers(seq_get(expressions, 0))
4668
4669            if not this and self._match(TokenType.R_PAREN, advance=False):
4670                this = self.expression(exp.Tuple)
4671            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4672                this = self._parse_subquery(this=this, parse_alias=False)
4673            elif isinstance(this, exp.Subquery):
4674                this = self._parse_subquery(
4675                    this=self._parse_set_operations(this), parse_alias=False
4676                )
4677            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4678                this = self.expression(exp.Tuple, expressions=expressions)
4679            else:
4680                this = self.expression(exp.Paren, this=this)
4681
4682            if this:
4683                this.add_comments(comments)
4684
4685            self._match_r_paren(expression=this)
4686            return this
4687
4688        return None
4689
4690    def _parse_field(
4691        self,
4692        any_token: bool = False,
4693        tokens: t.Optional[t.Collection[TokenType]] = None,
4694        anonymous_func: bool = False,
4695    ) -> t.Optional[exp.Expression]:
4696        if anonymous_func:
4697            field = (
4698                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4699                or self._parse_primary()
4700            )
4701        else:
4702            field = self._parse_primary() or self._parse_function(
4703                anonymous=anonymous_func, any_token=any_token
4704            )
4705        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4706
4707    def _parse_function(
4708        self,
4709        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4710        anonymous: bool = False,
4711        optional_parens: bool = True,
4712        any_token: bool = False,
4713    ) -> t.Optional[exp.Expression]:
4714        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4715        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4716        fn_syntax = False
4717        if (
4718            self._match(TokenType.L_BRACE, advance=False)
4719            and self._next
4720            and self._next.text.upper() == "FN"
4721        ):
4722            self._advance(2)
4723            fn_syntax = True
4724
4725        func = self._parse_function_call(
4726            functions=functions,
4727            anonymous=anonymous,
4728            optional_parens=optional_parens,
4729            any_token=any_token,
4730        )
4731
4732        if fn_syntax:
4733            self._match(TokenType.R_BRACE)
4734
4735        return func
4736
4737    def _parse_function_call(
4738        self,
4739        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4740        anonymous: bool = False,
4741        optional_parens: bool = True,
4742        any_token: bool = False,
4743    ) -> t.Optional[exp.Expression]:
4744        if not self._curr:
4745            return None
4746
4747        comments = self._curr.comments
4748        token_type = self._curr.token_type
4749        this = self._curr.text
4750        upper = this.upper()
4751
4752        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4753        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4754            self._advance()
4755            return self._parse_window(parser(self))
4756
4757        if not self._next or self._next.token_type != TokenType.L_PAREN:
4758            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4759                self._advance()
4760                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4761
4762            return None
4763
4764        if any_token:
4765            if token_type in self.RESERVED_TOKENS:
4766                return None
4767        elif token_type not in self.FUNC_TOKENS:
4768            return None
4769
4770        self._advance(2)
4771
4772        parser = self.FUNCTION_PARSERS.get(upper)
4773        if parser and not anonymous:
4774            this = parser(self)
4775        else:
4776            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4777
4778            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4779                this = self.expression(subquery_predicate, this=self._parse_select())
4780                self._match_r_paren()
4781                return this
4782
4783            if functions is None:
4784                functions = self.FUNCTIONS
4785
4786            function = functions.get(upper)
4787
4788            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4789            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4790
4791            if alias:
4792                args = self._kv_to_prop_eq(args)
4793
4794            if function and not anonymous:
4795                if "dialect" in function.__code__.co_varnames:
4796                    func = function(args, dialect=self.dialect)
4797                else:
4798                    func = function(args)
4799
4800                func = self.validate_expression(func, args)
4801                if not self.dialect.NORMALIZE_FUNCTIONS:
4802                    func.meta["name"] = this
4803
4804                this = func
4805            else:
4806                if token_type == TokenType.IDENTIFIER:
4807                    this = exp.Identifier(this=this, quoted=True)
4808                this = self.expression(exp.Anonymous, this=this, expressions=args)
4809
4810        if isinstance(this, exp.Expression):
4811            this.add_comments(comments)
4812
4813        self._match_r_paren(this)
4814        return self._parse_window(this)
4815
4816    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4817        transformed = []
4818
4819        for e in expressions:
4820            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4821                if isinstance(e, exp.Alias):
4822                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4823
4824                if not isinstance(e, exp.PropertyEQ):
4825                    e = self.expression(
4826                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4827                    )
4828
4829                if isinstance(e.this, exp.Column):
4830                    e.this.replace(e.this.this)
4831
4832            transformed.append(e)
4833
4834        return transformed
4835
4836    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4837        return self._parse_column_def(self._parse_id_var())
4838
4839    def _parse_user_defined_function(
4840        self, kind: t.Optional[TokenType] = None
4841    ) -> t.Optional[exp.Expression]:
4842        this = self._parse_id_var()
4843
4844        while self._match(TokenType.DOT):
4845            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4846
4847        if not self._match(TokenType.L_PAREN):
4848            return this
4849
4850        expressions = self._parse_csv(self._parse_function_parameter)
4851        self._match_r_paren()
4852        return self.expression(
4853            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4854        )
4855
4856    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4857        literal = self._parse_primary()
4858        if literal:
4859            return self.expression(exp.Introducer, this=token.text, expression=literal)
4860
4861        return self.expression(exp.Identifier, this=token.text)
4862
4863    def _parse_session_parameter(self) -> exp.SessionParameter:
4864        kind = None
4865        this = self._parse_id_var() or self._parse_primary()
4866
4867        if this and self._match(TokenType.DOT):
4868            kind = this.name
4869            this = self._parse_var() or self._parse_primary()
4870
4871        return self.expression(exp.SessionParameter, this=this, kind=kind)
4872
4873    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
4874        return self._parse_id_var()
4875
4876    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4877        index = self._index
4878
4879        if self._match(TokenType.L_PAREN):
4880            expressions = t.cast(
4881                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
4882            )
4883
4884            if not self._match(TokenType.R_PAREN):
4885                self._retreat(index)
4886        else:
4887            expressions = [self._parse_lambda_arg()]
4888
4889        if self._match_set(self.LAMBDAS):
4890            return self.LAMBDAS[self._prev.token_type](self, expressions)
4891
4892        self._retreat(index)
4893
4894        this: t.Optional[exp.Expression]
4895
4896        if self._match(TokenType.DISTINCT):
4897            this = self.expression(
4898                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
4899            )
4900        else:
4901            this = self._parse_select_or_expression(alias=alias)
4902
4903        return self._parse_limit(
4904            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
4905        )
4906
4907    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4908        index = self._index
4909        if not self._match(TokenType.L_PAREN):
4910            return this
4911
4912        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
4913        # expr can be of both types
4914        if self._match_set(self.SELECT_START_TOKENS):
4915            self._retreat(index)
4916            return this
4917        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4918        self._match_r_paren()
4919        return self.expression(exp.Schema, this=this, expressions=args)
4920
4921    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4922        return self._parse_column_def(self._parse_field(any_token=True))
4923
4924    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4925        # column defs are not really columns, they're identifiers
4926        if isinstance(this, exp.Column):
4927            this = this.this
4928
4929        kind = self._parse_types(schema=True)
4930
4931        if self._match_text_seq("FOR", "ORDINALITY"):
4932            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4933
4934        constraints: t.List[exp.Expression] = []
4935
4936        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
4937            ("ALIAS", "MATERIALIZED")
4938        ):
4939            persisted = self._prev.text.upper() == "MATERIALIZED"
4940            constraints.append(
4941                self.expression(
4942                    exp.ComputedColumnConstraint,
4943                    this=self._parse_assignment(),
4944                    persisted=persisted or self._match_text_seq("PERSISTED"),
4945                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4946                )
4947            )
4948        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4949            self._match(TokenType.ALIAS)
4950            constraints.append(
4951                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4952            )
4953
4954        while True:
4955            constraint = self._parse_column_constraint()
4956            if not constraint:
4957                break
4958            constraints.append(constraint)
4959
4960        if not kind and not constraints:
4961            return this
4962
4963        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4964
4965    def _parse_auto_increment(
4966        self,
4967    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4968        start = None
4969        increment = None
4970
4971        if self._match(TokenType.L_PAREN, advance=False):
4972            args = self._parse_wrapped_csv(self._parse_bitwise)
4973            start = seq_get(args, 0)
4974            increment = seq_get(args, 1)
4975        elif self._match_text_seq("START"):
4976            start = self._parse_bitwise()
4977            self._match_text_seq("INCREMENT")
4978            increment = self._parse_bitwise()
4979
4980        if start and increment:
4981            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4982
4983        return exp.AutoIncrementColumnConstraint()
4984
4985    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4986        if not self._match_text_seq("REFRESH"):
4987            self._retreat(self._index - 1)
4988            return None
4989        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4990
4991    def _parse_compress(self) -> exp.CompressColumnConstraint:
4992        if self._match(TokenType.L_PAREN, advance=False):
4993            return self.expression(
4994                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4995            )
4996
4997        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4998
4999    def _parse_generated_as_identity(
5000        self,
5001    ) -> (
5002        exp.GeneratedAsIdentityColumnConstraint
5003        | exp.ComputedColumnConstraint
5004        | exp.GeneratedAsRowColumnConstraint
5005    ):
5006        if self._match_text_seq("BY", "DEFAULT"):
5007            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5008            this = self.expression(
5009                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5010            )
5011        else:
5012            self._match_text_seq("ALWAYS")
5013            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5014
5015        self._match(TokenType.ALIAS)
5016
5017        if self._match_text_seq("ROW"):
5018            start = self._match_text_seq("START")
5019            if not start:
5020                self._match(TokenType.END)
5021            hidden = self._match_text_seq("HIDDEN")
5022            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5023
5024        identity = self._match_text_seq("IDENTITY")
5025
5026        if self._match(TokenType.L_PAREN):
5027            if self._match(TokenType.START_WITH):
5028                this.set("start", self._parse_bitwise())
5029            if self._match_text_seq("INCREMENT", "BY"):
5030                this.set("increment", self._parse_bitwise())
5031            if self._match_text_seq("MINVALUE"):
5032                this.set("minvalue", self._parse_bitwise())
5033            if self._match_text_seq("MAXVALUE"):
5034                this.set("maxvalue", self._parse_bitwise())
5035
5036            if self._match_text_seq("CYCLE"):
5037                this.set("cycle", True)
5038            elif self._match_text_seq("NO", "CYCLE"):
5039                this.set("cycle", False)
5040
5041            if not identity:
5042                this.set("expression", self._parse_range())
5043            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5044                args = self._parse_csv(self._parse_bitwise)
5045                this.set("start", seq_get(args, 0))
5046                this.set("increment", seq_get(args, 1))
5047
5048            self._match_r_paren()
5049
5050        return this
5051
5052    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5053        self._match_text_seq("LENGTH")
5054        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5055
5056    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5057        if self._match_text_seq("NULL"):
5058            return self.expression(exp.NotNullColumnConstraint)
5059        if self._match_text_seq("CASESPECIFIC"):
5060            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5061        if self._match_text_seq("FOR", "REPLICATION"):
5062            return self.expression(exp.NotForReplicationColumnConstraint)
5063        return None
5064
5065    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5066        if self._match(TokenType.CONSTRAINT):
5067            this = self._parse_id_var()
5068        else:
5069            this = None
5070
5071        if self._match_texts(self.CONSTRAINT_PARSERS):
5072            return self.expression(
5073                exp.ColumnConstraint,
5074                this=this,
5075                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5076            )
5077
5078        return this
5079
5080    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5081        if not self._match(TokenType.CONSTRAINT):
5082            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5083
5084        return self.expression(
5085            exp.Constraint,
5086            this=self._parse_id_var(),
5087            expressions=self._parse_unnamed_constraints(),
5088        )
5089
5090    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5091        constraints = []
5092        while True:
5093            constraint = self._parse_unnamed_constraint() or self._parse_function()
5094            if not constraint:
5095                break
5096            constraints.append(constraint)
5097
5098        return constraints
5099
5100    def _parse_unnamed_constraint(
5101        self, constraints: t.Optional[t.Collection[str]] = None
5102    ) -> t.Optional[exp.Expression]:
5103        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5104            constraints or self.CONSTRAINT_PARSERS
5105        ):
5106            return None
5107
5108        constraint = self._prev.text.upper()
5109        if constraint not in self.CONSTRAINT_PARSERS:
5110            self.raise_error(f"No parser found for schema constraint {constraint}.")
5111
5112        return self.CONSTRAINT_PARSERS[constraint](self)
5113
5114    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5115        self._match_text_seq("KEY")
5116        return self.expression(
5117            exp.UniqueColumnConstraint,
5118            this=self._parse_schema(self._parse_id_var(any_token=False)),
5119            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5120            on_conflict=self._parse_on_conflict(),
5121        )
5122
5123    def _parse_key_constraint_options(self) -> t.List[str]:
5124        options = []
5125        while True:
5126            if not self._curr:
5127                break
5128
5129            if self._match(TokenType.ON):
5130                action = None
5131                on = self._advance_any() and self._prev.text
5132
5133                if self._match_text_seq("NO", "ACTION"):
5134                    action = "NO ACTION"
5135                elif self._match_text_seq("CASCADE"):
5136                    action = "CASCADE"
5137                elif self._match_text_seq("RESTRICT"):
5138                    action = "RESTRICT"
5139                elif self._match_pair(TokenType.SET, TokenType.NULL):
5140                    action = "SET NULL"
5141                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5142                    action = "SET DEFAULT"
5143                else:
5144                    self.raise_error("Invalid key constraint")
5145
5146                options.append(f"ON {on} {action}")
5147            elif self._match_text_seq("NOT", "ENFORCED"):
5148                options.append("NOT ENFORCED")
5149            elif self._match_text_seq("DEFERRABLE"):
5150                options.append("DEFERRABLE")
5151            elif self._match_text_seq("INITIALLY", "DEFERRED"):
5152                options.append("INITIALLY DEFERRED")
5153            elif self._match_text_seq("NORELY"):
5154                options.append("NORELY")
5155            elif self._match_text_seq("MATCH", "FULL"):
5156                options.append("MATCH FULL")
5157            else:
5158                break
5159
5160        return options
5161
5162    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5163        if match and not self._match(TokenType.REFERENCES):
5164            return None
5165
5166        expressions = None
5167        this = self._parse_table(schema=True)
5168        options = self._parse_key_constraint_options()
5169        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5170
5171    def _parse_foreign_key(self) -> exp.ForeignKey:
5172        expressions = self._parse_wrapped_id_vars()
5173        reference = self._parse_references()
5174        options = {}
5175
5176        while self._match(TokenType.ON):
5177            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5178                self.raise_error("Expected DELETE or UPDATE")
5179
5180            kind = self._prev.text.lower()
5181
5182            if self._match_text_seq("NO", "ACTION"):
5183                action = "NO ACTION"
5184            elif self._match(TokenType.SET):
5185                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5186                action = "SET " + self._prev.text.upper()
5187            else:
5188                self._advance()
5189                action = self._prev.text.upper()
5190
5191            options[kind] = action
5192
5193        return self.expression(
5194            exp.ForeignKey,
5195            expressions=expressions,
5196            reference=reference,
5197            **options,  # type: ignore
5198        )
5199
5200    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5201        return self._parse_field()
5202
5203    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5204        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5205            self._retreat(self._index - 1)
5206            return None
5207
5208        id_vars = self._parse_wrapped_id_vars()
5209        return self.expression(
5210            exp.PeriodForSystemTimeConstraint,
5211            this=seq_get(id_vars, 0),
5212            expression=seq_get(id_vars, 1),
5213        )
5214
5215    def _parse_primary_key(
5216        self, wrapped_optional: bool = False, in_props: bool = False
5217    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5218        desc = (
5219            self._match_set((TokenType.ASC, TokenType.DESC))
5220            and self._prev.token_type == TokenType.DESC
5221        )
5222
5223        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5224            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5225
5226        expressions = self._parse_wrapped_csv(
5227            self._parse_primary_key_part, optional=wrapped_optional
5228        )
5229        options = self._parse_key_constraint_options()
5230        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5231
5232    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5233        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5234
5235    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5236        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5237            return this
5238
5239        bracket_kind = self._prev.token_type
5240        expressions = self._parse_csv(
5241            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5242        )
5243
5244        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5245            self.raise_error("Expected ]")
5246        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5247            self.raise_error("Expected }")
5248
5249        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5250        if bracket_kind == TokenType.L_BRACE:
5251            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5252        elif not this:
5253            this = self.expression(exp.Array, expressions=expressions)
5254        else:
5255            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5256            if constructor_type:
5257                return self.expression(constructor_type, expressions=expressions)
5258
5259            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5260            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5261
5262        self._add_comments(this)
5263        return self._parse_bracket(this)
5264
5265    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5266        if self._match(TokenType.COLON):
5267            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5268        return this
5269
5270    def _parse_case(self) -> t.Optional[exp.Expression]:
5271        ifs = []
5272        default = None
5273
5274        comments = self._prev_comments
5275        expression = self._parse_assignment()
5276
5277        while self._match(TokenType.WHEN):
5278            this = self._parse_assignment()
5279            self._match(TokenType.THEN)
5280            then = self._parse_assignment()
5281            ifs.append(self.expression(exp.If, this=this, true=then))
5282
5283        if self._match(TokenType.ELSE):
5284            default = self._parse_assignment()
5285
5286        if not self._match(TokenType.END):
5287            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5288                default = exp.column("interval")
5289            else:
5290                self.raise_error("Expected END after CASE", self._prev)
5291
5292        return self.expression(
5293            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5294        )
5295
5296    def _parse_if(self) -> t.Optional[exp.Expression]:
5297        if self._match(TokenType.L_PAREN):
5298            args = self._parse_csv(self._parse_assignment)
5299            this = self.validate_expression(exp.If.from_arg_list(args), args)
5300            self._match_r_paren()
5301        else:
5302            index = self._index - 1
5303
5304            if self.NO_PAREN_IF_COMMANDS and index == 0:
5305                return self._parse_as_command(self._prev)
5306
5307            condition = self._parse_assignment()
5308
5309            if not condition:
5310                self._retreat(index)
5311                return None
5312
5313            self._match(TokenType.THEN)
5314            true = self._parse_assignment()
5315            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5316            self._match(TokenType.END)
5317            this = self.expression(exp.If, this=condition, true=true, false=false)
5318
5319        return this
5320
5321    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5322        if not self._match_text_seq("VALUE", "FOR"):
5323            self._retreat(self._index - 1)
5324            return None
5325
5326        return self.expression(
5327            exp.NextValueFor,
5328            this=self._parse_column(),
5329            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5330        )
5331
5332    def _parse_extract(self) -> exp.Extract:
5333        this = self._parse_function() or self._parse_var() or self._parse_type()
5334
5335        if self._match(TokenType.FROM):
5336            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5337
5338        if not self._match(TokenType.COMMA):
5339            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5340
5341        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5342
5343    def _parse_gap_fill(self) -> exp.GapFill:
5344        self._match(TokenType.TABLE)
5345        this = self._parse_table()
5346
5347        self._match(TokenType.COMMA)
5348        args = [this, *self._parse_csv(self._parse_lambda)]
5349
5350        gap_fill = exp.GapFill.from_arg_list(args)
5351        return self.validate_expression(gap_fill, args)
5352
5353    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5354        this = self._parse_assignment()
5355
5356        if not self._match(TokenType.ALIAS):
5357            if self._match(TokenType.COMMA):
5358                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5359
5360            self.raise_error("Expected AS after CAST")
5361
5362        fmt = None
5363        to = self._parse_types()
5364
5365        if self._match(TokenType.FORMAT):
5366            fmt_string = self._parse_string()
5367            fmt = self._parse_at_time_zone(fmt_string)
5368
5369            if not to:
5370                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5371            if to.this in exp.DataType.TEMPORAL_TYPES:
5372                this = self.expression(
5373                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5374                    this=this,
5375                    format=exp.Literal.string(
5376                        format_time(
5377                            fmt_string.this if fmt_string else "",
5378                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5379                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5380                        )
5381                    ),
5382                )
5383
5384                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5385                    this.set("zone", fmt.args["zone"])
5386                return this
5387        elif not to:
5388            self.raise_error("Expected TYPE after CAST")
5389        elif isinstance(to, exp.Identifier):
5390            to = exp.DataType.build(to.name, udt=True)
5391        elif to.this == exp.DataType.Type.CHAR:
5392            if self._match(TokenType.CHARACTER_SET):
5393                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5394
5395        return self.expression(
5396            exp.Cast if strict else exp.TryCast,
5397            this=this,
5398            to=to,
5399            format=fmt,
5400            safe=safe,
5401            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5402        )
5403
5404    def _parse_string_agg(self) -> exp.Expression:
5405        if self._match(TokenType.DISTINCT):
5406            args: t.List[t.Optional[exp.Expression]] = [
5407                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5408            ]
5409            if self._match(TokenType.COMMA):
5410                args.extend(self._parse_csv(self._parse_assignment))
5411        else:
5412            args = self._parse_csv(self._parse_assignment)  # type: ignore
5413
5414        index = self._index
5415        if not self._match(TokenType.R_PAREN) and args:
5416            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5417            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5418            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5419            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5420
5421        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5422        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5423        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5424        if not self._match_text_seq("WITHIN", "GROUP"):
5425            self._retreat(index)
5426            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5427
5428        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5429        order = self._parse_order(this=seq_get(args, 0))
5430        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5431
5432    def _parse_convert(
5433        self, strict: bool, safe: t.Optional[bool] = None
5434    ) -> t.Optional[exp.Expression]:
5435        this = self._parse_bitwise()
5436
5437        if self._match(TokenType.USING):
5438            to: t.Optional[exp.Expression] = self.expression(
5439                exp.CharacterSet, this=self._parse_var()
5440            )
5441        elif self._match(TokenType.COMMA):
5442            to = self._parse_types()
5443        else:
5444            to = None
5445
5446        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5447
5448    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5449        """
5450        There are generally two variants of the DECODE function:
5451
5452        - DECODE(bin, charset)
5453        - DECODE(expression, search, result [, search, result] ... [, default])
5454
5455        The second variant will always be parsed into a CASE expression. Note that NULL
5456        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5457        instead of relying on pattern matching.
5458        """
5459        args = self._parse_csv(self._parse_assignment)
5460
5461        if len(args) < 3:
5462            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5463
5464        expression, *expressions = args
5465        if not expression:
5466            return None
5467
5468        ifs = []
5469        for search, result in zip(expressions[::2], expressions[1::2]):
5470            if not search or not result:
5471                return None
5472
5473            if isinstance(search, exp.Literal):
5474                ifs.append(
5475                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5476                )
5477            elif isinstance(search, exp.Null):
5478                ifs.append(
5479                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5480                )
5481            else:
5482                cond = exp.or_(
5483                    exp.EQ(this=expression.copy(), expression=search),
5484                    exp.and_(
5485                        exp.Is(this=expression.copy(), expression=exp.Null()),
5486                        exp.Is(this=search.copy(), expression=exp.Null()),
5487                        copy=False,
5488                    ),
5489                    copy=False,
5490                )
5491                ifs.append(exp.If(this=cond, true=result))
5492
5493        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5494
5495    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5496        self._match_text_seq("KEY")
5497        key = self._parse_column()
5498        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5499        self._match_text_seq("VALUE")
5500        value = self._parse_bitwise()
5501
5502        if not key and not value:
5503            return None
5504        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5505
5506    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5507        if not this or not self._match_text_seq("FORMAT", "JSON"):
5508            return this
5509
5510        return self.expression(exp.FormatJson, this=this)
5511
5512    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5513        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5514        for value in values:
5515            if self._match_text_seq(value, "ON", on):
5516                return f"{value} ON {on}"
5517
5518        return None
5519
5520    @t.overload
5521    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5522
5523    @t.overload
5524    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5525
5526    def _parse_json_object(self, agg=False):
5527        star = self._parse_star()
5528        expressions = (
5529            [star]
5530            if star
5531            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5532        )
5533        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5534
5535        unique_keys = None
5536        if self._match_text_seq("WITH", "UNIQUE"):
5537            unique_keys = True
5538        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5539            unique_keys = False
5540
5541        self._match_text_seq("KEYS")
5542
5543        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5544            self._parse_type()
5545        )
5546        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5547
5548        return self.expression(
5549            exp.JSONObjectAgg if agg else exp.JSONObject,
5550            expressions=expressions,
5551            null_handling=null_handling,
5552            unique_keys=unique_keys,
5553            return_type=return_type,
5554            encoding=encoding,
5555        )
5556
5557    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5558    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5559        if not self._match_text_seq("NESTED"):
5560            this = self._parse_id_var()
5561            kind = self._parse_types(allow_identifiers=False)
5562            nested = None
5563        else:
5564            this = None
5565            kind = None
5566            nested = True
5567
5568        path = self._match_text_seq("PATH") and self._parse_string()
5569        nested_schema = nested and self._parse_json_schema()
5570
5571        return self.expression(
5572            exp.JSONColumnDef,
5573            this=this,
5574            kind=kind,
5575            path=path,
5576            nested_schema=nested_schema,
5577        )
5578
5579    def _parse_json_schema(self) -> exp.JSONSchema:
5580        self._match_text_seq("COLUMNS")
5581        return self.expression(
5582            exp.JSONSchema,
5583            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5584        )
5585
5586    def _parse_json_table(self) -> exp.JSONTable:
5587        this = self._parse_format_json(self._parse_bitwise())
5588        path = self._match(TokenType.COMMA) and self._parse_string()
5589        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5590        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5591        schema = self._parse_json_schema()
5592
5593        return exp.JSONTable(
5594            this=this,
5595            schema=schema,
5596            path=path,
5597            error_handling=error_handling,
5598            empty_handling=empty_handling,
5599        )
5600
5601    def _parse_match_against(self) -> exp.MatchAgainst:
5602        expressions = self._parse_csv(self._parse_column)
5603
5604        self._match_text_seq(")", "AGAINST", "(")
5605
5606        this = self._parse_string()
5607
5608        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5609            modifier = "IN NATURAL LANGUAGE MODE"
5610            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5611                modifier = f"{modifier} WITH QUERY EXPANSION"
5612        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5613            modifier = "IN BOOLEAN MODE"
5614        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5615            modifier = "WITH QUERY EXPANSION"
5616        else:
5617            modifier = None
5618
5619        return self.expression(
5620            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5621        )
5622
5623    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5624    def _parse_open_json(self) -> exp.OpenJSON:
5625        this = self._parse_bitwise()
5626        path = self._match(TokenType.COMMA) and self._parse_string()
5627
5628        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5629            this = self._parse_field(any_token=True)
5630            kind = self._parse_types()
5631            path = self._parse_string()
5632            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5633
5634            return self.expression(
5635                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5636            )
5637
5638        expressions = None
5639        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5640            self._match_l_paren()
5641            expressions = self._parse_csv(_parse_open_json_column_def)
5642
5643        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5644
5645    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5646        args = self._parse_csv(self._parse_bitwise)
5647
5648        if self._match(TokenType.IN):
5649            return self.expression(
5650                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5651            )
5652
5653        if haystack_first:
5654            haystack = seq_get(args, 0)
5655            needle = seq_get(args, 1)
5656        else:
5657            needle = seq_get(args, 0)
5658            haystack = seq_get(args, 1)
5659
5660        return self.expression(
5661            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5662        )
5663
5664    def _parse_predict(self) -> exp.Predict:
5665        self._match_text_seq("MODEL")
5666        this = self._parse_table()
5667
5668        self._match(TokenType.COMMA)
5669        self._match_text_seq("TABLE")
5670
5671        return self.expression(
5672            exp.Predict,
5673            this=this,
5674            expression=self._parse_table(),
5675            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5676        )
5677
5678    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5679        args = self._parse_csv(self._parse_table)
5680        return exp.JoinHint(this=func_name.upper(), expressions=args)
5681
5682    def _parse_substring(self) -> exp.Substring:
5683        # Postgres supports the form: substring(string [from int] [for int])
5684        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5685
5686        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5687
5688        if self._match(TokenType.FROM):
5689            args.append(self._parse_bitwise())
5690        if self._match(TokenType.FOR):
5691            if len(args) == 1:
5692                args.append(exp.Literal.number(1))
5693            args.append(self._parse_bitwise())
5694
5695        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5696
5697    def _parse_trim(self) -> exp.Trim:
5698        # https://www.w3resource.com/sql/character-functions/trim.php
5699        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5700
5701        position = None
5702        collation = None
5703        expression = None
5704
5705        if self._match_texts(self.TRIM_TYPES):
5706            position = self._prev.text.upper()
5707
5708        this = self._parse_bitwise()
5709        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5710            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5711            expression = self._parse_bitwise()
5712
5713            if invert_order:
5714                this, expression = expression, this
5715
5716        if self._match(TokenType.COLLATE):
5717            collation = self._parse_bitwise()
5718
5719        return self.expression(
5720            exp.Trim, this=this, position=position, expression=expression, collation=collation
5721        )
5722
5723    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5724        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5725
5726    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5727        return self._parse_window(self._parse_id_var(), alias=True)
5728
5729    def _parse_respect_or_ignore_nulls(
5730        self, this: t.Optional[exp.Expression]
5731    ) -> t.Optional[exp.Expression]:
5732        if self._match_text_seq("IGNORE", "NULLS"):
5733            return self.expression(exp.IgnoreNulls, this=this)
5734        if self._match_text_seq("RESPECT", "NULLS"):
5735            return self.expression(exp.RespectNulls, this=this)
5736        return this
5737
5738    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5739        if self._match(TokenType.HAVING):
5740            self._match_texts(("MAX", "MIN"))
5741            max = self._prev.text.upper() != "MIN"
5742            return self.expression(
5743                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5744            )
5745
5746        return this
5747
5748    def _parse_window(
5749        self, this: t.Optional[exp.Expression], alias: bool = False
5750    ) -> t.Optional[exp.Expression]:
5751        func = this
5752        comments = func.comments if isinstance(func, exp.Expression) else None
5753
5754        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5755            self._match(TokenType.WHERE)
5756            this = self.expression(
5757                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5758            )
5759            self._match_r_paren()
5760
5761        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5762        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5763        if self._match_text_seq("WITHIN", "GROUP"):
5764            order = self._parse_wrapped(self._parse_order)
5765            this = self.expression(exp.WithinGroup, this=this, expression=order)
5766
5767        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5768        # Some dialects choose to implement and some do not.
5769        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5770
5771        # There is some code above in _parse_lambda that handles
5772        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5773
5774        # The below changes handle
5775        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5776
5777        # Oracle allows both formats
5778        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5779        #   and Snowflake chose to do the same for familiarity
5780        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5781        if isinstance(this, exp.AggFunc):
5782            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5783
5784            if ignore_respect and ignore_respect is not this:
5785                ignore_respect.replace(ignore_respect.this)
5786                this = self.expression(ignore_respect.__class__, this=this)
5787
5788        this = self._parse_respect_or_ignore_nulls(this)
5789
5790        # bigquery select from window x AS (partition by ...)
5791        if alias:
5792            over = None
5793            self._match(TokenType.ALIAS)
5794        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5795            return this
5796        else:
5797            over = self._prev.text.upper()
5798
5799        if comments and isinstance(func, exp.Expression):
5800            func.pop_comments()
5801
5802        if not self._match(TokenType.L_PAREN):
5803            return self.expression(
5804                exp.Window,
5805                comments=comments,
5806                this=this,
5807                alias=self._parse_id_var(False),
5808                over=over,
5809            )
5810
5811        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5812
5813        first = self._match(TokenType.FIRST)
5814        if self._match_text_seq("LAST"):
5815            first = False
5816
5817        partition, order = self._parse_partition_and_order()
5818        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5819
5820        if kind:
5821            self._match(TokenType.BETWEEN)
5822            start = self._parse_window_spec()
5823            self._match(TokenType.AND)
5824            end = self._parse_window_spec()
5825
5826            spec = self.expression(
5827                exp.WindowSpec,
5828                kind=kind,
5829                start=start["value"],
5830                start_side=start["side"],
5831                end=end["value"],
5832                end_side=end["side"],
5833            )
5834        else:
5835            spec = None
5836
5837        self._match_r_paren()
5838
5839        window = self.expression(
5840            exp.Window,
5841            comments=comments,
5842            this=this,
5843            partition_by=partition,
5844            order=order,
5845            spec=spec,
5846            alias=window_alias,
5847            over=over,
5848            first=first,
5849        )
5850
5851        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5852        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5853            return self._parse_window(window, alias=alias)
5854
5855        return window
5856
5857    def _parse_partition_and_order(
5858        self,
5859    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5860        return self._parse_partition_by(), self._parse_order()
5861
5862    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5863        self._match(TokenType.BETWEEN)
5864
5865        return {
5866            "value": (
5867                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5868                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5869                or self._parse_bitwise()
5870            ),
5871            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5872        }
5873
5874    def _parse_alias(
5875        self, this: t.Optional[exp.Expression], explicit: bool = False
5876    ) -> t.Optional[exp.Expression]:
5877        any_token = self._match(TokenType.ALIAS)
5878        comments = self._prev_comments or []
5879
5880        if explicit and not any_token:
5881            return this
5882
5883        if self._match(TokenType.L_PAREN):
5884            aliases = self.expression(
5885                exp.Aliases,
5886                comments=comments,
5887                this=this,
5888                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5889            )
5890            self._match_r_paren(aliases)
5891            return aliases
5892
5893        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
5894            self.STRING_ALIASES and self._parse_string_as_identifier()
5895        )
5896
5897        if alias:
5898            comments.extend(alias.pop_comments())
5899            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5900            column = this.this
5901
5902            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5903            if not this.comments and column and column.comments:
5904                this.comments = column.pop_comments()
5905
5906        return this
5907
5908    def _parse_id_var(
5909        self,
5910        any_token: bool = True,
5911        tokens: t.Optional[t.Collection[TokenType]] = None,
5912    ) -> t.Optional[exp.Expression]:
5913        expression = self._parse_identifier()
5914        if not expression and (
5915            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
5916        ):
5917            quoted = self._prev.token_type == TokenType.STRING
5918            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
5919
5920        return expression
5921
5922    def _parse_string(self) -> t.Optional[exp.Expression]:
5923        if self._match_set(self.STRING_PARSERS):
5924            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
5925        return self._parse_placeholder()
5926
5927    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5928        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5929
5930    def _parse_number(self) -> t.Optional[exp.Expression]:
5931        if self._match_set(self.NUMERIC_PARSERS):
5932            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
5933        return self._parse_placeholder()
5934
5935    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5936        if self._match(TokenType.IDENTIFIER):
5937            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5938        return self._parse_placeholder()
5939
5940    def _parse_var(
5941        self,
5942        any_token: bool = False,
5943        tokens: t.Optional[t.Collection[TokenType]] = None,
5944        upper: bool = False,
5945    ) -> t.Optional[exp.Expression]:
5946        if (
5947            (any_token and self._advance_any())
5948            or self._match(TokenType.VAR)
5949            or (self._match_set(tokens) if tokens else False)
5950        ):
5951            return self.expression(
5952                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5953            )
5954        return self._parse_placeholder()
5955
5956    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5957        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5958            self._advance()
5959            return self._prev
5960        return None
5961
5962    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5963        return self._parse_var() or self._parse_string()
5964
5965    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
5966        return self._parse_primary() or self._parse_var(any_token=True)
5967
5968    def _parse_null(self) -> t.Optional[exp.Expression]:
5969        if self._match_set(self.NULL_TOKENS):
5970            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5971        return self._parse_placeholder()
5972
5973    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5974        if self._match(TokenType.TRUE):
5975            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5976        if self._match(TokenType.FALSE):
5977            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5978        return self._parse_placeholder()
5979
5980    def _parse_star(self) -> t.Optional[exp.Expression]:
5981        if self._match(TokenType.STAR):
5982            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5983        return self._parse_placeholder()
5984
5985    def _parse_parameter(self) -> exp.Parameter:
5986        this = self._parse_identifier() or self._parse_primary_or_var()
5987        return self.expression(exp.Parameter, this=this)
5988
5989    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5990        if self._match_set(self.PLACEHOLDER_PARSERS):
5991            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5992            if placeholder:
5993                return placeholder
5994            self._advance(-1)
5995        return None
5996
5997    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
5998        if not self._match_texts(keywords):
5999            return None
6000        if self._match(TokenType.L_PAREN, advance=False):
6001            return self._parse_wrapped_csv(self._parse_expression)
6002
6003        expression = self._parse_expression()
6004        return [expression] if expression else None
6005
6006    def _parse_csv(
6007        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6008    ) -> t.List[exp.Expression]:
6009        parse_result = parse_method()
6010        items = [parse_result] if parse_result is not None else []
6011
6012        while self._match(sep):
6013            self._add_comments(parse_result)
6014            parse_result = parse_method()
6015            if parse_result is not None:
6016                items.append(parse_result)
6017
6018        return items
6019
6020    def _parse_tokens(
6021        self, parse_method: t.Callable, expressions: t.Dict
6022    ) -> t.Optional[exp.Expression]:
6023        this = parse_method()
6024
6025        while self._match_set(expressions):
6026            this = self.expression(
6027                expressions[self._prev.token_type],
6028                this=this,
6029                comments=self._prev_comments,
6030                expression=parse_method(),
6031            )
6032
6033        return this
6034
6035    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6036        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6037
6038    def _parse_wrapped_csv(
6039        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6040    ) -> t.List[exp.Expression]:
6041        return self._parse_wrapped(
6042            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6043        )
6044
6045    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6046        wrapped = self._match(TokenType.L_PAREN)
6047        if not wrapped and not optional:
6048            self.raise_error("Expecting (")
6049        parse_result = parse_method()
6050        if wrapped:
6051            self._match_r_paren()
6052        return parse_result
6053
6054    def _parse_expressions(self) -> t.List[exp.Expression]:
6055        return self._parse_csv(self._parse_expression)
6056
6057    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6058        return self._parse_select() or self._parse_set_operations(
6059            self._parse_expression() if alias else self._parse_assignment()
6060        )
6061
6062    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6063        return self._parse_query_modifiers(
6064            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6065        )
6066
6067    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6068        this = None
6069        if self._match_texts(self.TRANSACTION_KIND):
6070            this = self._prev.text
6071
6072        self._match_texts(("TRANSACTION", "WORK"))
6073
6074        modes = []
6075        while True:
6076            mode = []
6077            while self._match(TokenType.VAR):
6078                mode.append(self._prev.text)
6079
6080            if mode:
6081                modes.append(" ".join(mode))
6082            if not self._match(TokenType.COMMA):
6083                break
6084
6085        return self.expression(exp.Transaction, this=this, modes=modes)
6086
6087    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6088        chain = None
6089        savepoint = None
6090        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6091
6092        self._match_texts(("TRANSACTION", "WORK"))
6093
6094        if self._match_text_seq("TO"):
6095            self._match_text_seq("SAVEPOINT")
6096            savepoint = self._parse_id_var()
6097
6098        if self._match(TokenType.AND):
6099            chain = not self._match_text_seq("NO")
6100            self._match_text_seq("CHAIN")
6101
6102        if is_rollback:
6103            return self.expression(exp.Rollback, savepoint=savepoint)
6104
6105        return self.expression(exp.Commit, chain=chain)
6106
6107    def _parse_refresh(self) -> exp.Refresh:
6108        self._match(TokenType.TABLE)
6109        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6110
6111    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6112        if not self._match_text_seq("ADD"):
6113            return None
6114
6115        self._match(TokenType.COLUMN)
6116        exists_column = self._parse_exists(not_=True)
6117        expression = self._parse_field_def()
6118
6119        if expression:
6120            expression.set("exists", exists_column)
6121
6122            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6123            if self._match_texts(("FIRST", "AFTER")):
6124                position = self._prev.text
6125                column_position = self.expression(
6126                    exp.ColumnPosition, this=self._parse_column(), position=position
6127                )
6128                expression.set("position", column_position)
6129
6130        return expression
6131
6132    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6133        drop = self._match(TokenType.DROP) and self._parse_drop()
6134        if drop and not isinstance(drop, exp.Command):
6135            drop.set("kind", drop.args.get("kind", "COLUMN"))
6136        return drop
6137
6138    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6139    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6140        return self.expression(
6141            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6142        )
6143
6144    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6145        index = self._index - 1
6146
6147        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6148            return self._parse_csv(
6149                lambda: self.expression(
6150                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6151                )
6152            )
6153
6154        self._retreat(index)
6155        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6156            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6157        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6158
6159    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6160        if self._match_texts(self.ALTER_ALTER_PARSERS):
6161            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6162
6163        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6164        # keyword after ALTER we default to parsing this statement
6165        self._match(TokenType.COLUMN)
6166        column = self._parse_field(any_token=True)
6167
6168        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6169            return self.expression(exp.AlterColumn, this=column, drop=True)
6170        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6171            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6172        if self._match(TokenType.COMMENT):
6173            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6174        if self._match_text_seq("DROP", "NOT", "NULL"):
6175            return self.expression(
6176                exp.AlterColumn,
6177                this=column,
6178                drop=True,
6179                allow_null=True,
6180            )
6181        if self._match_text_seq("SET", "NOT", "NULL"):
6182            return self.expression(
6183                exp.AlterColumn,
6184                this=column,
6185                allow_null=False,
6186            )
6187        self._match_text_seq("SET", "DATA")
6188        self._match_text_seq("TYPE")
6189        return self.expression(
6190            exp.AlterColumn,
6191            this=column,
6192            dtype=self._parse_types(),
6193            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6194            using=self._match(TokenType.USING) and self._parse_assignment(),
6195        )
6196
6197    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6198        if self._match_texts(("ALL", "EVEN", "AUTO")):
6199            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6200
6201        self._match_text_seq("KEY", "DISTKEY")
6202        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6203
6204    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6205        if compound:
6206            self._match_text_seq("SORTKEY")
6207
6208        if self._match(TokenType.L_PAREN, advance=False):
6209            return self.expression(
6210                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6211            )
6212
6213        self._match_texts(("AUTO", "NONE"))
6214        return self.expression(
6215            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6216        )
6217
6218    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6219        index = self._index - 1
6220
6221        partition_exists = self._parse_exists()
6222        if self._match(TokenType.PARTITION, advance=False):
6223            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6224
6225        self._retreat(index)
6226        return self._parse_csv(self._parse_drop_column)
6227
6228    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
6229        if self._match(TokenType.COLUMN):
6230            exists = self._parse_exists()
6231            old_column = self._parse_column()
6232            to = self._match_text_seq("TO")
6233            new_column = self._parse_column()
6234
6235            if old_column is None or to is None or new_column is None:
6236                return None
6237
6238            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6239
6240        self._match_text_seq("TO")
6241        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
6242
6243    def _parse_alter_table_set(self) -> exp.AlterSet:
6244        alter_set = self.expression(exp.AlterSet)
6245
6246        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6247            "TABLE", "PROPERTIES"
6248        ):
6249            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6250        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6251            alter_set.set("expressions", [self._parse_assignment()])
6252        elif self._match_texts(("LOGGED", "UNLOGGED")):
6253            alter_set.set("option", exp.var(self._prev.text.upper()))
6254        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6255            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6256        elif self._match_text_seq("LOCATION"):
6257            alter_set.set("location", self._parse_field())
6258        elif self._match_text_seq("ACCESS", "METHOD"):
6259            alter_set.set("access_method", self._parse_field())
6260        elif self._match_text_seq("TABLESPACE"):
6261            alter_set.set("tablespace", self._parse_field())
6262        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6263            alter_set.set("file_format", [self._parse_field()])
6264        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6265            alter_set.set("file_format", self._parse_wrapped_options())
6266        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6267            alter_set.set("copy_options", self._parse_wrapped_options())
6268        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6269            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6270        else:
6271            if self._match_text_seq("SERDE"):
6272                alter_set.set("serde", self._parse_field())
6273
6274            alter_set.set("expressions", [self._parse_properties()])
6275
6276        return alter_set
6277
6278    def _parse_alter(self) -> exp.AlterTable | exp.Command:
6279        start = self._prev
6280
6281        if not self._match(TokenType.TABLE):
6282            return self._parse_as_command(start)
6283
6284        exists = self._parse_exists()
6285        only = self._match_text_seq("ONLY")
6286        this = self._parse_table(schema=True)
6287        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6288
6289        if self._next:
6290            self._advance()
6291
6292        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6293        if parser:
6294            actions = ensure_list(parser(self))
6295            options = self._parse_csv(self._parse_property)
6296
6297            if not self._curr and actions:
6298                return self.expression(
6299                    exp.AlterTable,
6300                    this=this,
6301                    exists=exists,
6302                    actions=actions,
6303                    only=only,
6304                    options=options,
6305                    cluster=cluster,
6306                )
6307
6308        return self._parse_as_command(start)
6309
6310    def _parse_merge(self) -> exp.Merge:
6311        self._match(TokenType.INTO)
6312        target = self._parse_table()
6313
6314        if target and self._match(TokenType.ALIAS, advance=False):
6315            target.set("alias", self._parse_table_alias())
6316
6317        self._match(TokenType.USING)
6318        using = self._parse_table()
6319
6320        self._match(TokenType.ON)
6321        on = self._parse_assignment()
6322
6323        return self.expression(
6324            exp.Merge,
6325            this=target,
6326            using=using,
6327            on=on,
6328            expressions=self._parse_when_matched(),
6329        )
6330
6331    def _parse_when_matched(self) -> t.List[exp.When]:
6332        whens = []
6333
6334        while self._match(TokenType.WHEN):
6335            matched = not self._match(TokenType.NOT)
6336            self._match_text_seq("MATCHED")
6337            source = (
6338                False
6339                if self._match_text_seq("BY", "TARGET")
6340                else self._match_text_seq("BY", "SOURCE")
6341            )
6342            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6343
6344            self._match(TokenType.THEN)
6345
6346            if self._match(TokenType.INSERT):
6347                _this = self._parse_star()
6348                if _this:
6349                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
6350                else:
6351                    then = self.expression(
6352                        exp.Insert,
6353                        this=self._parse_value(),
6354                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6355                    )
6356            elif self._match(TokenType.UPDATE):
6357                expressions = self._parse_star()
6358                if expressions:
6359                    then = self.expression(exp.Update, expressions=expressions)
6360                else:
6361                    then = self.expression(
6362                        exp.Update,
6363                        expressions=self._match(TokenType.SET)
6364                        and self._parse_csv(self._parse_equality),
6365                    )
6366            elif self._match(TokenType.DELETE):
6367                then = self.expression(exp.Var, this=self._prev.text)
6368            else:
6369                then = None
6370
6371            whens.append(
6372                self.expression(
6373                    exp.When,
6374                    matched=matched,
6375                    source=source,
6376                    condition=condition,
6377                    then=then,
6378                )
6379            )
6380        return whens
6381
6382    def _parse_show(self) -> t.Optional[exp.Expression]:
6383        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
6384        if parser:
6385            return parser(self)
6386        return self._parse_as_command(self._prev)
6387
6388    def _parse_set_item_assignment(
6389        self, kind: t.Optional[str] = None
6390    ) -> t.Optional[exp.Expression]:
6391        index = self._index
6392
6393        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
6394            return self._parse_set_transaction(global_=kind == "GLOBAL")
6395
6396        left = self._parse_primary() or self._parse_column()
6397        assignment_delimiter = self._match_texts(("=", "TO"))
6398
6399        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
6400            self._retreat(index)
6401            return None
6402
6403        right = self._parse_statement() or self._parse_id_var()
6404        if isinstance(right, (exp.Column, exp.Identifier)):
6405            right = exp.var(right.name)
6406
6407        this = self.expression(exp.EQ, this=left, expression=right)
6408        return self.expression(exp.SetItem, this=this, kind=kind)
6409
6410    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
6411        self._match_text_seq("TRANSACTION")
6412        characteristics = self._parse_csv(
6413            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
6414        )
6415        return self.expression(
6416            exp.SetItem,
6417            expressions=characteristics,
6418            kind="TRANSACTION",
6419            **{"global": global_},  # type: ignore
6420        )
6421
6422    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6423        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6424        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6425
6426    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6427        index = self._index
6428        set_ = self.expression(
6429            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6430        )
6431
6432        if self._curr:
6433            self._retreat(index)
6434            return self._parse_as_command(self._prev)
6435
6436        return set_
6437
6438    def _parse_var_from_options(
6439        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6440    ) -> t.Optional[exp.Var]:
6441        start = self._curr
6442        if not start:
6443            return None
6444
6445        option = start.text.upper()
6446        continuations = options.get(option)
6447
6448        index = self._index
6449        self._advance()
6450        for keywords in continuations or []:
6451            if isinstance(keywords, str):
6452                keywords = (keywords,)
6453
6454            if self._match_text_seq(*keywords):
6455                option = f"{option} {' '.join(keywords)}"
6456                break
6457        else:
6458            if continuations or continuations is None:
6459                if raise_unmatched:
6460                    self.raise_error(f"Unknown option {option}")
6461
6462                self._retreat(index)
6463                return None
6464
6465        return exp.var(option)
6466
6467    def _parse_as_command(self, start: Token) -> exp.Command:
6468        while self._curr:
6469            self._advance()
6470        text = self._find_sql(start, self._prev)
6471        size = len(start.text)
6472        self._warn_unsupported()
6473        return exp.Command(this=text[:size], expression=text[size:])
6474
6475    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6476        settings = []
6477
6478        self._match_l_paren()
6479        kind = self._parse_id_var()
6480
6481        if self._match(TokenType.L_PAREN):
6482            while True:
6483                key = self._parse_id_var()
6484                value = self._parse_primary()
6485
6486                if not key and value is None:
6487                    break
6488                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6489            self._match(TokenType.R_PAREN)
6490
6491        self._match_r_paren()
6492
6493        return self.expression(
6494            exp.DictProperty,
6495            this=this,
6496            kind=kind.this if kind else None,
6497            settings=settings,
6498        )
6499
6500    def _parse_dict_range(self, this: str) -> exp.DictRange:
6501        self._match_l_paren()
6502        has_min = self._match_text_seq("MIN")
6503        if has_min:
6504            min = self._parse_var() or self._parse_primary()
6505            self._match_text_seq("MAX")
6506            max = self._parse_var() or self._parse_primary()
6507        else:
6508            max = self._parse_var() or self._parse_primary()
6509            min = exp.Literal.number(0)
6510        self._match_r_paren()
6511        return self.expression(exp.DictRange, this=this, min=min, max=max)
6512
6513    def _parse_comprehension(
6514        self, this: t.Optional[exp.Expression]
6515    ) -> t.Optional[exp.Comprehension]:
6516        index = self._index
6517        expression = self._parse_column()
6518        if not self._match(TokenType.IN):
6519            self._retreat(index - 1)
6520            return None
6521        iterator = self._parse_column()
6522        condition = self._parse_assignment() if self._match_text_seq("IF") else None
6523        return self.expression(
6524            exp.Comprehension,
6525            this=this,
6526            expression=expression,
6527            iterator=iterator,
6528            condition=condition,
6529        )
6530
6531    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6532        if self._match(TokenType.HEREDOC_STRING):
6533            return self.expression(exp.Heredoc, this=self._prev.text)
6534
6535        if not self._match_text_seq("$"):
6536            return None
6537
6538        tags = ["$"]
6539        tag_text = None
6540
6541        if self._is_connected():
6542            self._advance()
6543            tags.append(self._prev.text.upper())
6544        else:
6545            self.raise_error("No closing $ found")
6546
6547        if tags[-1] != "$":
6548            if self._is_connected() and self._match_text_seq("$"):
6549                tag_text = tags[-1]
6550                tags.append("$")
6551            else:
6552                self.raise_error("No closing $ found")
6553
6554        heredoc_start = self._curr
6555
6556        while self._curr:
6557            if self._match_text_seq(*tags, advance=False):
6558                this = self._find_sql(heredoc_start, self._prev)
6559                self._advance(len(tags))
6560                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6561
6562            self._advance()
6563
6564        self.raise_error(f"No closing {''.join(tags)} found")
6565        return None
6566
6567    def _find_parser(
6568        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6569    ) -> t.Optional[t.Callable]:
6570        if not self._curr:
6571            return None
6572
6573        index = self._index
6574        this = []
6575        while True:
6576            # The current token might be multiple words
6577            curr = self._curr.text.upper()
6578            key = curr.split(" ")
6579            this.append(curr)
6580
6581            self._advance()
6582            result, trie = in_trie(trie, key)
6583            if result == TrieResult.FAILED:
6584                break
6585
6586            if result == TrieResult.EXISTS:
6587                subparser = parsers[" ".join(this)]
6588                return subparser
6589
6590        self._retreat(index)
6591        return None
6592
6593    def _match(self, token_type, advance=True, expression=None):
6594        if not self._curr:
6595            return None
6596
6597        if self._curr.token_type == token_type:
6598            if advance:
6599                self._advance()
6600            self._add_comments(expression)
6601            return True
6602
6603        return None
6604
6605    def _match_set(self, types, advance=True):
6606        if not self._curr:
6607            return None
6608
6609        if self._curr.token_type in types:
6610            if advance:
6611                self._advance()
6612            return True
6613
6614        return None
6615
6616    def _match_pair(self, token_type_a, token_type_b, advance=True):
6617        if not self._curr or not self._next:
6618            return None
6619
6620        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6621            if advance:
6622                self._advance(2)
6623            return True
6624
6625        return None
6626
6627    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6628        if not self._match(TokenType.L_PAREN, expression=expression):
6629            self.raise_error("Expecting (")
6630
6631    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6632        if not self._match(TokenType.R_PAREN, expression=expression):
6633            self.raise_error("Expecting )")
6634
6635    def _match_texts(self, texts, advance=True):
6636        if self._curr and self._curr.text.upper() in texts:
6637            if advance:
6638                self._advance()
6639            return True
6640        return None
6641
6642    def _match_text_seq(self, *texts, advance=True):
6643        index = self._index
6644        for text in texts:
6645            if self._curr and self._curr.text.upper() == text:
6646                self._advance()
6647            else:
6648                self._retreat(index)
6649                return None
6650
6651        if not advance:
6652            self._retreat(index)
6653
6654        return True
6655
6656    def _replace_lambda(
6657        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
6658    ) -> t.Optional[exp.Expression]:
6659        if not node:
6660            return node
6661
6662        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
6663
6664        for column in node.find_all(exp.Column):
6665            typ = lambda_types.get(column.parts[0].name)
6666            if typ is not None:
6667                dot_or_id = column.to_dot() if column.table else column.this
6668
6669                if typ:
6670                    dot_or_id = self.expression(
6671                        exp.Cast,
6672                        this=dot_or_id,
6673                        to=typ,
6674                    )
6675
6676                parent = column.parent
6677
6678                while isinstance(parent, exp.Dot):
6679                    if not isinstance(parent.parent, exp.Dot):
6680                        parent.replace(dot_or_id)
6681                        break
6682                    parent = parent.parent
6683                else:
6684                    if column is node:
6685                        node = dot_or_id
6686                    else:
6687                        column.replace(dot_or_id)
6688        return node
6689
6690    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6691        start = self._prev
6692
6693        # Not to be confused with TRUNCATE(number, decimals) function call
6694        if self._match(TokenType.L_PAREN):
6695            self._retreat(self._index - 2)
6696            return self._parse_function()
6697
6698        # Clickhouse supports TRUNCATE DATABASE as well
6699        is_database = self._match(TokenType.DATABASE)
6700
6701        self._match(TokenType.TABLE)
6702
6703        exists = self._parse_exists(not_=False)
6704
6705        expressions = self._parse_csv(
6706            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6707        )
6708
6709        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6710
6711        if self._match_text_seq("RESTART", "IDENTITY"):
6712            identity = "RESTART"
6713        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6714            identity = "CONTINUE"
6715        else:
6716            identity = None
6717
6718        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6719            option = self._prev.text
6720        else:
6721            option = None
6722
6723        partition = self._parse_partition()
6724
6725        # Fallback case
6726        if self._curr:
6727            return self._parse_as_command(start)
6728
6729        return self.expression(
6730            exp.TruncateTable,
6731            expressions=expressions,
6732            is_database=is_database,
6733            exists=exists,
6734            cluster=cluster,
6735            identity=identity,
6736            option=option,
6737            partition=partition,
6738        )
6739
6740    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6741        this = self._parse_ordered(self._parse_opclass)
6742
6743        if not self._match(TokenType.WITH):
6744            return this
6745
6746        op = self._parse_var(any_token=True)
6747
6748        return self.expression(exp.WithOperator, this=this, op=op)
6749
6750    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6751        self._match(TokenType.EQ)
6752        self._match(TokenType.L_PAREN)
6753
6754        opts: t.List[t.Optional[exp.Expression]] = []
6755        while self._curr and not self._match(TokenType.R_PAREN):
6756            if self._match_text_seq("FORMAT_NAME", "="):
6757                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
6758                # so we parse it separately to use _parse_field()
6759                prop = self.expression(
6760                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
6761                )
6762                opts.append(prop)
6763            else:
6764                opts.append(self._parse_property())
6765
6766            self._match(TokenType.COMMA)
6767
6768        return opts
6769
6770    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6771        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6772
6773        options = []
6774        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6775            option = self._parse_var(any_token=True)
6776            prev = self._prev.text.upper()
6777
6778            # Different dialects might separate options and values by white space, "=" and "AS"
6779            self._match(TokenType.EQ)
6780            self._match(TokenType.ALIAS)
6781
6782            param = self.expression(exp.CopyParameter, this=option)
6783
6784            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
6785                TokenType.L_PAREN, advance=False
6786            ):
6787                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
6788                param.set("expressions", self._parse_wrapped_options())
6789            elif prev == "FILE_FORMAT":
6790                # T-SQL's external file format case
6791                param.set("expression", self._parse_field())
6792            else:
6793                param.set("expression", self._parse_unquoted_field())
6794
6795            options.append(param)
6796            self._match(sep)
6797
6798        return options
6799
6800    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6801        expr = self.expression(exp.Credentials)
6802
6803        if self._match_text_seq("STORAGE_INTEGRATION", "="):
6804            expr.set("storage", self._parse_field())
6805        if self._match_text_seq("CREDENTIALS"):
6806            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
6807            creds = (
6808                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6809            )
6810            expr.set("credentials", creds)
6811        if self._match_text_seq("ENCRYPTION"):
6812            expr.set("encryption", self._parse_wrapped_options())
6813        if self._match_text_seq("IAM_ROLE"):
6814            expr.set("iam_role", self._parse_field())
6815        if self._match_text_seq("REGION"):
6816            expr.set("region", self._parse_field())
6817
6818        return expr
6819
6820    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6821        return self._parse_field()
6822
6823    def _parse_copy(self) -> exp.Copy | exp.Command:
6824        start = self._prev
6825
6826        self._match(TokenType.INTO)
6827
6828        this = (
6829            self._parse_select(nested=True, parse_subquery_alias=False)
6830            if self._match(TokenType.L_PAREN, advance=False)
6831            else self._parse_table(schema=True)
6832        )
6833
6834        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
6835
6836        files = self._parse_csv(self._parse_file_location)
6837        credentials = self._parse_credentials()
6838
6839        self._match_text_seq("WITH")
6840
6841        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
6842
6843        # Fallback case
6844        if self._curr:
6845            return self._parse_as_command(start)
6846
6847        return self.expression(
6848            exp.Copy,
6849            this=this,
6850            kind=kind,
6851            credentials=credentials,
6852            files=files,
6853            params=params,
6854        )
logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
27    if len(args) == 1 and args[0].is_star:
28        return exp.StarMap(this=args[0])
29
30    keys = []
31    values = []
32    for i in range(0, len(args), 2):
33        keys.append(args[i])
34        values.append(args[i + 1])
35
36    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
39def build_like(args: t.List) -> exp.Escape | exp.Like:
40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
41    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], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
44def binary_range_parser(
45    expr_type: t.Type[exp.Expression], reverse_args: bool = False
46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
47    def _parse_binary_range(
48        self: Parser, this: t.Optional[exp.Expression]
49    ) -> t.Optional[exp.Expression]:
50        expression = self._parse_bitwise()
51        if reverse_args:
52            this, expression = expression, this
53        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
54
55    return _parse_binary_range
def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
58def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
59    # Default argument order is base, expression
60    this = seq_get(args, 0)
61    expression = seq_get(args, 1)
62
63    if expression:
64        if not dialect.LOG_BASE_FIRST:
65            this, expression = expression, this
66        return exp.Log(this=this, expression=expression)
67
68    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
def build_hex( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex:
71def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
72    arg = seq_get(args, 0)
73    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex:
76def build_lower(args: t.List) -> exp.Lower | exp.Hex:
77    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
78    arg = seq_get(args, 0)
79    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex:
82def build_upper(args: t.List) -> exp.Upper | exp.Hex:
83    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
84    arg = seq_get(args, 0)
85    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]:
88def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
89    def _builder(args: t.List, dialect: Dialect) -> E:
90        expression = expr_type(
91            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
92        )
93        if len(args) > 2 and expr_type is exp.JSONExtract:
94            expression.set("expressions", args[2:])
95
96        return expression
97
98    return _builder
def build_mod(args: List) -> sqlglot.expressions.Mod:
101def build_mod(args: t.List) -> exp.Mod:
102    this = seq_get(args, 0)
103    expression = seq_get(args, 1)
104
105    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
106    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
107    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
108
109    return exp.Mod(this=this, expression=expression)
class Parser:
 122class Parser(metaclass=_Parser):
 123    """
 124    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 125
 126    Args:
 127        error_level: The desired error level.
 128            Default: ErrorLevel.IMMEDIATE
 129        error_message_context: The amount of context to capture from a query string when displaying
 130            the error message (in number of characters).
 131            Default: 100
 132        max_errors: Maximum number of error messages to include in a raised ParseError.
 133            This is only relevant if error_level is ErrorLevel.RAISE.
 134            Default: 3
 135    """
 136
 137    FUNCTIONS: t.Dict[str, t.Callable] = {
 138        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 139        "CONCAT": lambda args, dialect: exp.Concat(
 140            expressions=args,
 141            safe=not dialect.STRICT_STRING_CONCAT,
 142            coalesce=dialect.CONCAT_COALESCE,
 143        ),
 144        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 145            expressions=args,
 146            safe=not dialect.STRICT_STRING_CONCAT,
 147            coalesce=dialect.CONCAT_COALESCE,
 148        ),
 149        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 150            this=seq_get(args, 0),
 151            to=exp.DataType(this=exp.DataType.Type.TEXT),
 152        ),
 153        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 154        "HEX": build_hex,
 155        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 156        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 157        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 158        "LIKE": build_like,
 159        "LOG": build_logarithm,
 160        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 161        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 162        "LOWER": build_lower,
 163        "MOD": build_mod,
 164        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 165            this=seq_get(args, 0),
 166            to=exp.DataType(this=exp.DataType.Type.TEXT),
 167        ),
 168        "TO_HEX": build_hex,
 169        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 170            this=exp.Cast(
 171                this=seq_get(args, 0),
 172                to=exp.DataType(this=exp.DataType.Type.TEXT),
 173            ),
 174            start=exp.Literal.number(1),
 175            length=exp.Literal.number(10),
 176        ),
 177        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 178        "UPPER": build_upper,
 179        "VAR_MAP": build_var_map,
 180    }
 181
 182    NO_PAREN_FUNCTIONS = {
 183        TokenType.CURRENT_DATE: exp.CurrentDate,
 184        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 185        TokenType.CURRENT_TIME: exp.CurrentTime,
 186        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 187        TokenType.CURRENT_USER: exp.CurrentUser,
 188    }
 189
 190    STRUCT_TYPE_TOKENS = {
 191        TokenType.NESTED,
 192        TokenType.OBJECT,
 193        TokenType.STRUCT,
 194    }
 195
 196    NESTED_TYPE_TOKENS = {
 197        TokenType.ARRAY,
 198        TokenType.LIST,
 199        TokenType.LOWCARDINALITY,
 200        TokenType.MAP,
 201        TokenType.NULLABLE,
 202        *STRUCT_TYPE_TOKENS,
 203    }
 204
 205    ENUM_TYPE_TOKENS = {
 206        TokenType.ENUM,
 207        TokenType.ENUM8,
 208        TokenType.ENUM16,
 209    }
 210
 211    AGGREGATE_TYPE_TOKENS = {
 212        TokenType.AGGREGATEFUNCTION,
 213        TokenType.SIMPLEAGGREGATEFUNCTION,
 214    }
 215
 216    TYPE_TOKENS = {
 217        TokenType.BIT,
 218        TokenType.BOOLEAN,
 219        TokenType.TINYINT,
 220        TokenType.UTINYINT,
 221        TokenType.SMALLINT,
 222        TokenType.USMALLINT,
 223        TokenType.INT,
 224        TokenType.UINT,
 225        TokenType.BIGINT,
 226        TokenType.UBIGINT,
 227        TokenType.INT128,
 228        TokenType.UINT128,
 229        TokenType.INT256,
 230        TokenType.UINT256,
 231        TokenType.MEDIUMINT,
 232        TokenType.UMEDIUMINT,
 233        TokenType.FIXEDSTRING,
 234        TokenType.FLOAT,
 235        TokenType.DOUBLE,
 236        TokenType.CHAR,
 237        TokenType.NCHAR,
 238        TokenType.VARCHAR,
 239        TokenType.NVARCHAR,
 240        TokenType.BPCHAR,
 241        TokenType.TEXT,
 242        TokenType.MEDIUMTEXT,
 243        TokenType.LONGTEXT,
 244        TokenType.MEDIUMBLOB,
 245        TokenType.LONGBLOB,
 246        TokenType.BINARY,
 247        TokenType.VARBINARY,
 248        TokenType.JSON,
 249        TokenType.JSONB,
 250        TokenType.INTERVAL,
 251        TokenType.TINYBLOB,
 252        TokenType.TINYTEXT,
 253        TokenType.TIME,
 254        TokenType.TIMETZ,
 255        TokenType.TIMESTAMP,
 256        TokenType.TIMESTAMP_S,
 257        TokenType.TIMESTAMP_MS,
 258        TokenType.TIMESTAMP_NS,
 259        TokenType.TIMESTAMPTZ,
 260        TokenType.TIMESTAMPLTZ,
 261        TokenType.TIMESTAMPNTZ,
 262        TokenType.DATETIME,
 263        TokenType.DATETIME64,
 264        TokenType.DATE,
 265        TokenType.DATE32,
 266        TokenType.INT4RANGE,
 267        TokenType.INT4MULTIRANGE,
 268        TokenType.INT8RANGE,
 269        TokenType.INT8MULTIRANGE,
 270        TokenType.NUMRANGE,
 271        TokenType.NUMMULTIRANGE,
 272        TokenType.TSRANGE,
 273        TokenType.TSMULTIRANGE,
 274        TokenType.TSTZRANGE,
 275        TokenType.TSTZMULTIRANGE,
 276        TokenType.DATERANGE,
 277        TokenType.DATEMULTIRANGE,
 278        TokenType.DECIMAL,
 279        TokenType.UDECIMAL,
 280        TokenType.BIGDECIMAL,
 281        TokenType.UUID,
 282        TokenType.GEOGRAPHY,
 283        TokenType.GEOMETRY,
 284        TokenType.HLLSKETCH,
 285        TokenType.HSTORE,
 286        TokenType.PSEUDO_TYPE,
 287        TokenType.SUPER,
 288        TokenType.SERIAL,
 289        TokenType.SMALLSERIAL,
 290        TokenType.BIGSERIAL,
 291        TokenType.XML,
 292        TokenType.YEAR,
 293        TokenType.UNIQUEIDENTIFIER,
 294        TokenType.USERDEFINED,
 295        TokenType.MONEY,
 296        TokenType.SMALLMONEY,
 297        TokenType.ROWVERSION,
 298        TokenType.IMAGE,
 299        TokenType.VARIANT,
 300        TokenType.OBJECT,
 301        TokenType.OBJECT_IDENTIFIER,
 302        TokenType.INET,
 303        TokenType.IPADDRESS,
 304        TokenType.IPPREFIX,
 305        TokenType.IPV4,
 306        TokenType.IPV6,
 307        TokenType.UNKNOWN,
 308        TokenType.NULL,
 309        TokenType.NAME,
 310        TokenType.TDIGEST,
 311        *ENUM_TYPE_TOKENS,
 312        *NESTED_TYPE_TOKENS,
 313        *AGGREGATE_TYPE_TOKENS,
 314    }
 315
 316    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 317        TokenType.BIGINT: TokenType.UBIGINT,
 318        TokenType.INT: TokenType.UINT,
 319        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 320        TokenType.SMALLINT: TokenType.USMALLINT,
 321        TokenType.TINYINT: TokenType.UTINYINT,
 322        TokenType.DECIMAL: TokenType.UDECIMAL,
 323    }
 324
 325    SUBQUERY_PREDICATES = {
 326        TokenType.ANY: exp.Any,
 327        TokenType.ALL: exp.All,
 328        TokenType.EXISTS: exp.Exists,
 329        TokenType.SOME: exp.Any,
 330    }
 331
 332    RESERVED_TOKENS = {
 333        *Tokenizer.SINGLE_TOKENS.values(),
 334        TokenType.SELECT,
 335    } - {TokenType.IDENTIFIER}
 336
 337    DB_CREATABLES = {
 338        TokenType.DATABASE,
 339        TokenType.DICTIONARY,
 340        TokenType.MODEL,
 341        TokenType.SCHEMA,
 342        TokenType.SEQUENCE,
 343        TokenType.STORAGE_INTEGRATION,
 344        TokenType.TABLE,
 345        TokenType.TAG,
 346        TokenType.VIEW,
 347        TokenType.WAREHOUSE,
 348        TokenType.STREAMLIT,
 349    }
 350
 351    CREATABLES = {
 352        TokenType.COLUMN,
 353        TokenType.CONSTRAINT,
 354        TokenType.FOREIGN_KEY,
 355        TokenType.FUNCTION,
 356        TokenType.INDEX,
 357        TokenType.PROCEDURE,
 358        *DB_CREATABLES,
 359    }
 360
 361    # Tokens that can represent identifiers
 362    ID_VAR_TOKENS = {
 363        TokenType.VAR,
 364        TokenType.ANTI,
 365        TokenType.APPLY,
 366        TokenType.ASC,
 367        TokenType.ASOF,
 368        TokenType.AUTO_INCREMENT,
 369        TokenType.BEGIN,
 370        TokenType.BPCHAR,
 371        TokenType.CACHE,
 372        TokenType.CASE,
 373        TokenType.COLLATE,
 374        TokenType.COMMAND,
 375        TokenType.COMMENT,
 376        TokenType.COMMIT,
 377        TokenType.CONSTRAINT,
 378        TokenType.COPY,
 379        TokenType.DEFAULT,
 380        TokenType.DELETE,
 381        TokenType.DESC,
 382        TokenType.DESCRIBE,
 383        TokenType.DICTIONARY,
 384        TokenType.DIV,
 385        TokenType.END,
 386        TokenType.EXECUTE,
 387        TokenType.ESCAPE,
 388        TokenType.FALSE,
 389        TokenType.FIRST,
 390        TokenType.FILTER,
 391        TokenType.FINAL,
 392        TokenType.FORMAT,
 393        TokenType.FULL,
 394        TokenType.IDENTIFIER,
 395        TokenType.IS,
 396        TokenType.ISNULL,
 397        TokenType.INTERVAL,
 398        TokenType.KEEP,
 399        TokenType.KILL,
 400        TokenType.LEFT,
 401        TokenType.LOAD,
 402        TokenType.MERGE,
 403        TokenType.NATURAL,
 404        TokenType.NEXT,
 405        TokenType.OFFSET,
 406        TokenType.OPERATOR,
 407        TokenType.ORDINALITY,
 408        TokenType.OVERLAPS,
 409        TokenType.OVERWRITE,
 410        TokenType.PARTITION,
 411        TokenType.PERCENT,
 412        TokenType.PIVOT,
 413        TokenType.PRAGMA,
 414        TokenType.RANGE,
 415        TokenType.RECURSIVE,
 416        TokenType.REFERENCES,
 417        TokenType.REFRESH,
 418        TokenType.REPLACE,
 419        TokenType.RIGHT,
 420        TokenType.ROLLUP,
 421        TokenType.ROW,
 422        TokenType.ROWS,
 423        TokenType.SEMI,
 424        TokenType.SET,
 425        TokenType.SETTINGS,
 426        TokenType.SHOW,
 427        TokenType.TEMPORARY,
 428        TokenType.TOP,
 429        TokenType.TRUE,
 430        TokenType.TRUNCATE,
 431        TokenType.UNIQUE,
 432        TokenType.UNNEST,
 433        TokenType.UNPIVOT,
 434        TokenType.UPDATE,
 435        TokenType.USE,
 436        TokenType.VOLATILE,
 437        TokenType.WINDOW,
 438        *CREATABLES,
 439        *SUBQUERY_PREDICATES,
 440        *TYPE_TOKENS,
 441        *NO_PAREN_FUNCTIONS,
 442    }
 443
 444    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 445
 446    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 447        TokenType.ANTI,
 448        TokenType.APPLY,
 449        TokenType.ASOF,
 450        TokenType.FULL,
 451        TokenType.LEFT,
 452        TokenType.LOCK,
 453        TokenType.NATURAL,
 454        TokenType.OFFSET,
 455        TokenType.RIGHT,
 456        TokenType.SEMI,
 457        TokenType.WINDOW,
 458    }
 459
 460    ALIAS_TOKENS = ID_VAR_TOKENS
 461
 462    ARRAY_CONSTRUCTORS = {
 463        "ARRAY": exp.Array,
 464        "LIST": exp.List,
 465    }
 466
 467    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 468
 469    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 470
 471    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 472
 473    FUNC_TOKENS = {
 474        TokenType.COLLATE,
 475        TokenType.COMMAND,
 476        TokenType.CURRENT_DATE,
 477        TokenType.CURRENT_DATETIME,
 478        TokenType.CURRENT_TIMESTAMP,
 479        TokenType.CURRENT_TIME,
 480        TokenType.CURRENT_USER,
 481        TokenType.FILTER,
 482        TokenType.FIRST,
 483        TokenType.FORMAT,
 484        TokenType.GLOB,
 485        TokenType.IDENTIFIER,
 486        TokenType.INDEX,
 487        TokenType.ISNULL,
 488        TokenType.ILIKE,
 489        TokenType.INSERT,
 490        TokenType.LIKE,
 491        TokenType.MERGE,
 492        TokenType.OFFSET,
 493        TokenType.PRIMARY_KEY,
 494        TokenType.RANGE,
 495        TokenType.REPLACE,
 496        TokenType.RLIKE,
 497        TokenType.ROW,
 498        TokenType.UNNEST,
 499        TokenType.VAR,
 500        TokenType.LEFT,
 501        TokenType.RIGHT,
 502        TokenType.SEQUENCE,
 503        TokenType.DATE,
 504        TokenType.DATETIME,
 505        TokenType.TABLE,
 506        TokenType.TIMESTAMP,
 507        TokenType.TIMESTAMPTZ,
 508        TokenType.TRUNCATE,
 509        TokenType.WINDOW,
 510        TokenType.XOR,
 511        *TYPE_TOKENS,
 512        *SUBQUERY_PREDICATES,
 513    }
 514
 515    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 516        TokenType.AND: exp.And,
 517    }
 518
 519    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 520        TokenType.COLON_EQ: exp.PropertyEQ,
 521    }
 522
 523    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 524        TokenType.OR: exp.Or,
 525    }
 526
 527    EQUALITY = {
 528        TokenType.EQ: exp.EQ,
 529        TokenType.NEQ: exp.NEQ,
 530        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 531    }
 532
 533    COMPARISON = {
 534        TokenType.GT: exp.GT,
 535        TokenType.GTE: exp.GTE,
 536        TokenType.LT: exp.LT,
 537        TokenType.LTE: exp.LTE,
 538    }
 539
 540    BITWISE = {
 541        TokenType.AMP: exp.BitwiseAnd,
 542        TokenType.CARET: exp.BitwiseXor,
 543        TokenType.PIPE: exp.BitwiseOr,
 544    }
 545
 546    TERM = {
 547        TokenType.DASH: exp.Sub,
 548        TokenType.PLUS: exp.Add,
 549        TokenType.MOD: exp.Mod,
 550        TokenType.COLLATE: exp.Collate,
 551    }
 552
 553    FACTOR = {
 554        TokenType.DIV: exp.IntDiv,
 555        TokenType.LR_ARROW: exp.Distance,
 556        TokenType.SLASH: exp.Div,
 557        TokenType.STAR: exp.Mul,
 558    }
 559
 560    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 561
 562    TIMES = {
 563        TokenType.TIME,
 564        TokenType.TIMETZ,
 565    }
 566
 567    TIMESTAMPS = {
 568        TokenType.TIMESTAMP,
 569        TokenType.TIMESTAMPTZ,
 570        TokenType.TIMESTAMPLTZ,
 571        *TIMES,
 572    }
 573
 574    SET_OPERATIONS = {
 575        TokenType.UNION,
 576        TokenType.INTERSECT,
 577        TokenType.EXCEPT,
 578    }
 579
 580    JOIN_METHODS = {
 581        TokenType.ASOF,
 582        TokenType.NATURAL,
 583        TokenType.POSITIONAL,
 584    }
 585
 586    JOIN_SIDES = {
 587        TokenType.LEFT,
 588        TokenType.RIGHT,
 589        TokenType.FULL,
 590    }
 591
 592    JOIN_KINDS = {
 593        TokenType.ANTI,
 594        TokenType.CROSS,
 595        TokenType.INNER,
 596        TokenType.OUTER,
 597        TokenType.SEMI,
 598        TokenType.STRAIGHT_JOIN,
 599    }
 600
 601    JOIN_HINTS: t.Set[str] = set()
 602
 603    LAMBDAS = {
 604        TokenType.ARROW: lambda self, expressions: self.expression(
 605            exp.Lambda,
 606            this=self._replace_lambda(
 607                self._parse_assignment(),
 608                expressions,
 609            ),
 610            expressions=expressions,
 611        ),
 612        TokenType.FARROW: lambda self, expressions: self.expression(
 613            exp.Kwarg,
 614            this=exp.var(expressions[0].name),
 615            expression=self._parse_assignment(),
 616        ),
 617    }
 618
 619    COLUMN_OPERATORS = {
 620        TokenType.DOT: None,
 621        TokenType.DCOLON: lambda self, this, to: self.expression(
 622            exp.Cast if self.STRICT_CAST else exp.TryCast,
 623            this=this,
 624            to=to,
 625        ),
 626        TokenType.ARROW: lambda self, this, path: self.expression(
 627            exp.JSONExtract,
 628            this=this,
 629            expression=self.dialect.to_json_path(path),
 630            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 631        ),
 632        TokenType.DARROW: lambda self, this, path: self.expression(
 633            exp.JSONExtractScalar,
 634            this=this,
 635            expression=self.dialect.to_json_path(path),
 636            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 637        ),
 638        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 639            exp.JSONBExtract,
 640            this=this,
 641            expression=path,
 642        ),
 643        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 644            exp.JSONBExtractScalar,
 645            this=this,
 646            expression=path,
 647        ),
 648        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 649            exp.JSONBContains,
 650            this=this,
 651            expression=key,
 652        ),
 653    }
 654
 655    EXPRESSION_PARSERS = {
 656        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 657        exp.Column: lambda self: self._parse_column(),
 658        exp.Condition: lambda self: self._parse_assignment(),
 659        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 660        exp.Expression: lambda self: self._parse_expression(),
 661        exp.From: lambda self: self._parse_from(joins=True),
 662        exp.Group: lambda self: self._parse_group(),
 663        exp.Having: lambda self: self._parse_having(),
 664        exp.Identifier: lambda self: self._parse_id_var(),
 665        exp.Join: lambda self: self._parse_join(),
 666        exp.Lambda: lambda self: self._parse_lambda(),
 667        exp.Lateral: lambda self: self._parse_lateral(),
 668        exp.Limit: lambda self: self._parse_limit(),
 669        exp.Offset: lambda self: self._parse_offset(),
 670        exp.Order: lambda self: self._parse_order(),
 671        exp.Ordered: lambda self: self._parse_ordered(),
 672        exp.Properties: lambda self: self._parse_properties(),
 673        exp.Qualify: lambda self: self._parse_qualify(),
 674        exp.Returning: lambda self: self._parse_returning(),
 675        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 676        exp.Table: lambda self: self._parse_table_parts(),
 677        exp.TableAlias: lambda self: self._parse_table_alias(),
 678        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 679        exp.Where: lambda self: self._parse_where(),
 680        exp.Window: lambda self: self._parse_named_window(),
 681        exp.With: lambda self: self._parse_with(),
 682        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 683    }
 684
 685    STATEMENT_PARSERS = {
 686        TokenType.ALTER: lambda self: self._parse_alter(),
 687        TokenType.BEGIN: lambda self: self._parse_transaction(),
 688        TokenType.CACHE: lambda self: self._parse_cache(),
 689        TokenType.COMMENT: lambda self: self._parse_comment(),
 690        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 691        TokenType.COPY: lambda self: self._parse_copy(),
 692        TokenType.CREATE: lambda self: self._parse_create(),
 693        TokenType.DELETE: lambda self: self._parse_delete(),
 694        TokenType.DESC: lambda self: self._parse_describe(),
 695        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 696        TokenType.DROP: lambda self: self._parse_drop(),
 697        TokenType.INSERT: lambda self: self._parse_insert(),
 698        TokenType.KILL: lambda self: self._parse_kill(),
 699        TokenType.LOAD: lambda self: self._parse_load(),
 700        TokenType.MERGE: lambda self: self._parse_merge(),
 701        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 702        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 703        TokenType.REFRESH: lambda self: self._parse_refresh(),
 704        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 705        TokenType.SET: lambda self: self._parse_set(),
 706        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 707        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 708        TokenType.UPDATE: lambda self: self._parse_update(),
 709        TokenType.USE: lambda self: self.expression(
 710            exp.Use,
 711            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 712            this=self._parse_table(schema=False),
 713        ),
 714        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 715    }
 716
 717    UNARY_PARSERS = {
 718        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 719        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 720        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 721        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 722        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 723        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 724    }
 725
 726    STRING_PARSERS = {
 727        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 728            exp.RawString, this=token.text
 729        ),
 730        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 731            exp.National, this=token.text
 732        ),
 733        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 734        TokenType.STRING: lambda self, token: self.expression(
 735            exp.Literal, this=token.text, is_string=True
 736        ),
 737        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 738            exp.UnicodeString,
 739            this=token.text,
 740            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 741        ),
 742    }
 743
 744    NUMERIC_PARSERS = {
 745        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 746        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 747        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 748        TokenType.NUMBER: lambda self, token: self.expression(
 749            exp.Literal, this=token.text, is_string=False
 750        ),
 751    }
 752
 753    PRIMARY_PARSERS = {
 754        **STRING_PARSERS,
 755        **NUMERIC_PARSERS,
 756        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 757        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 758        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 759        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 760        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 761        TokenType.STAR: lambda self, _: self.expression(
 762            exp.Star,
 763            **{
 764                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
 765                "replace": self._parse_star_op("REPLACE"),
 766                "rename": self._parse_star_op("RENAME"),
 767            },
 768        ),
 769    }
 770
 771    PLACEHOLDER_PARSERS = {
 772        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 773        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 774        TokenType.COLON: lambda self: (
 775            self.expression(exp.Placeholder, this=self._prev.text)
 776            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 777            else None
 778        ),
 779    }
 780
 781    RANGE_PARSERS = {
 782        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 783        TokenType.GLOB: binary_range_parser(exp.Glob),
 784        TokenType.ILIKE: binary_range_parser(exp.ILike),
 785        TokenType.IN: lambda self, this: self._parse_in(this),
 786        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 787        TokenType.IS: lambda self, this: self._parse_is(this),
 788        TokenType.LIKE: binary_range_parser(exp.Like),
 789        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 790        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 791        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 792        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 793    }
 794
 795    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 796        "ALLOWED_VALUES": lambda self: self.expression(
 797            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 798        ),
 799        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 800        "AUTO": lambda self: self._parse_auto_property(),
 801        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 802        "BACKUP": lambda self: self.expression(
 803            exp.BackupProperty, this=self._parse_var(any_token=True)
 804        ),
 805        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 806        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 807        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 808        "CHECKSUM": lambda self: self._parse_checksum(),
 809        "CLUSTER BY": lambda self: self._parse_cluster(),
 810        "CLUSTERED": lambda self: self._parse_clustered_by(),
 811        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 812            exp.CollateProperty, **kwargs
 813        ),
 814        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 815        "CONTAINS": lambda self: self._parse_contains_property(),
 816        "COPY": lambda self: self._parse_copy_property(),
 817        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 818        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 819        "DEFINER": lambda self: self._parse_definer(),
 820        "DETERMINISTIC": lambda self: self.expression(
 821            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 822        ),
 823        "DISTKEY": lambda self: self._parse_distkey(),
 824        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 825        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 826        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 827        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 828        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 829        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 830        "FREESPACE": lambda self: self._parse_freespace(),
 831        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 832        "HEAP": lambda self: self.expression(exp.HeapProperty),
 833        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 834        "IMMUTABLE": lambda self: self.expression(
 835            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 836        ),
 837        "INHERITS": lambda self: self.expression(
 838            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 839        ),
 840        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 841        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 842        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 843        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 844        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 845        "LIKE": lambda self: self._parse_create_like(),
 846        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 847        "LOCK": lambda self: self._parse_locking(),
 848        "LOCKING": lambda self: self._parse_locking(),
 849        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 850        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 851        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 852        "MODIFIES": lambda self: self._parse_modifies_property(),
 853        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 854        "NO": lambda self: self._parse_no_property(),
 855        "ON": lambda self: self._parse_on_property(),
 856        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 857        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 858        "PARTITION": lambda self: self._parse_partitioned_of(),
 859        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 860        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 861        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 862        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 863        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 864        "READS": lambda self: self._parse_reads_property(),
 865        "REMOTE": lambda self: self._parse_remote_with_connection(),
 866        "RETURNS": lambda self: self._parse_returns(),
 867        "STRICT": lambda self: self.expression(exp.StrictProperty),
 868        "ROW": lambda self: self._parse_row(),
 869        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 870        "SAMPLE": lambda self: self.expression(
 871            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 872        ),
 873        "SECURE": lambda self: self.expression(exp.SecureProperty),
 874        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 875        "SETTINGS": lambda self: self.expression(
 876            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 877        ),
 878        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 879        "SORTKEY": lambda self: self._parse_sortkey(),
 880        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 881        "STABLE": lambda self: self.expression(
 882            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 883        ),
 884        "STORED": lambda self: self._parse_stored(),
 885        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 886        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 887        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 888        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 889        "TO": lambda self: self._parse_to_table(),
 890        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 891        "TRANSFORM": lambda self: self.expression(
 892            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 893        ),
 894        "TTL": lambda self: self._parse_ttl(),
 895        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 896        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 897        "VOLATILE": lambda self: self._parse_volatile_property(),
 898        "WITH": lambda self: self._parse_with_property(),
 899    }
 900
 901    CONSTRAINT_PARSERS = {
 902        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 903        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 904        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 905        "CHARACTER SET": lambda self: self.expression(
 906            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 907        ),
 908        "CHECK": lambda self: self.expression(
 909            exp.CheckColumnConstraint,
 910            this=self._parse_wrapped(self._parse_assignment),
 911            enforced=self._match_text_seq("ENFORCED"),
 912        ),
 913        "COLLATE": lambda self: self.expression(
 914            exp.CollateColumnConstraint, this=self._parse_var(any_token=True)
 915        ),
 916        "COMMENT": lambda self: self.expression(
 917            exp.CommentColumnConstraint, this=self._parse_string()
 918        ),
 919        "COMPRESS": lambda self: self._parse_compress(),
 920        "CLUSTERED": lambda self: self.expression(
 921            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 922        ),
 923        "NONCLUSTERED": lambda self: self.expression(
 924            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 925        ),
 926        "DEFAULT": lambda self: self.expression(
 927            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 928        ),
 929        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 930        "EPHEMERAL": lambda self: self.expression(
 931            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 932        ),
 933        "EXCLUDE": lambda self: self.expression(
 934            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 935        ),
 936        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 937        "FORMAT": lambda self: self.expression(
 938            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 939        ),
 940        "GENERATED": lambda self: self._parse_generated_as_identity(),
 941        "IDENTITY": lambda self: self._parse_auto_increment(),
 942        "INLINE": lambda self: self._parse_inline(),
 943        "LIKE": lambda self: self._parse_create_like(),
 944        "NOT": lambda self: self._parse_not_constraint(),
 945        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 946        "ON": lambda self: (
 947            self._match(TokenType.UPDATE)
 948            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 949        )
 950        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 951        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 952        "PERIOD": lambda self: self._parse_period_for_system_time(),
 953        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 954        "REFERENCES": lambda self: self._parse_references(match=False),
 955        "TITLE": lambda self: self.expression(
 956            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 957        ),
 958        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 959        "UNIQUE": lambda self: self._parse_unique(),
 960        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 961        "WITH": lambda self: self.expression(
 962            exp.Properties, expressions=self._parse_wrapped_properties()
 963        ),
 964    }
 965
 966    ALTER_PARSERS = {
 967        "ADD": lambda self: self._parse_alter_table_add(),
 968        "ALTER": lambda self: self._parse_alter_table_alter(),
 969        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 970        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 971        "DROP": lambda self: self._parse_alter_table_drop(),
 972        "RENAME": lambda self: self._parse_alter_table_rename(),
 973        "SET": lambda self: self._parse_alter_table_set(),
 974    }
 975
 976    ALTER_ALTER_PARSERS = {
 977        "DISTKEY": lambda self: self._parse_alter_diststyle(),
 978        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
 979        "SORTKEY": lambda self: self._parse_alter_sortkey(),
 980        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
 981    }
 982
 983    SCHEMA_UNNAMED_CONSTRAINTS = {
 984        "CHECK",
 985        "EXCLUDE",
 986        "FOREIGN KEY",
 987        "LIKE",
 988        "PERIOD",
 989        "PRIMARY KEY",
 990        "UNIQUE",
 991    }
 992
 993    NO_PAREN_FUNCTION_PARSERS = {
 994        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 995        "CASE": lambda self: self._parse_case(),
 996        "IF": lambda self: self._parse_if(),
 997        "NEXT": lambda self: self._parse_next_value_for(),
 998    }
 999
1000    INVALID_FUNC_NAME_TOKENS = {
1001        TokenType.IDENTIFIER,
1002        TokenType.STRING,
1003    }
1004
1005    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1006
1007    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1008
1009    FUNCTION_PARSERS = {
1010        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1011        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1012        "DECODE": lambda self: self._parse_decode(),
1013        "EXTRACT": lambda self: self._parse_extract(),
1014        "GAP_FILL": lambda self: self._parse_gap_fill(),
1015        "JSON_OBJECT": lambda self: self._parse_json_object(),
1016        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1017        "JSON_TABLE": lambda self: self._parse_json_table(),
1018        "MATCH": lambda self: self._parse_match_against(),
1019        "OPENJSON": lambda self: self._parse_open_json(),
1020        "POSITION": lambda self: self._parse_position(),
1021        "PREDICT": lambda self: self._parse_predict(),
1022        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1023        "STRING_AGG": lambda self: self._parse_string_agg(),
1024        "SUBSTRING": lambda self: self._parse_substring(),
1025        "TRIM": lambda self: self._parse_trim(),
1026        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1027        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1028    }
1029
1030    QUERY_MODIFIER_PARSERS = {
1031        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1032        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1033        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1034        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1035        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1036        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1037        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1038        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1039        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1040        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1041        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1042        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1043        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1044        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1045        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1046        TokenType.CLUSTER_BY: lambda self: (
1047            "cluster",
1048            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1049        ),
1050        TokenType.DISTRIBUTE_BY: lambda self: (
1051            "distribute",
1052            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1053        ),
1054        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1055        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1056        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1057    }
1058
1059    SET_PARSERS = {
1060        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1061        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1062        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1063        "TRANSACTION": lambda self: self._parse_set_transaction(),
1064    }
1065
1066    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1067
1068    TYPE_LITERAL_PARSERS = {
1069        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1070    }
1071
1072    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1073
1074    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1075
1076    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1077
1078    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1079    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1080        "ISOLATION": (
1081            ("LEVEL", "REPEATABLE", "READ"),
1082            ("LEVEL", "READ", "COMMITTED"),
1083            ("LEVEL", "READ", "UNCOMITTED"),
1084            ("LEVEL", "SERIALIZABLE"),
1085        ),
1086        "READ": ("WRITE", "ONLY"),
1087    }
1088
1089    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1090        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1091    )
1092    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1093
1094    CREATE_SEQUENCE: OPTIONS_TYPE = {
1095        "SCALE": ("EXTEND", "NOEXTEND"),
1096        "SHARD": ("EXTEND", "NOEXTEND"),
1097        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1098        **dict.fromkeys(
1099            (
1100                "SESSION",
1101                "GLOBAL",
1102                "KEEP",
1103                "NOKEEP",
1104                "ORDER",
1105                "NOORDER",
1106                "NOCACHE",
1107                "CYCLE",
1108                "NOCYCLE",
1109                "NOMINVALUE",
1110                "NOMAXVALUE",
1111                "NOSCALE",
1112                "NOSHARD",
1113            ),
1114            tuple(),
1115        ),
1116    }
1117
1118    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1119
1120    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
1121
1122    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1123
1124    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1125
1126    CLONE_KEYWORDS = {"CLONE", "COPY"}
1127    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1128
1129    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1130
1131    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1132
1133    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1134
1135    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1136
1137    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1138    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1139    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1140
1141    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1142
1143    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1144
1145    ADD_CONSTRAINT_TOKENS = {
1146        TokenType.CONSTRAINT,
1147        TokenType.FOREIGN_KEY,
1148        TokenType.INDEX,
1149        TokenType.KEY,
1150        TokenType.PRIMARY_KEY,
1151        TokenType.UNIQUE,
1152    }
1153
1154    DISTINCT_TOKENS = {TokenType.DISTINCT}
1155
1156    NULL_TOKENS = {TokenType.NULL}
1157
1158    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1159
1160    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1161
1162    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1163
1164    STRICT_CAST = True
1165
1166    PREFIXED_PIVOT_COLUMNS = False
1167    IDENTIFY_PIVOT_STRINGS = False
1168
1169    LOG_DEFAULTS_TO_LN = False
1170
1171    # Whether ADD is present for each column added by ALTER TABLE
1172    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1173
1174    # Whether the table sample clause expects CSV syntax
1175    TABLESAMPLE_CSV = False
1176
1177    # The default method used for table sampling
1178    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1179
1180    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1181    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1182
1183    # Whether the TRIM function expects the characters to trim as its first argument
1184    TRIM_PATTERN_FIRST = False
1185
1186    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1187    STRING_ALIASES = False
1188
1189    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1190    MODIFIERS_ATTACHED_TO_SET_OP = True
1191    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1192
1193    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1194    NO_PAREN_IF_COMMANDS = True
1195
1196    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1197    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1198
1199    # Whether the `:` operator is used to extract a value from a JSON document
1200    COLON_IS_JSON_EXTRACT = False
1201
1202    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1203    # If this is True and '(' is not found, the keyword will be treated as an identifier
1204    VALUES_FOLLOWED_BY_PAREN = True
1205
1206    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1207    SUPPORTS_IMPLICIT_UNNEST = False
1208
1209    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1210    INTERVAL_SPANS = True
1211
1212    # Whether a PARTITION clause can follow a table reference
1213    SUPPORTS_PARTITION_SELECTION = False
1214
1215    __slots__ = (
1216        "error_level",
1217        "error_message_context",
1218        "max_errors",
1219        "dialect",
1220        "sql",
1221        "errors",
1222        "_tokens",
1223        "_index",
1224        "_curr",
1225        "_next",
1226        "_prev",
1227        "_prev_comments",
1228    )
1229
1230    # Autofilled
1231    SHOW_TRIE: t.Dict = {}
1232    SET_TRIE: t.Dict = {}
1233
1234    def __init__(
1235        self,
1236        error_level: t.Optional[ErrorLevel] = None,
1237        error_message_context: int = 100,
1238        max_errors: int = 3,
1239        dialect: DialectType = None,
1240    ):
1241        from sqlglot.dialects import Dialect
1242
1243        self.error_level = error_level or ErrorLevel.IMMEDIATE
1244        self.error_message_context = error_message_context
1245        self.max_errors = max_errors
1246        self.dialect = Dialect.get_or_raise(dialect)
1247        self.reset()
1248
1249    def reset(self):
1250        self.sql = ""
1251        self.errors = []
1252        self._tokens = []
1253        self._index = 0
1254        self._curr = None
1255        self._next = None
1256        self._prev = None
1257        self._prev_comments = None
1258
1259    def parse(
1260        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1261    ) -> t.List[t.Optional[exp.Expression]]:
1262        """
1263        Parses a list of tokens and returns a list of syntax trees, one tree
1264        per parsed SQL statement.
1265
1266        Args:
1267            raw_tokens: The list of tokens.
1268            sql: The original SQL string, used to produce helpful debug messages.
1269
1270        Returns:
1271            The list of the produced syntax trees.
1272        """
1273        return self._parse(
1274            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1275        )
1276
1277    def parse_into(
1278        self,
1279        expression_types: exp.IntoType,
1280        raw_tokens: t.List[Token],
1281        sql: t.Optional[str] = None,
1282    ) -> t.List[t.Optional[exp.Expression]]:
1283        """
1284        Parses a list of tokens into a given Expression type. If a collection of Expression
1285        types is given instead, this method will try to parse the token list into each one
1286        of them, stopping at the first for which the parsing succeeds.
1287
1288        Args:
1289            expression_types: The expression type(s) to try and parse the token list into.
1290            raw_tokens: The list of tokens.
1291            sql: The original SQL string, used to produce helpful debug messages.
1292
1293        Returns:
1294            The target Expression.
1295        """
1296        errors = []
1297        for expression_type in ensure_list(expression_types):
1298            parser = self.EXPRESSION_PARSERS.get(expression_type)
1299            if not parser:
1300                raise TypeError(f"No parser registered for {expression_type}")
1301
1302            try:
1303                return self._parse(parser, raw_tokens, sql)
1304            except ParseError as e:
1305                e.errors[0]["into_expression"] = expression_type
1306                errors.append(e)
1307
1308        raise ParseError(
1309            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1310            errors=merge_errors(errors),
1311        ) from errors[-1]
1312
1313    def _parse(
1314        self,
1315        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1316        raw_tokens: t.List[Token],
1317        sql: t.Optional[str] = None,
1318    ) -> t.List[t.Optional[exp.Expression]]:
1319        self.reset()
1320        self.sql = sql or ""
1321
1322        total = len(raw_tokens)
1323        chunks: t.List[t.List[Token]] = [[]]
1324
1325        for i, token in enumerate(raw_tokens):
1326            if token.token_type == TokenType.SEMICOLON:
1327                if token.comments:
1328                    chunks.append([token])
1329
1330                if i < total - 1:
1331                    chunks.append([])
1332            else:
1333                chunks[-1].append(token)
1334
1335        expressions = []
1336
1337        for tokens in chunks:
1338            self._index = -1
1339            self._tokens = tokens
1340            self._advance()
1341
1342            expressions.append(parse_method(self))
1343
1344            if self._index < len(self._tokens):
1345                self.raise_error("Invalid expression / Unexpected token")
1346
1347            self.check_errors()
1348
1349        return expressions
1350
1351    def check_errors(self) -> None:
1352        """Logs or raises any found errors, depending on the chosen error level setting."""
1353        if self.error_level == ErrorLevel.WARN:
1354            for error in self.errors:
1355                logger.error(str(error))
1356        elif self.error_level == ErrorLevel.RAISE and self.errors:
1357            raise ParseError(
1358                concat_messages(self.errors, self.max_errors),
1359                errors=merge_errors(self.errors),
1360            )
1361
1362    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1363        """
1364        Appends an error in the list of recorded errors or raises it, depending on the chosen
1365        error level setting.
1366        """
1367        token = token or self._curr or self._prev or Token.string("")
1368        start = token.start
1369        end = token.end + 1
1370        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1371        highlight = self.sql[start:end]
1372        end_context = self.sql[end : end + self.error_message_context]
1373
1374        error = ParseError.new(
1375            f"{message}. Line {token.line}, Col: {token.col}.\n"
1376            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1377            description=message,
1378            line=token.line,
1379            col=token.col,
1380            start_context=start_context,
1381            highlight=highlight,
1382            end_context=end_context,
1383        )
1384
1385        if self.error_level == ErrorLevel.IMMEDIATE:
1386            raise error
1387
1388        self.errors.append(error)
1389
1390    def expression(
1391        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1392    ) -> E:
1393        """
1394        Creates a new, validated Expression.
1395
1396        Args:
1397            exp_class: The expression class to instantiate.
1398            comments: An optional list of comments to attach to the expression.
1399            kwargs: The arguments to set for the expression along with their respective values.
1400
1401        Returns:
1402            The target expression.
1403        """
1404        instance = exp_class(**kwargs)
1405        instance.add_comments(comments) if comments else self._add_comments(instance)
1406        return self.validate_expression(instance)
1407
1408    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1409        if expression and self._prev_comments:
1410            expression.add_comments(self._prev_comments)
1411            self._prev_comments = None
1412
1413    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1414        """
1415        Validates an Expression, making sure that all its mandatory arguments are set.
1416
1417        Args:
1418            expression: The expression to validate.
1419            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1420
1421        Returns:
1422            The validated expression.
1423        """
1424        if self.error_level != ErrorLevel.IGNORE:
1425            for error_message in expression.error_messages(args):
1426                self.raise_error(error_message)
1427
1428        return expression
1429
1430    def _find_sql(self, start: Token, end: Token) -> str:
1431        return self.sql[start.start : end.end + 1]
1432
1433    def _is_connected(self) -> bool:
1434        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1435
1436    def _advance(self, times: int = 1) -> None:
1437        self._index += times
1438        self._curr = seq_get(self._tokens, self._index)
1439        self._next = seq_get(self._tokens, self._index + 1)
1440
1441        if self._index > 0:
1442            self._prev = self._tokens[self._index - 1]
1443            self._prev_comments = self._prev.comments
1444        else:
1445            self._prev = None
1446            self._prev_comments = None
1447
1448    def _retreat(self, index: int) -> None:
1449        if index != self._index:
1450            self._advance(index - self._index)
1451
1452    def _warn_unsupported(self) -> None:
1453        if len(self._tokens) <= 1:
1454            return
1455
1456        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1457        # interested in emitting a warning for the one being currently processed.
1458        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1459
1460        logger.warning(
1461            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1462        )
1463
1464    def _parse_command(self) -> exp.Command:
1465        self._warn_unsupported()
1466        return self.expression(
1467            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1468        )
1469
1470    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1471        """
1472        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
1473        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
1474        the parser state accordingly
1475        """
1476        index = self._index
1477        error_level = self.error_level
1478
1479        self.error_level = ErrorLevel.IMMEDIATE
1480        try:
1481            this = parse_method()
1482        except ParseError:
1483            this = None
1484        finally:
1485            if not this or retreat:
1486                self._retreat(index)
1487            self.error_level = error_level
1488
1489        return this
1490
1491    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1492        start = self._prev
1493        exists = self._parse_exists() if allow_exists else None
1494
1495        self._match(TokenType.ON)
1496
1497        materialized = self._match_text_seq("MATERIALIZED")
1498        kind = self._match_set(self.CREATABLES) and self._prev
1499        if not kind:
1500            return self._parse_as_command(start)
1501
1502        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1503            this = self._parse_user_defined_function(kind=kind.token_type)
1504        elif kind.token_type == TokenType.TABLE:
1505            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1506        elif kind.token_type == TokenType.COLUMN:
1507            this = self._parse_column()
1508        else:
1509            this = self._parse_id_var()
1510
1511        self._match(TokenType.IS)
1512
1513        return self.expression(
1514            exp.Comment,
1515            this=this,
1516            kind=kind.text,
1517            expression=self._parse_string(),
1518            exists=exists,
1519            materialized=materialized,
1520        )
1521
1522    def _parse_to_table(
1523        self,
1524    ) -> exp.ToTableProperty:
1525        table = self._parse_table_parts(schema=True)
1526        return self.expression(exp.ToTableProperty, this=table)
1527
1528    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1529    def _parse_ttl(self) -> exp.Expression:
1530        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1531            this = self._parse_bitwise()
1532
1533            if self._match_text_seq("DELETE"):
1534                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1535            if self._match_text_seq("RECOMPRESS"):
1536                return self.expression(
1537                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1538                )
1539            if self._match_text_seq("TO", "DISK"):
1540                return self.expression(
1541                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1542                )
1543            if self._match_text_seq("TO", "VOLUME"):
1544                return self.expression(
1545                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1546                )
1547
1548            return this
1549
1550        expressions = self._parse_csv(_parse_ttl_action)
1551        where = self._parse_where()
1552        group = self._parse_group()
1553
1554        aggregates = None
1555        if group and self._match(TokenType.SET):
1556            aggregates = self._parse_csv(self._parse_set_item)
1557
1558        return self.expression(
1559            exp.MergeTreeTTL,
1560            expressions=expressions,
1561            where=where,
1562            group=group,
1563            aggregates=aggregates,
1564        )
1565
1566    def _parse_statement(self) -> t.Optional[exp.Expression]:
1567        if self._curr is None:
1568            return None
1569
1570        if self._match_set(self.STATEMENT_PARSERS):
1571            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1572
1573        if self._match_set(self.dialect.tokenizer.COMMANDS):
1574            return self._parse_command()
1575
1576        expression = self._parse_expression()
1577        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1578        return self._parse_query_modifiers(expression)
1579
1580    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1581        start = self._prev
1582        temporary = self._match(TokenType.TEMPORARY)
1583        materialized = self._match_text_seq("MATERIALIZED")
1584
1585        kind = self._match_set(self.CREATABLES) and self._prev.text
1586        if not kind:
1587            return self._parse_as_command(start)
1588
1589        if_exists = exists or self._parse_exists()
1590        table = self._parse_table_parts(
1591            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1592        )
1593
1594        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1595
1596        if self._match(TokenType.L_PAREN, advance=False):
1597            expressions = self._parse_wrapped_csv(self._parse_types)
1598        else:
1599            expressions = None
1600
1601        return self.expression(
1602            exp.Drop,
1603            comments=start.comments,
1604            exists=if_exists,
1605            this=table,
1606            expressions=expressions,
1607            kind=kind.upper(),
1608            temporary=temporary,
1609            materialized=materialized,
1610            cascade=self._match_text_seq("CASCADE"),
1611            constraints=self._match_text_seq("CONSTRAINTS"),
1612            purge=self._match_text_seq("PURGE"),
1613            cluster=cluster,
1614        )
1615
1616    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1617        return (
1618            self._match_text_seq("IF")
1619            and (not not_ or self._match(TokenType.NOT))
1620            and self._match(TokenType.EXISTS)
1621        )
1622
1623    def _parse_create(self) -> exp.Create | exp.Command:
1624        # Note: this can't be None because we've matched a statement parser
1625        start = self._prev
1626        comments = self._prev_comments
1627
1628        replace = (
1629            start.token_type == TokenType.REPLACE
1630            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1631            or self._match_pair(TokenType.OR, TokenType.ALTER)
1632        )
1633
1634        unique = self._match(TokenType.UNIQUE)
1635
1636        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1637            self._advance()
1638
1639        properties = None
1640        create_token = self._match_set(self.CREATABLES) and self._prev
1641
1642        if not create_token:
1643            # exp.Properties.Location.POST_CREATE
1644            properties = self._parse_properties()
1645            create_token = self._match_set(self.CREATABLES) and self._prev
1646
1647            if not properties or not create_token:
1648                return self._parse_as_command(start)
1649
1650        exists = self._parse_exists(not_=True)
1651        this = None
1652        expression: t.Optional[exp.Expression] = None
1653        indexes = None
1654        no_schema_binding = None
1655        begin = None
1656        end = None
1657        clone = None
1658
1659        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1660            nonlocal properties
1661            if properties and temp_props:
1662                properties.expressions.extend(temp_props.expressions)
1663            elif temp_props:
1664                properties = temp_props
1665
1666        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1667            this = self._parse_user_defined_function(kind=create_token.token_type)
1668
1669            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1670            extend_props(self._parse_properties())
1671
1672            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1673            extend_props(self._parse_properties())
1674
1675            if not expression:
1676                if self._match(TokenType.COMMAND):
1677                    expression = self._parse_as_command(self._prev)
1678                else:
1679                    begin = self._match(TokenType.BEGIN)
1680                    return_ = self._match_text_seq("RETURN")
1681
1682                    if self._match(TokenType.STRING, advance=False):
1683                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1684                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1685                        expression = self._parse_string()
1686                        extend_props(self._parse_properties())
1687                    else:
1688                        expression = self._parse_statement()
1689
1690                    end = self._match_text_seq("END")
1691
1692                    if return_:
1693                        expression = self.expression(exp.Return, this=expression)
1694        elif create_token.token_type == TokenType.INDEX:
1695            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1696            if not self._match(TokenType.ON):
1697                index = self._parse_id_var()
1698                anonymous = False
1699            else:
1700                index = None
1701                anonymous = True
1702
1703            this = self._parse_index(index=index, anonymous=anonymous)
1704        elif create_token.token_type in self.DB_CREATABLES:
1705            table_parts = self._parse_table_parts(
1706                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1707            )
1708
1709            # exp.Properties.Location.POST_NAME
1710            self._match(TokenType.COMMA)
1711            extend_props(self._parse_properties(before=True))
1712
1713            this = self._parse_schema(this=table_parts)
1714
1715            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1716            extend_props(self._parse_properties())
1717
1718            self._match(TokenType.ALIAS)
1719            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1720                # exp.Properties.Location.POST_ALIAS
1721                extend_props(self._parse_properties())
1722
1723            if create_token.token_type == TokenType.SEQUENCE:
1724                expression = self._parse_types()
1725                extend_props(self._parse_properties())
1726            else:
1727                expression = self._parse_ddl_select()
1728
1729            if create_token.token_type == TokenType.TABLE:
1730                # exp.Properties.Location.POST_EXPRESSION
1731                extend_props(self._parse_properties())
1732
1733                indexes = []
1734                while True:
1735                    index = self._parse_index()
1736
1737                    # exp.Properties.Location.POST_INDEX
1738                    extend_props(self._parse_properties())
1739
1740                    if not index:
1741                        break
1742                    else:
1743                        self._match(TokenType.COMMA)
1744                        indexes.append(index)
1745            elif create_token.token_type == TokenType.VIEW:
1746                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1747                    no_schema_binding = True
1748
1749            shallow = self._match_text_seq("SHALLOW")
1750
1751            if self._match_texts(self.CLONE_KEYWORDS):
1752                copy = self._prev.text.lower() == "copy"
1753                clone = self.expression(
1754                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1755                )
1756
1757        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1758            return self._parse_as_command(start)
1759
1760        return self.expression(
1761            exp.Create,
1762            comments=comments,
1763            this=this,
1764            kind=create_token.text.upper(),
1765            replace=replace,
1766            unique=unique,
1767            expression=expression,
1768            exists=exists,
1769            properties=properties,
1770            indexes=indexes,
1771            no_schema_binding=no_schema_binding,
1772            begin=begin,
1773            end=end,
1774            clone=clone,
1775        )
1776
1777    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1778        seq = exp.SequenceProperties()
1779
1780        options = []
1781        index = self._index
1782
1783        while self._curr:
1784            self._match(TokenType.COMMA)
1785            if self._match_text_seq("INCREMENT"):
1786                self._match_text_seq("BY")
1787                self._match_text_seq("=")
1788                seq.set("increment", self._parse_term())
1789            elif self._match_text_seq("MINVALUE"):
1790                seq.set("minvalue", self._parse_term())
1791            elif self._match_text_seq("MAXVALUE"):
1792                seq.set("maxvalue", self._parse_term())
1793            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1794                self._match_text_seq("=")
1795                seq.set("start", self._parse_term())
1796            elif self._match_text_seq("CACHE"):
1797                # T-SQL allows empty CACHE which is initialized dynamically
1798                seq.set("cache", self._parse_number() or True)
1799            elif self._match_text_seq("OWNED", "BY"):
1800                # "OWNED BY NONE" is the default
1801                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1802            else:
1803                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1804                if opt:
1805                    options.append(opt)
1806                else:
1807                    break
1808
1809        seq.set("options", options if options else None)
1810        return None if self._index == index else seq
1811
1812    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1813        # only used for teradata currently
1814        self._match(TokenType.COMMA)
1815
1816        kwargs = {
1817            "no": self._match_text_seq("NO"),
1818            "dual": self._match_text_seq("DUAL"),
1819            "before": self._match_text_seq("BEFORE"),
1820            "default": self._match_text_seq("DEFAULT"),
1821            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1822            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1823            "after": self._match_text_seq("AFTER"),
1824            "minimum": self._match_texts(("MIN", "MINIMUM")),
1825            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1826        }
1827
1828        if self._match_texts(self.PROPERTY_PARSERS):
1829            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1830            try:
1831                return parser(self, **{k: v for k, v in kwargs.items() if v})
1832            except TypeError:
1833                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1834
1835        return None
1836
1837    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1838        return self._parse_wrapped_csv(self._parse_property)
1839
1840    def _parse_property(self) -> t.Optional[exp.Expression]:
1841        if self._match_texts(self.PROPERTY_PARSERS):
1842            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1843
1844        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1845            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1846
1847        if self._match_text_seq("COMPOUND", "SORTKEY"):
1848            return self._parse_sortkey(compound=True)
1849
1850        if self._match_text_seq("SQL", "SECURITY"):
1851            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1852
1853        index = self._index
1854        key = self._parse_column()
1855
1856        if not self._match(TokenType.EQ):
1857            self._retreat(index)
1858            return self._parse_sequence_properties()
1859
1860        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
1861        if isinstance(key, exp.Column):
1862            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
1863
1864        value = self._parse_bitwise() or self._parse_var(any_token=True)
1865
1866        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
1867        if isinstance(value, exp.Column):
1868            value = exp.var(value.name)
1869
1870        return self.expression(exp.Property, this=key, value=value)
1871
1872    def _parse_stored(self) -> exp.FileFormatProperty:
1873        self._match(TokenType.ALIAS)
1874
1875        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1876        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1877
1878        return self.expression(
1879            exp.FileFormatProperty,
1880            this=(
1881                self.expression(
1882                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1883                )
1884                if input_format or output_format
1885                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1886            ),
1887        )
1888
1889    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
1890        field = self._parse_field()
1891        if isinstance(field, exp.Identifier) and not field.quoted:
1892            field = exp.var(field)
1893
1894        return field
1895
1896    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1897        self._match(TokenType.EQ)
1898        self._match(TokenType.ALIAS)
1899
1900        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1901
1902    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1903        properties = []
1904        while True:
1905            if before:
1906                prop = self._parse_property_before()
1907            else:
1908                prop = self._parse_property()
1909            if not prop:
1910                break
1911            for p in ensure_list(prop):
1912                properties.append(p)
1913
1914        if properties:
1915            return self.expression(exp.Properties, expressions=properties)
1916
1917        return None
1918
1919    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1920        return self.expression(
1921            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1922        )
1923
1924    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1925        if self._index >= 2:
1926            pre_volatile_token = self._tokens[self._index - 2]
1927        else:
1928            pre_volatile_token = None
1929
1930        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1931            return exp.VolatileProperty()
1932
1933        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1934
1935    def _parse_retention_period(self) -> exp.Var:
1936        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
1937        number = self._parse_number()
1938        number_str = f"{number} " if number else ""
1939        unit = self._parse_var(any_token=True)
1940        return exp.var(f"{number_str}{unit}")
1941
1942    def _parse_system_versioning_property(
1943        self, with_: bool = False
1944    ) -> exp.WithSystemVersioningProperty:
1945        self._match(TokenType.EQ)
1946        prop = self.expression(
1947            exp.WithSystemVersioningProperty,
1948            **{  # type: ignore
1949                "on": True,
1950                "with": with_,
1951            },
1952        )
1953
1954        if self._match_text_seq("OFF"):
1955            prop.set("on", False)
1956            return prop
1957
1958        self._match(TokenType.ON)
1959        if self._match(TokenType.L_PAREN):
1960            while self._curr and not self._match(TokenType.R_PAREN):
1961                if self._match_text_seq("HISTORY_TABLE", "="):
1962                    prop.set("this", self._parse_table_parts())
1963                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
1964                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
1965                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
1966                    prop.set("retention_period", self._parse_retention_period())
1967
1968                self._match(TokenType.COMMA)
1969
1970        return prop
1971
1972    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
1973        self._match(TokenType.EQ)
1974        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
1975        prop = self.expression(exp.DataDeletionProperty, on=on)
1976
1977        if self._match(TokenType.L_PAREN):
1978            while self._curr and not self._match(TokenType.R_PAREN):
1979                if self._match_text_seq("FILTER_COLUMN", "="):
1980                    prop.set("filter_column", self._parse_column())
1981                elif self._match_text_seq("RETENTION_PERIOD", "="):
1982                    prop.set("retention_period", self._parse_retention_period())
1983
1984                self._match(TokenType.COMMA)
1985
1986        return prop
1987
1988    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1989        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
1990            prop = self._parse_system_versioning_property(with_=True)
1991            self._match_r_paren()
1992            return prop
1993
1994        if self._match(TokenType.L_PAREN, advance=False):
1995            return self._parse_wrapped_properties()
1996
1997        if self._match_text_seq("JOURNAL"):
1998            return self._parse_withjournaltable()
1999
2000        if self._match_texts(self.VIEW_ATTRIBUTES):
2001            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2002
2003        if self._match_text_seq("DATA"):
2004            return self._parse_withdata(no=False)
2005        elif self._match_text_seq("NO", "DATA"):
2006            return self._parse_withdata(no=True)
2007
2008        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2009            return self._parse_serde_properties(with_=True)
2010
2011        if not self._next:
2012            return None
2013
2014        return self._parse_withisolatedloading()
2015
2016    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2017    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2018        self._match(TokenType.EQ)
2019
2020        user = self._parse_id_var()
2021        self._match(TokenType.PARAMETER)
2022        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2023
2024        if not user or not host:
2025            return None
2026
2027        return exp.DefinerProperty(this=f"{user}@{host}")
2028
2029    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2030        self._match(TokenType.TABLE)
2031        self._match(TokenType.EQ)
2032        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2033
2034    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2035        return self.expression(exp.LogProperty, no=no)
2036
2037    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2038        return self.expression(exp.JournalProperty, **kwargs)
2039
2040    def _parse_checksum(self) -> exp.ChecksumProperty:
2041        self._match(TokenType.EQ)
2042
2043        on = None
2044        if self._match(TokenType.ON):
2045            on = True
2046        elif self._match_text_seq("OFF"):
2047            on = False
2048
2049        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2050
2051    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2052        return self.expression(
2053            exp.Cluster,
2054            expressions=(
2055                self._parse_wrapped_csv(self._parse_ordered)
2056                if wrapped
2057                else self._parse_csv(self._parse_ordered)
2058            ),
2059        )
2060
2061    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2062        self._match_text_seq("BY")
2063
2064        self._match_l_paren()
2065        expressions = self._parse_csv(self._parse_column)
2066        self._match_r_paren()
2067
2068        if self._match_text_seq("SORTED", "BY"):
2069            self._match_l_paren()
2070            sorted_by = self._parse_csv(self._parse_ordered)
2071            self._match_r_paren()
2072        else:
2073            sorted_by = None
2074
2075        self._match(TokenType.INTO)
2076        buckets = self._parse_number()
2077        self._match_text_seq("BUCKETS")
2078
2079        return self.expression(
2080            exp.ClusteredByProperty,
2081            expressions=expressions,
2082            sorted_by=sorted_by,
2083            buckets=buckets,
2084        )
2085
2086    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2087        if not self._match_text_seq("GRANTS"):
2088            self._retreat(self._index - 1)
2089            return None
2090
2091        return self.expression(exp.CopyGrantsProperty)
2092
2093    def _parse_freespace(self) -> exp.FreespaceProperty:
2094        self._match(TokenType.EQ)
2095        return self.expression(
2096            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2097        )
2098
2099    def _parse_mergeblockratio(
2100        self, no: bool = False, default: bool = False
2101    ) -> exp.MergeBlockRatioProperty:
2102        if self._match(TokenType.EQ):
2103            return self.expression(
2104                exp.MergeBlockRatioProperty,
2105                this=self._parse_number(),
2106                percent=self._match(TokenType.PERCENT),
2107            )
2108
2109        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2110
2111    def _parse_datablocksize(
2112        self,
2113        default: t.Optional[bool] = None,
2114        minimum: t.Optional[bool] = None,
2115        maximum: t.Optional[bool] = None,
2116    ) -> exp.DataBlocksizeProperty:
2117        self._match(TokenType.EQ)
2118        size = self._parse_number()
2119
2120        units = None
2121        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2122            units = self._prev.text
2123
2124        return self.expression(
2125            exp.DataBlocksizeProperty,
2126            size=size,
2127            units=units,
2128            default=default,
2129            minimum=minimum,
2130            maximum=maximum,
2131        )
2132
2133    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2134        self._match(TokenType.EQ)
2135        always = self._match_text_seq("ALWAYS")
2136        manual = self._match_text_seq("MANUAL")
2137        never = self._match_text_seq("NEVER")
2138        default = self._match_text_seq("DEFAULT")
2139
2140        autotemp = None
2141        if self._match_text_seq("AUTOTEMP"):
2142            autotemp = self._parse_schema()
2143
2144        return self.expression(
2145            exp.BlockCompressionProperty,
2146            always=always,
2147            manual=manual,
2148            never=never,
2149            default=default,
2150            autotemp=autotemp,
2151        )
2152
2153    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2154        index = self._index
2155        no = self._match_text_seq("NO")
2156        concurrent = self._match_text_seq("CONCURRENT")
2157
2158        if not self._match_text_seq("ISOLATED", "LOADING"):
2159            self._retreat(index)
2160            return None
2161
2162        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2163        return self.expression(
2164            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2165        )
2166
2167    def _parse_locking(self) -> exp.LockingProperty:
2168        if self._match(TokenType.TABLE):
2169            kind = "TABLE"
2170        elif self._match(TokenType.VIEW):
2171            kind = "VIEW"
2172        elif self._match(TokenType.ROW):
2173            kind = "ROW"
2174        elif self._match_text_seq("DATABASE"):
2175            kind = "DATABASE"
2176        else:
2177            kind = None
2178
2179        if kind in ("DATABASE", "TABLE", "VIEW"):
2180            this = self._parse_table_parts()
2181        else:
2182            this = None
2183
2184        if self._match(TokenType.FOR):
2185            for_or_in = "FOR"
2186        elif self._match(TokenType.IN):
2187            for_or_in = "IN"
2188        else:
2189            for_or_in = None
2190
2191        if self._match_text_seq("ACCESS"):
2192            lock_type = "ACCESS"
2193        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2194            lock_type = "EXCLUSIVE"
2195        elif self._match_text_seq("SHARE"):
2196            lock_type = "SHARE"
2197        elif self._match_text_seq("READ"):
2198            lock_type = "READ"
2199        elif self._match_text_seq("WRITE"):
2200            lock_type = "WRITE"
2201        elif self._match_text_seq("CHECKSUM"):
2202            lock_type = "CHECKSUM"
2203        else:
2204            lock_type = None
2205
2206        override = self._match_text_seq("OVERRIDE")
2207
2208        return self.expression(
2209            exp.LockingProperty,
2210            this=this,
2211            kind=kind,
2212            for_or_in=for_or_in,
2213            lock_type=lock_type,
2214            override=override,
2215        )
2216
2217    def _parse_partition_by(self) -> t.List[exp.Expression]:
2218        if self._match(TokenType.PARTITION_BY):
2219            return self._parse_csv(self._parse_assignment)
2220        return []
2221
2222    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2223        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2224            if self._match_text_seq("MINVALUE"):
2225                return exp.var("MINVALUE")
2226            if self._match_text_seq("MAXVALUE"):
2227                return exp.var("MAXVALUE")
2228            return self._parse_bitwise()
2229
2230        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2231        expression = None
2232        from_expressions = None
2233        to_expressions = None
2234
2235        if self._match(TokenType.IN):
2236            this = self._parse_wrapped_csv(self._parse_bitwise)
2237        elif self._match(TokenType.FROM):
2238            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2239            self._match_text_seq("TO")
2240            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2241        elif self._match_text_seq("WITH", "(", "MODULUS"):
2242            this = self._parse_number()
2243            self._match_text_seq(",", "REMAINDER")
2244            expression = self._parse_number()
2245            self._match_r_paren()
2246        else:
2247            self.raise_error("Failed to parse partition bound spec.")
2248
2249        return self.expression(
2250            exp.PartitionBoundSpec,
2251            this=this,
2252            expression=expression,
2253            from_expressions=from_expressions,
2254            to_expressions=to_expressions,
2255        )
2256
2257    # https://www.postgresql.org/docs/current/sql-createtable.html
2258    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2259        if not self._match_text_seq("OF"):
2260            self._retreat(self._index - 1)
2261            return None
2262
2263        this = self._parse_table(schema=True)
2264
2265        if self._match(TokenType.DEFAULT):
2266            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2267        elif self._match_text_seq("FOR", "VALUES"):
2268            expression = self._parse_partition_bound_spec()
2269        else:
2270            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2271
2272        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2273
2274    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2275        self._match(TokenType.EQ)
2276        return self.expression(
2277            exp.PartitionedByProperty,
2278            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2279        )
2280
2281    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2282        if self._match_text_seq("AND", "STATISTICS"):
2283            statistics = True
2284        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2285            statistics = False
2286        else:
2287            statistics = None
2288
2289        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2290
2291    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2292        if self._match_text_seq("SQL"):
2293            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2294        return None
2295
2296    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2297        if self._match_text_seq("SQL", "DATA"):
2298            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2299        return None
2300
2301    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2302        if self._match_text_seq("PRIMARY", "INDEX"):
2303            return exp.NoPrimaryIndexProperty()
2304        if self._match_text_seq("SQL"):
2305            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2306        return None
2307
2308    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2309        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2310            return exp.OnCommitProperty()
2311        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2312            return exp.OnCommitProperty(delete=True)
2313        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2314
2315    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2316        if self._match_text_seq("SQL", "DATA"):
2317            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2318        return None
2319
2320    def _parse_distkey(self) -> exp.DistKeyProperty:
2321        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2322
2323    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2324        table = self._parse_table(schema=True)
2325
2326        options = []
2327        while self._match_texts(("INCLUDING", "EXCLUDING")):
2328            this = self._prev.text.upper()
2329
2330            id_var = self._parse_id_var()
2331            if not id_var:
2332                return None
2333
2334            options.append(
2335                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2336            )
2337
2338        return self.expression(exp.LikeProperty, this=table, expressions=options)
2339
2340    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2341        return self.expression(
2342            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2343        )
2344
2345    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2346        self._match(TokenType.EQ)
2347        return self.expression(
2348            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2349        )
2350
2351    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2352        self._match_text_seq("WITH", "CONNECTION")
2353        return self.expression(
2354            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2355        )
2356
2357    def _parse_returns(self) -> exp.ReturnsProperty:
2358        value: t.Optional[exp.Expression]
2359        null = None
2360        is_table = self._match(TokenType.TABLE)
2361
2362        if is_table:
2363            if self._match(TokenType.LT):
2364                value = self.expression(
2365                    exp.Schema,
2366                    this="TABLE",
2367                    expressions=self._parse_csv(self._parse_struct_types),
2368                )
2369                if not self._match(TokenType.GT):
2370                    self.raise_error("Expecting >")
2371            else:
2372                value = self._parse_schema(exp.var("TABLE"))
2373        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2374            null = True
2375            value = None
2376        else:
2377            value = self._parse_types()
2378
2379        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2380
2381    def _parse_describe(self) -> exp.Describe:
2382        kind = self._match_set(self.CREATABLES) and self._prev.text
2383        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2384        if self._match(TokenType.DOT):
2385            style = None
2386            self._retreat(self._index - 2)
2387        this = self._parse_table(schema=True)
2388        properties = self._parse_properties()
2389        expressions = properties.expressions if properties else None
2390        return self.expression(
2391            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2392        )
2393
2394    def _parse_insert(self) -> exp.Insert:
2395        comments = ensure_list(self._prev_comments)
2396        hint = self._parse_hint()
2397        overwrite = self._match(TokenType.OVERWRITE)
2398        ignore = self._match(TokenType.IGNORE)
2399        local = self._match_text_seq("LOCAL")
2400        alternative = None
2401        is_function = None
2402
2403        if self._match_text_seq("DIRECTORY"):
2404            this: t.Optional[exp.Expression] = self.expression(
2405                exp.Directory,
2406                this=self._parse_var_or_string(),
2407                local=local,
2408                row_format=self._parse_row_format(match_row=True),
2409            )
2410        else:
2411            if self._match(TokenType.OR):
2412                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2413
2414            self._match(TokenType.INTO)
2415            comments += ensure_list(self._prev_comments)
2416            self._match(TokenType.TABLE)
2417            is_function = self._match(TokenType.FUNCTION)
2418
2419            this = (
2420                self._parse_table(schema=True, parse_partition=True)
2421                if not is_function
2422                else self._parse_function()
2423            )
2424
2425        returning = self._parse_returning()
2426
2427        return self.expression(
2428            exp.Insert,
2429            comments=comments,
2430            hint=hint,
2431            is_function=is_function,
2432            this=this,
2433            stored=self._match_text_seq("STORED") and self._parse_stored(),
2434            by_name=self._match_text_seq("BY", "NAME"),
2435            exists=self._parse_exists(),
2436            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2437            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2438            conflict=self._parse_on_conflict(),
2439            returning=returning or self._parse_returning(),
2440            overwrite=overwrite,
2441            alternative=alternative,
2442            ignore=ignore,
2443        )
2444
2445    def _parse_kill(self) -> exp.Kill:
2446        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2447
2448        return self.expression(
2449            exp.Kill,
2450            this=self._parse_primary(),
2451            kind=kind,
2452        )
2453
2454    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2455        conflict = self._match_text_seq("ON", "CONFLICT")
2456        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2457
2458        if not conflict and not duplicate:
2459            return None
2460
2461        conflict_keys = None
2462        constraint = None
2463
2464        if conflict:
2465            if self._match_text_seq("ON", "CONSTRAINT"):
2466                constraint = self._parse_id_var()
2467            elif self._match(TokenType.L_PAREN):
2468                conflict_keys = self._parse_csv(self._parse_id_var)
2469                self._match_r_paren()
2470
2471        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2472        if self._prev.token_type == TokenType.UPDATE:
2473            self._match(TokenType.SET)
2474            expressions = self._parse_csv(self._parse_equality)
2475        else:
2476            expressions = None
2477
2478        return self.expression(
2479            exp.OnConflict,
2480            duplicate=duplicate,
2481            expressions=expressions,
2482            action=action,
2483            conflict_keys=conflict_keys,
2484            constraint=constraint,
2485        )
2486
2487    def _parse_returning(self) -> t.Optional[exp.Returning]:
2488        if not self._match(TokenType.RETURNING):
2489            return None
2490        return self.expression(
2491            exp.Returning,
2492            expressions=self._parse_csv(self._parse_expression),
2493            into=self._match(TokenType.INTO) and self._parse_table_part(),
2494        )
2495
2496    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2497        if not self._match(TokenType.FORMAT):
2498            return None
2499        return self._parse_row_format()
2500
2501    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2502        index = self._index
2503        with_ = with_ or self._match_text_seq("WITH")
2504
2505        if not self._match(TokenType.SERDE_PROPERTIES):
2506            self._retreat(index)
2507            return None
2508        return self.expression(
2509            exp.SerdeProperties,
2510            **{  # type: ignore
2511                "expressions": self._parse_wrapped_properties(),
2512                "with": with_,
2513            },
2514        )
2515
2516    def _parse_row_format(
2517        self, match_row: bool = False
2518    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2519        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2520            return None
2521
2522        if self._match_text_seq("SERDE"):
2523            this = self._parse_string()
2524
2525            serde_properties = self._parse_serde_properties()
2526
2527            return self.expression(
2528                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2529            )
2530
2531        self._match_text_seq("DELIMITED")
2532
2533        kwargs = {}
2534
2535        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2536            kwargs["fields"] = self._parse_string()
2537            if self._match_text_seq("ESCAPED", "BY"):
2538                kwargs["escaped"] = self._parse_string()
2539        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2540            kwargs["collection_items"] = self._parse_string()
2541        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2542            kwargs["map_keys"] = self._parse_string()
2543        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2544            kwargs["lines"] = self._parse_string()
2545        if self._match_text_seq("NULL", "DEFINED", "AS"):
2546            kwargs["null"] = self._parse_string()
2547
2548        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2549
2550    def _parse_load(self) -> exp.LoadData | exp.Command:
2551        if self._match_text_seq("DATA"):
2552            local = self._match_text_seq("LOCAL")
2553            self._match_text_seq("INPATH")
2554            inpath = self._parse_string()
2555            overwrite = self._match(TokenType.OVERWRITE)
2556            self._match_pair(TokenType.INTO, TokenType.TABLE)
2557
2558            return self.expression(
2559                exp.LoadData,
2560                this=self._parse_table(schema=True),
2561                local=local,
2562                overwrite=overwrite,
2563                inpath=inpath,
2564                partition=self._parse_partition(),
2565                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2566                serde=self._match_text_seq("SERDE") and self._parse_string(),
2567            )
2568        return self._parse_as_command(self._prev)
2569
2570    def _parse_delete(self) -> exp.Delete:
2571        # This handles MySQL's "Multiple-Table Syntax"
2572        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2573        tables = None
2574        comments = self._prev_comments
2575        if not self._match(TokenType.FROM, advance=False):
2576            tables = self._parse_csv(self._parse_table) or None
2577
2578        returning = self._parse_returning()
2579
2580        return self.expression(
2581            exp.Delete,
2582            comments=comments,
2583            tables=tables,
2584            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2585            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2586            where=self._parse_where(),
2587            returning=returning or self._parse_returning(),
2588            limit=self._parse_limit(),
2589        )
2590
2591    def _parse_update(self) -> exp.Update:
2592        comments = self._prev_comments
2593        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2594        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2595        returning = self._parse_returning()
2596        return self.expression(
2597            exp.Update,
2598            comments=comments,
2599            **{  # type: ignore
2600                "this": this,
2601                "expressions": expressions,
2602                "from": self._parse_from(joins=True),
2603                "where": self._parse_where(),
2604                "returning": returning or self._parse_returning(),
2605                "order": self._parse_order(),
2606                "limit": self._parse_limit(),
2607            },
2608        )
2609
2610    def _parse_uncache(self) -> exp.Uncache:
2611        if not self._match(TokenType.TABLE):
2612            self.raise_error("Expecting TABLE after UNCACHE")
2613
2614        return self.expression(
2615            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2616        )
2617
2618    def _parse_cache(self) -> exp.Cache:
2619        lazy = self._match_text_seq("LAZY")
2620        self._match(TokenType.TABLE)
2621        table = self._parse_table(schema=True)
2622
2623        options = []
2624        if self._match_text_seq("OPTIONS"):
2625            self._match_l_paren()
2626            k = self._parse_string()
2627            self._match(TokenType.EQ)
2628            v = self._parse_string()
2629            options = [k, v]
2630            self._match_r_paren()
2631
2632        self._match(TokenType.ALIAS)
2633        return self.expression(
2634            exp.Cache,
2635            this=table,
2636            lazy=lazy,
2637            options=options,
2638            expression=self._parse_select(nested=True),
2639        )
2640
2641    def _parse_partition(self) -> t.Optional[exp.Partition]:
2642        if not self._match(TokenType.PARTITION):
2643            return None
2644
2645        return self.expression(
2646            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2647        )
2648
2649    def _parse_value(self) -> t.Optional[exp.Tuple]:
2650        if self._match(TokenType.L_PAREN):
2651            expressions = self._parse_csv(self._parse_expression)
2652            self._match_r_paren()
2653            return self.expression(exp.Tuple, expressions=expressions)
2654
2655        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2656        expression = self._parse_expression()
2657        if expression:
2658            return self.expression(exp.Tuple, expressions=[expression])
2659        return None
2660
2661    def _parse_projections(self) -> t.List[exp.Expression]:
2662        return self._parse_expressions()
2663
2664    def _parse_select(
2665        self,
2666        nested: bool = False,
2667        table: bool = False,
2668        parse_subquery_alias: bool = True,
2669        parse_set_operation: bool = True,
2670    ) -> t.Optional[exp.Expression]:
2671        cte = self._parse_with()
2672
2673        if cte:
2674            this = self._parse_statement()
2675
2676            if not this:
2677                self.raise_error("Failed to parse any statement following CTE")
2678                return cte
2679
2680            if "with" in this.arg_types:
2681                this.set("with", cte)
2682            else:
2683                self.raise_error(f"{this.key} does not support CTE")
2684                this = cte
2685
2686            return this
2687
2688        # duckdb supports leading with FROM x
2689        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2690
2691        if self._match(TokenType.SELECT):
2692            comments = self._prev_comments
2693
2694            hint = self._parse_hint()
2695            all_ = self._match(TokenType.ALL)
2696            distinct = self._match_set(self.DISTINCT_TOKENS)
2697
2698            kind = (
2699                self._match(TokenType.ALIAS)
2700                and self._match_texts(("STRUCT", "VALUE"))
2701                and self._prev.text.upper()
2702            )
2703
2704            if distinct:
2705                distinct = self.expression(
2706                    exp.Distinct,
2707                    on=self._parse_value() if self._match(TokenType.ON) else None,
2708                )
2709
2710            if all_ and distinct:
2711                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2712
2713            limit = self._parse_limit(top=True)
2714            projections = self._parse_projections()
2715
2716            this = self.expression(
2717                exp.Select,
2718                kind=kind,
2719                hint=hint,
2720                distinct=distinct,
2721                expressions=projections,
2722                limit=limit,
2723            )
2724            this.comments = comments
2725
2726            into = self._parse_into()
2727            if into:
2728                this.set("into", into)
2729
2730            if not from_:
2731                from_ = self._parse_from()
2732
2733            if from_:
2734                this.set("from", from_)
2735
2736            this = self._parse_query_modifiers(this)
2737        elif (table or nested) and self._match(TokenType.L_PAREN):
2738            if self._match(TokenType.PIVOT):
2739                this = self._parse_simplified_pivot()
2740            elif self._match(TokenType.FROM):
2741                this = exp.select("*").from_(
2742                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2743                )
2744            else:
2745                this = (
2746                    self._parse_table()
2747                    if table
2748                    else self._parse_select(nested=True, parse_set_operation=False)
2749                )
2750                this = self._parse_query_modifiers(self._parse_set_operations(this))
2751
2752            self._match_r_paren()
2753
2754            # We return early here so that the UNION isn't attached to the subquery by the
2755            # following call to _parse_set_operations, but instead becomes the parent node
2756            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2757        elif self._match(TokenType.VALUES, advance=False):
2758            this = self._parse_derived_table_values()
2759        elif from_:
2760            this = exp.select("*").from_(from_.this, copy=False)
2761        else:
2762            this = None
2763
2764        if parse_set_operation:
2765            return self._parse_set_operations(this)
2766        return this
2767
2768    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2769        if not skip_with_token and not self._match(TokenType.WITH):
2770            return None
2771
2772        comments = self._prev_comments
2773        recursive = self._match(TokenType.RECURSIVE)
2774
2775        expressions = []
2776        while True:
2777            expressions.append(self._parse_cte())
2778
2779            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2780                break
2781            else:
2782                self._match(TokenType.WITH)
2783
2784        return self.expression(
2785            exp.With, comments=comments, expressions=expressions, recursive=recursive
2786        )
2787
2788    def _parse_cte(self) -> exp.CTE:
2789        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2790        if not alias or not alias.this:
2791            self.raise_error("Expected CTE to have alias")
2792
2793        self._match(TokenType.ALIAS)
2794
2795        if self._match_text_seq("NOT", "MATERIALIZED"):
2796            materialized = False
2797        elif self._match_text_seq("MATERIALIZED"):
2798            materialized = True
2799        else:
2800            materialized = None
2801
2802        return self.expression(
2803            exp.CTE,
2804            this=self._parse_wrapped(self._parse_statement),
2805            alias=alias,
2806            materialized=materialized,
2807        )
2808
2809    def _parse_table_alias(
2810        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2811    ) -> t.Optional[exp.TableAlias]:
2812        any_token = self._match(TokenType.ALIAS)
2813        alias = (
2814            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2815            or self._parse_string_as_identifier()
2816        )
2817
2818        index = self._index
2819        if self._match(TokenType.L_PAREN):
2820            columns = self._parse_csv(self._parse_function_parameter)
2821            self._match_r_paren() if columns else self._retreat(index)
2822        else:
2823            columns = None
2824
2825        if not alias and not columns:
2826            return None
2827
2828        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
2829
2830        # We bubble up comments from the Identifier to the TableAlias
2831        if isinstance(alias, exp.Identifier):
2832            table_alias.add_comments(alias.pop_comments())
2833
2834        return table_alias
2835
2836    def _parse_subquery(
2837        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2838    ) -> t.Optional[exp.Subquery]:
2839        if not this:
2840            return None
2841
2842        return self.expression(
2843            exp.Subquery,
2844            this=this,
2845            pivots=self._parse_pivots(),
2846            alias=self._parse_table_alias() if parse_alias else None,
2847        )
2848
2849    def _implicit_unnests_to_explicit(self, this: E) -> E:
2850        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
2851
2852        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2853        for i, join in enumerate(this.args.get("joins") or []):
2854            table = join.this
2855            normalized_table = table.copy()
2856            normalized_table.meta["maybe_column"] = True
2857            normalized_table = _norm(normalized_table, dialect=self.dialect)
2858
2859            if isinstance(table, exp.Table) and not join.args.get("on"):
2860                if normalized_table.parts[0].name in refs:
2861                    table_as_column = table.to_column()
2862                    unnest = exp.Unnest(expressions=[table_as_column])
2863
2864                    # Table.to_column creates a parent Alias node that we want to convert to
2865                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2866                    if isinstance(table.args.get("alias"), exp.TableAlias):
2867                        table_as_column.replace(table_as_column.this)
2868                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2869
2870                    table.replace(unnest)
2871
2872            refs.add(normalized_table.alias_or_name)
2873
2874        return this
2875
2876    def _parse_query_modifiers(
2877        self, this: t.Optional[exp.Expression]
2878    ) -> t.Optional[exp.Expression]:
2879        if isinstance(this, (exp.Query, exp.Table)):
2880            for join in self._parse_joins():
2881                this.append("joins", join)
2882            for lateral in iter(self._parse_lateral, None):
2883                this.append("laterals", lateral)
2884
2885            while True:
2886                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2887                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2888                    key, expression = parser(self)
2889
2890                    if expression:
2891                        this.set(key, expression)
2892                        if key == "limit":
2893                            offset = expression.args.pop("offset", None)
2894
2895                            if offset:
2896                                offset = exp.Offset(expression=offset)
2897                                this.set("offset", offset)
2898
2899                                limit_by_expressions = expression.expressions
2900                                expression.set("expressions", None)
2901                                offset.set("expressions", limit_by_expressions)
2902                        continue
2903                break
2904
2905        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
2906            this = self._implicit_unnests_to_explicit(this)
2907
2908        return this
2909
2910    def _parse_hint(self) -> t.Optional[exp.Hint]:
2911        if self._match(TokenType.HINT):
2912            hints = []
2913            for hint in iter(
2914                lambda: self._parse_csv(
2915                    lambda: self._parse_function() or self._parse_var(upper=True)
2916                ),
2917                [],
2918            ):
2919                hints.extend(hint)
2920
2921            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2922                self.raise_error("Expected */ after HINT")
2923
2924            return self.expression(exp.Hint, expressions=hints)
2925
2926        return None
2927
2928    def _parse_into(self) -> t.Optional[exp.Into]:
2929        if not self._match(TokenType.INTO):
2930            return None
2931
2932        temp = self._match(TokenType.TEMPORARY)
2933        unlogged = self._match_text_seq("UNLOGGED")
2934        self._match(TokenType.TABLE)
2935
2936        return self.expression(
2937            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2938        )
2939
2940    def _parse_from(
2941        self, joins: bool = False, skip_from_token: bool = False
2942    ) -> t.Optional[exp.From]:
2943        if not skip_from_token and not self._match(TokenType.FROM):
2944            return None
2945
2946        return self.expression(
2947            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2948        )
2949
2950    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
2951        return self.expression(
2952            exp.MatchRecognizeMeasure,
2953            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
2954            this=self._parse_expression(),
2955        )
2956
2957    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2958        if not self._match(TokenType.MATCH_RECOGNIZE):
2959            return None
2960
2961        self._match_l_paren()
2962
2963        partition = self._parse_partition_by()
2964        order = self._parse_order()
2965
2966        measures = (
2967            self._parse_csv(self._parse_match_recognize_measure)
2968            if self._match_text_seq("MEASURES")
2969            else None
2970        )
2971
2972        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2973            rows = exp.var("ONE ROW PER MATCH")
2974        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2975            text = "ALL ROWS PER MATCH"
2976            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2977                text += " SHOW EMPTY MATCHES"
2978            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2979                text += " OMIT EMPTY MATCHES"
2980            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2981                text += " WITH UNMATCHED ROWS"
2982            rows = exp.var(text)
2983        else:
2984            rows = None
2985
2986        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2987            text = "AFTER MATCH SKIP"
2988            if self._match_text_seq("PAST", "LAST", "ROW"):
2989                text += " PAST LAST ROW"
2990            elif self._match_text_seq("TO", "NEXT", "ROW"):
2991                text += " TO NEXT ROW"
2992            elif self._match_text_seq("TO", "FIRST"):
2993                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2994            elif self._match_text_seq("TO", "LAST"):
2995                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2996            after = exp.var(text)
2997        else:
2998            after = None
2999
3000        if self._match_text_seq("PATTERN"):
3001            self._match_l_paren()
3002
3003            if not self._curr:
3004                self.raise_error("Expecting )", self._curr)
3005
3006            paren = 1
3007            start = self._curr
3008
3009            while self._curr and paren > 0:
3010                if self._curr.token_type == TokenType.L_PAREN:
3011                    paren += 1
3012                if self._curr.token_type == TokenType.R_PAREN:
3013                    paren -= 1
3014
3015                end = self._prev
3016                self._advance()
3017
3018            if paren > 0:
3019                self.raise_error("Expecting )", self._curr)
3020
3021            pattern = exp.var(self._find_sql(start, end))
3022        else:
3023            pattern = None
3024
3025        define = (
3026            self._parse_csv(self._parse_name_as_expression)
3027            if self._match_text_seq("DEFINE")
3028            else None
3029        )
3030
3031        self._match_r_paren()
3032
3033        return self.expression(
3034            exp.MatchRecognize,
3035            partition_by=partition,
3036            order=order,
3037            measures=measures,
3038            rows=rows,
3039            after=after,
3040            pattern=pattern,
3041            define=define,
3042            alias=self._parse_table_alias(),
3043        )
3044
3045    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3046        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3047        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3048            cross_apply = False
3049
3050        if cross_apply is not None:
3051            this = self._parse_select(table=True)
3052            view = None
3053            outer = None
3054        elif self._match(TokenType.LATERAL):
3055            this = self._parse_select(table=True)
3056            view = self._match(TokenType.VIEW)
3057            outer = self._match(TokenType.OUTER)
3058        else:
3059            return None
3060
3061        if not this:
3062            this = (
3063                self._parse_unnest()
3064                or self._parse_function()
3065                or self._parse_id_var(any_token=False)
3066            )
3067
3068            while self._match(TokenType.DOT):
3069                this = exp.Dot(
3070                    this=this,
3071                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3072                )
3073
3074        if view:
3075            table = self._parse_id_var(any_token=False)
3076            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3077            table_alias: t.Optional[exp.TableAlias] = self.expression(
3078                exp.TableAlias, this=table, columns=columns
3079            )
3080        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3081            # We move the alias from the lateral's child node to the lateral itself
3082            table_alias = this.args["alias"].pop()
3083        else:
3084            table_alias = self._parse_table_alias()
3085
3086        return self.expression(
3087            exp.Lateral,
3088            this=this,
3089            view=view,
3090            outer=outer,
3091            alias=table_alias,
3092            cross_apply=cross_apply,
3093        )
3094
3095    def _parse_join_parts(
3096        self,
3097    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3098        return (
3099            self._match_set(self.JOIN_METHODS) and self._prev,
3100            self._match_set(self.JOIN_SIDES) and self._prev,
3101            self._match_set(self.JOIN_KINDS) and self._prev,
3102        )
3103
3104    def _parse_join(
3105        self, skip_join_token: bool = False, parse_bracket: bool = False
3106    ) -> t.Optional[exp.Join]:
3107        if self._match(TokenType.COMMA):
3108            return self.expression(exp.Join, this=self._parse_table())
3109
3110        index = self._index
3111        method, side, kind = self._parse_join_parts()
3112        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3113        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3114
3115        if not skip_join_token and not join:
3116            self._retreat(index)
3117            kind = None
3118            method = None
3119            side = None
3120
3121        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3122        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3123
3124        if not skip_join_token and not join and not outer_apply and not cross_apply:
3125            return None
3126
3127        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3128
3129        if method:
3130            kwargs["method"] = method.text
3131        if side:
3132            kwargs["side"] = side.text
3133        if kind:
3134            kwargs["kind"] = kind.text
3135        if hint:
3136            kwargs["hint"] = hint
3137
3138        if self._match(TokenType.MATCH_CONDITION):
3139            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3140
3141        if self._match(TokenType.ON):
3142            kwargs["on"] = self._parse_assignment()
3143        elif self._match(TokenType.USING):
3144            kwargs["using"] = self._parse_wrapped_id_vars()
3145        elif not isinstance(kwargs["this"], exp.Unnest) and not (
3146            kind and kind.token_type == TokenType.CROSS
3147        ):
3148            index = self._index
3149            joins: t.Optional[list] = list(self._parse_joins())
3150
3151            if joins and self._match(TokenType.ON):
3152                kwargs["on"] = self._parse_assignment()
3153            elif joins and self._match(TokenType.USING):
3154                kwargs["using"] = self._parse_wrapped_id_vars()
3155            else:
3156                joins = None
3157                self._retreat(index)
3158
3159            kwargs["this"].set("joins", joins if joins else None)
3160
3161        comments = [c for token in (method, side, kind) if token for c in token.comments]
3162        return self.expression(exp.Join, comments=comments, **kwargs)
3163
3164    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3165        this = self._parse_assignment()
3166
3167        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3168            return this
3169
3170        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3171            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3172
3173        return this
3174
3175    def _parse_index_params(self) -> exp.IndexParameters:
3176        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3177
3178        if self._match(TokenType.L_PAREN, advance=False):
3179            columns = self._parse_wrapped_csv(self._parse_with_operator)
3180        else:
3181            columns = None
3182
3183        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3184        partition_by = self._parse_partition_by()
3185        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3186        tablespace = (
3187            self._parse_var(any_token=True)
3188            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3189            else None
3190        )
3191        where = self._parse_where()
3192
3193        on = self._parse_field() if self._match(TokenType.ON) else None
3194
3195        return self.expression(
3196            exp.IndexParameters,
3197            using=using,
3198            columns=columns,
3199            include=include,
3200            partition_by=partition_by,
3201            where=where,
3202            with_storage=with_storage,
3203            tablespace=tablespace,
3204            on=on,
3205        )
3206
3207    def _parse_index(
3208        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3209    ) -> t.Optional[exp.Index]:
3210        if index or anonymous:
3211            unique = None
3212            primary = None
3213            amp = None
3214
3215            self._match(TokenType.ON)
3216            self._match(TokenType.TABLE)  # hive
3217            table = self._parse_table_parts(schema=True)
3218        else:
3219            unique = self._match(TokenType.UNIQUE)
3220            primary = self._match_text_seq("PRIMARY")
3221            amp = self._match_text_seq("AMP")
3222
3223            if not self._match(TokenType.INDEX):
3224                return None
3225
3226            index = self._parse_id_var()
3227            table = None
3228
3229        params = self._parse_index_params()
3230
3231        return self.expression(
3232            exp.Index,
3233            this=index,
3234            table=table,
3235            unique=unique,
3236            primary=primary,
3237            amp=amp,
3238            params=params,
3239        )
3240
3241    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3242        hints: t.List[exp.Expression] = []
3243        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3244            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3245            hints.append(
3246                self.expression(
3247                    exp.WithTableHint,
3248                    expressions=self._parse_csv(
3249                        lambda: self._parse_function() or self._parse_var(any_token=True)
3250                    ),
3251                )
3252            )
3253            self._match_r_paren()
3254        else:
3255            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3256            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3257                hint = exp.IndexTableHint(this=self._prev.text.upper())
3258
3259                self._match_set((TokenType.INDEX, TokenType.KEY))
3260                if self._match(TokenType.FOR):
3261                    hint.set("target", self._advance_any() and self._prev.text.upper())
3262
3263                hint.set("expressions", self._parse_wrapped_id_vars())
3264                hints.append(hint)
3265
3266        return hints or None
3267
3268    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3269        return (
3270            (not schema and self._parse_function(optional_parens=False))
3271            or self._parse_id_var(any_token=False)
3272            or self._parse_string_as_identifier()
3273            or self._parse_placeholder()
3274        )
3275
3276    def _parse_table_parts(
3277        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3278    ) -> exp.Table:
3279        catalog = None
3280        db = None
3281        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3282
3283        while self._match(TokenType.DOT):
3284            if catalog:
3285                # This allows nesting the table in arbitrarily many dot expressions if needed
3286                table = self.expression(
3287                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3288                )
3289            else:
3290                catalog = db
3291                db = table
3292                # "" used for tsql FROM a..b case
3293                table = self._parse_table_part(schema=schema) or ""
3294
3295        if (
3296            wildcard
3297            and self._is_connected()
3298            and (isinstance(table, exp.Identifier) or not table)
3299            and self._match(TokenType.STAR)
3300        ):
3301            if isinstance(table, exp.Identifier):
3302                table.args["this"] += "*"
3303            else:
3304                table = exp.Identifier(this="*")
3305
3306        # We bubble up comments from the Identifier to the Table
3307        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3308
3309        if is_db_reference:
3310            catalog = db
3311            db = table
3312            table = None
3313
3314        if not table and not is_db_reference:
3315            self.raise_error(f"Expected table name but got {self._curr}")
3316        if not db and is_db_reference:
3317            self.raise_error(f"Expected database name but got {self._curr}")
3318
3319        return self.expression(
3320            exp.Table,
3321            comments=comments,
3322            this=table,
3323            db=db,
3324            catalog=catalog,
3325            pivots=self._parse_pivots(),
3326        )
3327
3328    def _parse_table(
3329        self,
3330        schema: bool = False,
3331        joins: bool = False,
3332        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3333        parse_bracket: bool = False,
3334        is_db_reference: bool = False,
3335        parse_partition: bool = False,
3336    ) -> t.Optional[exp.Expression]:
3337        lateral = self._parse_lateral()
3338        if lateral:
3339            return lateral
3340
3341        unnest = self._parse_unnest()
3342        if unnest:
3343            return unnest
3344
3345        values = self._parse_derived_table_values()
3346        if values:
3347            return values
3348
3349        subquery = self._parse_select(table=True)
3350        if subquery:
3351            if not subquery.args.get("pivots"):
3352                subquery.set("pivots", self._parse_pivots())
3353            return subquery
3354
3355        bracket = parse_bracket and self._parse_bracket(None)
3356        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3357
3358        only = self._match(TokenType.ONLY)
3359
3360        this = t.cast(
3361            exp.Expression,
3362            bracket
3363            or self._parse_bracket(
3364                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3365            ),
3366        )
3367
3368        if only:
3369            this.set("only", only)
3370
3371        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3372        self._match_text_seq("*")
3373
3374        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3375        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3376            this.set("partition", self._parse_partition())
3377
3378        if schema:
3379            return self._parse_schema(this=this)
3380
3381        version = self._parse_version()
3382
3383        if version:
3384            this.set("version", version)
3385
3386        if self.dialect.ALIAS_POST_TABLESAMPLE:
3387            table_sample = self._parse_table_sample()
3388
3389        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3390        if alias:
3391            this.set("alias", alias)
3392
3393        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3394            return self.expression(
3395                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3396            )
3397
3398        this.set("hints", self._parse_table_hints())
3399
3400        if not this.args.get("pivots"):
3401            this.set("pivots", self._parse_pivots())
3402
3403        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3404            table_sample = self._parse_table_sample()
3405
3406        if table_sample:
3407            table_sample.set("this", this)
3408            this = table_sample
3409
3410        if joins:
3411            for join in self._parse_joins():
3412                this.append("joins", join)
3413
3414        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3415            this.set("ordinality", True)
3416            this.set("alias", self._parse_table_alias())
3417
3418        return this
3419
3420    def _parse_version(self) -> t.Optional[exp.Version]:
3421        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3422            this = "TIMESTAMP"
3423        elif self._match(TokenType.VERSION_SNAPSHOT):
3424            this = "VERSION"
3425        else:
3426            return None
3427
3428        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3429            kind = self._prev.text.upper()
3430            start = self._parse_bitwise()
3431            self._match_texts(("TO", "AND"))
3432            end = self._parse_bitwise()
3433            expression: t.Optional[exp.Expression] = self.expression(
3434                exp.Tuple, expressions=[start, end]
3435            )
3436        elif self._match_text_seq("CONTAINED", "IN"):
3437            kind = "CONTAINED IN"
3438            expression = self.expression(
3439                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3440            )
3441        elif self._match(TokenType.ALL):
3442            kind = "ALL"
3443            expression = None
3444        else:
3445            self._match_text_seq("AS", "OF")
3446            kind = "AS OF"
3447            expression = self._parse_type()
3448
3449        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3450
3451    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3452        if not self._match(TokenType.UNNEST):
3453            return None
3454
3455        expressions = self._parse_wrapped_csv(self._parse_equality)
3456        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3457
3458        alias = self._parse_table_alias() if with_alias else None
3459
3460        if alias:
3461            if self.dialect.UNNEST_COLUMN_ONLY:
3462                if alias.args.get("columns"):
3463                    self.raise_error("Unexpected extra column alias in unnest.")
3464
3465                alias.set("columns", [alias.this])
3466                alias.set("this", None)
3467
3468            columns = alias.args.get("columns") or []
3469            if offset and len(expressions) < len(columns):
3470                offset = columns.pop()
3471
3472        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3473            self._match(TokenType.ALIAS)
3474            offset = self._parse_id_var(
3475                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3476            ) or exp.to_identifier("offset")
3477
3478        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3479
3480    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3481        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3482        if not is_derived and not self._match_text_seq("VALUES"):
3483            return None
3484
3485        expressions = self._parse_csv(self._parse_value)
3486        alias = self._parse_table_alias()
3487
3488        if is_derived:
3489            self._match_r_paren()
3490
3491        return self.expression(
3492            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3493        )
3494
3495    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3496        if not self._match(TokenType.TABLE_SAMPLE) and not (
3497            as_modifier and self._match_text_seq("USING", "SAMPLE")
3498        ):
3499            return None
3500
3501        bucket_numerator = None
3502        bucket_denominator = None
3503        bucket_field = None
3504        percent = None
3505        size = None
3506        seed = None
3507
3508        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3509        matched_l_paren = self._match(TokenType.L_PAREN)
3510
3511        if self.TABLESAMPLE_CSV:
3512            num = None
3513            expressions = self._parse_csv(self._parse_primary)
3514        else:
3515            expressions = None
3516            num = (
3517                self._parse_factor()
3518                if self._match(TokenType.NUMBER, advance=False)
3519                else self._parse_primary() or self._parse_placeholder()
3520            )
3521
3522        if self._match_text_seq("BUCKET"):
3523            bucket_numerator = self._parse_number()
3524            self._match_text_seq("OUT", "OF")
3525            bucket_denominator = bucket_denominator = self._parse_number()
3526            self._match(TokenType.ON)
3527            bucket_field = self._parse_field()
3528        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3529            percent = num
3530        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3531            size = num
3532        else:
3533            percent = num
3534
3535        if matched_l_paren:
3536            self._match_r_paren()
3537
3538        if self._match(TokenType.L_PAREN):
3539            method = self._parse_var(upper=True)
3540            seed = self._match(TokenType.COMMA) and self._parse_number()
3541            self._match_r_paren()
3542        elif self._match_texts(("SEED", "REPEATABLE")):
3543            seed = self._parse_wrapped(self._parse_number)
3544
3545        if not method and self.DEFAULT_SAMPLING_METHOD:
3546            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3547
3548        return self.expression(
3549            exp.TableSample,
3550            expressions=expressions,
3551            method=method,
3552            bucket_numerator=bucket_numerator,
3553            bucket_denominator=bucket_denominator,
3554            bucket_field=bucket_field,
3555            percent=percent,
3556            size=size,
3557            seed=seed,
3558        )
3559
3560    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3561        return list(iter(self._parse_pivot, None)) or None
3562
3563    def _parse_joins(self) -> t.Iterator[exp.Join]:
3564        return iter(self._parse_join, None)
3565
3566    # https://duckdb.org/docs/sql/statements/pivot
3567    def _parse_simplified_pivot(self) -> exp.Pivot:
3568        def _parse_on() -> t.Optional[exp.Expression]:
3569            this = self._parse_bitwise()
3570            return self._parse_in(this) if self._match(TokenType.IN) else this
3571
3572        this = self._parse_table()
3573        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3574        using = self._match(TokenType.USING) and self._parse_csv(
3575            lambda: self._parse_alias(self._parse_function())
3576        )
3577        group = self._parse_group()
3578        return self.expression(
3579            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3580        )
3581
3582    def _parse_pivot_in(self) -> exp.In:
3583        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3584            this = self._parse_assignment()
3585
3586            self._match(TokenType.ALIAS)
3587            alias = self._parse_field()
3588            if alias:
3589                return self.expression(exp.PivotAlias, this=this, alias=alias)
3590
3591            return this
3592
3593        value = self._parse_column()
3594
3595        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3596            self.raise_error("Expecting IN (")
3597
3598        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3599
3600        self._match_r_paren()
3601        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3602
3603    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3604        index = self._index
3605        include_nulls = None
3606
3607        if self._match(TokenType.PIVOT):
3608            unpivot = False
3609        elif self._match(TokenType.UNPIVOT):
3610            unpivot = True
3611
3612            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3613            if self._match_text_seq("INCLUDE", "NULLS"):
3614                include_nulls = True
3615            elif self._match_text_seq("EXCLUDE", "NULLS"):
3616                include_nulls = False
3617        else:
3618            return None
3619
3620        expressions = []
3621
3622        if not self._match(TokenType.L_PAREN):
3623            self._retreat(index)
3624            return None
3625
3626        if unpivot:
3627            expressions = self._parse_csv(self._parse_column)
3628        else:
3629            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3630
3631        if not expressions:
3632            self.raise_error("Failed to parse PIVOT's aggregation list")
3633
3634        if not self._match(TokenType.FOR):
3635            self.raise_error("Expecting FOR")
3636
3637        field = self._parse_pivot_in()
3638
3639        self._match_r_paren()
3640
3641        pivot = self.expression(
3642            exp.Pivot,
3643            expressions=expressions,
3644            field=field,
3645            unpivot=unpivot,
3646            include_nulls=include_nulls,
3647        )
3648
3649        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3650            pivot.set("alias", self._parse_table_alias())
3651
3652        if not unpivot:
3653            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3654
3655            columns: t.List[exp.Expression] = []
3656            for fld in pivot.args["field"].expressions:
3657                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3658                for name in names:
3659                    if self.PREFIXED_PIVOT_COLUMNS:
3660                        name = f"{name}_{field_name}" if name else field_name
3661                    else:
3662                        name = f"{field_name}_{name}" if name else field_name
3663
3664                    columns.append(exp.to_identifier(name))
3665
3666            pivot.set("columns", columns)
3667
3668        return pivot
3669
3670    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3671        return [agg.alias for agg in aggregations]
3672
3673    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3674        if not skip_where_token and not self._match(TokenType.PREWHERE):
3675            return None
3676
3677        return self.expression(
3678            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
3679        )
3680
3681    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3682        if not skip_where_token and not self._match(TokenType.WHERE):
3683            return None
3684
3685        return self.expression(
3686            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
3687        )
3688
3689    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3690        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3691            return None
3692
3693        elements: t.Dict[str, t.Any] = defaultdict(list)
3694
3695        if self._match(TokenType.ALL):
3696            elements["all"] = True
3697        elif self._match(TokenType.DISTINCT):
3698            elements["all"] = False
3699
3700        while True:
3701            expressions = self._parse_csv(
3702                lambda: None
3703                if self._match(TokenType.ROLLUP, advance=False)
3704                else self._parse_assignment()
3705            )
3706            if expressions:
3707                elements["expressions"].extend(expressions)
3708
3709            grouping_sets = self._parse_grouping_sets()
3710            if grouping_sets:
3711                elements["grouping_sets"].extend(grouping_sets)
3712
3713            rollup = None
3714            cube = None
3715            totals = None
3716
3717            index = self._index
3718            with_ = self._match(TokenType.WITH)
3719            if self._match(TokenType.ROLLUP):
3720                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3721                elements["rollup"].extend(ensure_list(rollup))
3722
3723            if self._match(TokenType.CUBE):
3724                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3725                elements["cube"].extend(ensure_list(cube))
3726
3727            if self._match_text_seq("TOTALS"):
3728                totals = True
3729                elements["totals"] = True  # type: ignore
3730
3731            if not (grouping_sets or rollup or cube or totals):
3732                if with_:
3733                    self._retreat(index)
3734                break
3735
3736        return self.expression(exp.Group, **elements)  # type: ignore
3737
3738    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3739        if not self._match(TokenType.GROUPING_SETS):
3740            return None
3741
3742        return self._parse_wrapped_csv(self._parse_grouping_set)
3743
3744    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3745        if self._match(TokenType.L_PAREN):
3746            grouping_set = self._parse_csv(self._parse_column)
3747            self._match_r_paren()
3748            return self.expression(exp.Tuple, expressions=grouping_set)
3749
3750        return self._parse_column()
3751
3752    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3753        if not skip_having_token and not self._match(TokenType.HAVING):
3754            return None
3755        return self.expression(exp.Having, this=self._parse_assignment())
3756
3757    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3758        if not self._match(TokenType.QUALIFY):
3759            return None
3760        return self.expression(exp.Qualify, this=self._parse_assignment())
3761
3762    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3763        if skip_start_token:
3764            start = None
3765        elif self._match(TokenType.START_WITH):
3766            start = self._parse_assignment()
3767        else:
3768            return None
3769
3770        self._match(TokenType.CONNECT_BY)
3771        nocycle = self._match_text_seq("NOCYCLE")
3772        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3773            exp.Prior, this=self._parse_bitwise()
3774        )
3775        connect = self._parse_assignment()
3776        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3777
3778        if not start and self._match(TokenType.START_WITH):
3779            start = self._parse_assignment()
3780
3781        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3782
3783    def _parse_name_as_expression(self) -> exp.Alias:
3784        return self.expression(
3785            exp.Alias,
3786            alias=self._parse_id_var(any_token=True),
3787            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
3788        )
3789
3790    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3791        if self._match_text_seq("INTERPOLATE"):
3792            return self._parse_wrapped_csv(self._parse_name_as_expression)
3793        return None
3794
3795    def _parse_order(
3796        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3797    ) -> t.Optional[exp.Expression]:
3798        siblings = None
3799        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3800            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3801                return this
3802
3803            siblings = True
3804
3805        return self.expression(
3806            exp.Order,
3807            this=this,
3808            expressions=self._parse_csv(self._parse_ordered),
3809            interpolate=self._parse_interpolate(),
3810            siblings=siblings,
3811        )
3812
3813    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3814        if not self._match(token):
3815            return None
3816        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3817
3818    def _parse_ordered(
3819        self, parse_method: t.Optional[t.Callable] = None
3820    ) -> t.Optional[exp.Ordered]:
3821        this = parse_method() if parse_method else self._parse_assignment()
3822        if not this:
3823            return None
3824
3825        asc = self._match(TokenType.ASC)
3826        desc = self._match(TokenType.DESC) or (asc and False)
3827
3828        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3829        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3830
3831        nulls_first = is_nulls_first or False
3832        explicitly_null_ordered = is_nulls_first or is_nulls_last
3833
3834        if (
3835            not explicitly_null_ordered
3836            and (
3837                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3838                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3839            )
3840            and self.dialect.NULL_ORDERING != "nulls_are_last"
3841        ):
3842            nulls_first = True
3843
3844        if self._match_text_seq("WITH", "FILL"):
3845            with_fill = self.expression(
3846                exp.WithFill,
3847                **{  # type: ignore
3848                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3849                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3850                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3851                },
3852            )
3853        else:
3854            with_fill = None
3855
3856        return self.expression(
3857            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3858        )
3859
3860    def _parse_limit(
3861        self,
3862        this: t.Optional[exp.Expression] = None,
3863        top: bool = False,
3864        skip_limit_token: bool = False,
3865    ) -> t.Optional[exp.Expression]:
3866        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3867            comments = self._prev_comments
3868            if top:
3869                limit_paren = self._match(TokenType.L_PAREN)
3870                expression = self._parse_term() if limit_paren else self._parse_number()
3871
3872                if limit_paren:
3873                    self._match_r_paren()
3874            else:
3875                expression = self._parse_term()
3876
3877            if self._match(TokenType.COMMA):
3878                offset = expression
3879                expression = self._parse_term()
3880            else:
3881                offset = None
3882
3883            limit_exp = self.expression(
3884                exp.Limit,
3885                this=this,
3886                expression=expression,
3887                offset=offset,
3888                comments=comments,
3889                expressions=self._parse_limit_by(),
3890            )
3891
3892            return limit_exp
3893
3894        if self._match(TokenType.FETCH):
3895            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3896            direction = self._prev.text.upper() if direction else "FIRST"
3897
3898            count = self._parse_field(tokens=self.FETCH_TOKENS)
3899            percent = self._match(TokenType.PERCENT)
3900
3901            self._match_set((TokenType.ROW, TokenType.ROWS))
3902
3903            only = self._match_text_seq("ONLY")
3904            with_ties = self._match_text_seq("WITH", "TIES")
3905
3906            if only and with_ties:
3907                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3908
3909            return self.expression(
3910                exp.Fetch,
3911                direction=direction,
3912                count=count,
3913                percent=percent,
3914                with_ties=with_ties,
3915            )
3916
3917        return this
3918
3919    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3920        if not self._match(TokenType.OFFSET):
3921            return this
3922
3923        count = self._parse_term()
3924        self._match_set((TokenType.ROW, TokenType.ROWS))
3925
3926        return self.expression(
3927            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
3928        )
3929
3930    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
3931        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
3932
3933    def _parse_locks(self) -> t.List[exp.Lock]:
3934        locks = []
3935        while True:
3936            if self._match_text_seq("FOR", "UPDATE"):
3937                update = True
3938            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3939                "LOCK", "IN", "SHARE", "MODE"
3940            ):
3941                update = False
3942            else:
3943                break
3944
3945            expressions = None
3946            if self._match_text_seq("OF"):
3947                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3948
3949            wait: t.Optional[bool | exp.Expression] = None
3950            if self._match_text_seq("NOWAIT"):
3951                wait = True
3952            elif self._match_text_seq("WAIT"):
3953                wait = self._parse_primary()
3954            elif self._match_text_seq("SKIP", "LOCKED"):
3955                wait = False
3956
3957            locks.append(
3958                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3959            )
3960
3961        return locks
3962
3963    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3964        while this and self._match_set(self.SET_OPERATIONS):
3965            token_type = self._prev.token_type
3966
3967            if token_type == TokenType.UNION:
3968                operation: t.Type[exp.SetOperation] = exp.Union
3969            elif token_type == TokenType.EXCEPT:
3970                operation = exp.Except
3971            else:
3972                operation = exp.Intersect
3973
3974            comments = self._prev.comments
3975            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3976            by_name = self._match_text_seq("BY", "NAME")
3977            expression = self._parse_select(nested=True, parse_set_operation=False)
3978
3979            this = self.expression(
3980                operation,
3981                comments=comments,
3982                this=this,
3983                distinct=distinct,
3984                by_name=by_name,
3985                expression=expression,
3986            )
3987
3988        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
3989            expression = this.expression
3990
3991            if expression:
3992                for arg in self.SET_OP_MODIFIERS:
3993                    expr = expression.args.get(arg)
3994                    if expr:
3995                        this.set(arg, expr.pop())
3996
3997        return this
3998
3999    def _parse_expression(self) -> t.Optional[exp.Expression]:
4000        return self._parse_alias(self._parse_assignment())
4001
4002    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4003        this = self._parse_disjunction()
4004
4005        while self._match_set(self.ASSIGNMENT):
4006            this = self.expression(
4007                self.ASSIGNMENT[self._prev.token_type],
4008                this=this,
4009                comments=self._prev_comments,
4010                expression=self._parse_assignment(),
4011            )
4012
4013        return this
4014
4015    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4016        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4017
4018    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4019        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4020
4021    def _parse_equality(self) -> t.Optional[exp.Expression]:
4022        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4023
4024    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4025        return self._parse_tokens(self._parse_range, self.COMPARISON)
4026
4027    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4028        this = this or self._parse_bitwise()
4029        negate = self._match(TokenType.NOT)
4030
4031        if self._match_set(self.RANGE_PARSERS):
4032            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4033            if not expression:
4034                return this
4035
4036            this = expression
4037        elif self._match(TokenType.ISNULL):
4038            this = self.expression(exp.Is, this=this, expression=exp.Null())
4039
4040        # Postgres supports ISNULL and NOTNULL for conditions.
4041        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4042        if self._match(TokenType.NOTNULL):
4043            this = self.expression(exp.Is, this=this, expression=exp.Null())
4044            this = self.expression(exp.Not, this=this)
4045
4046        if negate:
4047            this = self.expression(exp.Not, this=this)
4048
4049        if self._match(TokenType.IS):
4050            this = self._parse_is(this)
4051
4052        return this
4053
4054    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4055        index = self._index - 1
4056        negate = self._match(TokenType.NOT)
4057
4058        if self._match_text_seq("DISTINCT", "FROM"):
4059            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4060            return self.expression(klass, this=this, expression=self._parse_bitwise())
4061
4062        expression = self._parse_null() or self._parse_boolean()
4063        if not expression:
4064            self._retreat(index)
4065            return None
4066
4067        this = self.expression(exp.Is, this=this, expression=expression)
4068        return self.expression(exp.Not, this=this) if negate else this
4069
4070    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4071        unnest = self._parse_unnest(with_alias=False)
4072        if unnest:
4073            this = self.expression(exp.In, this=this, unnest=unnest)
4074        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4075            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4076            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4077
4078            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4079                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4080            else:
4081                this = self.expression(exp.In, this=this, expressions=expressions)
4082
4083            if matched_l_paren:
4084                self._match_r_paren(this)
4085            elif not self._match(TokenType.R_BRACKET, expression=this):
4086                self.raise_error("Expecting ]")
4087        else:
4088            this = self.expression(exp.In, this=this, field=self._parse_field())
4089
4090        return this
4091
4092    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4093        low = self._parse_bitwise()
4094        self._match(TokenType.AND)
4095        high = self._parse_bitwise()
4096        return self.expression(exp.Between, this=this, low=low, high=high)
4097
4098    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4099        if not self._match(TokenType.ESCAPE):
4100            return this
4101        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4102
4103    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4104        index = self._index
4105
4106        if not self._match(TokenType.INTERVAL) and match_interval:
4107            return None
4108
4109        if self._match(TokenType.STRING, advance=False):
4110            this = self._parse_primary()
4111        else:
4112            this = self._parse_term()
4113
4114        if not this or (
4115            isinstance(this, exp.Column)
4116            and not this.table
4117            and not this.this.quoted
4118            and this.name.upper() == "IS"
4119        ):
4120            self._retreat(index)
4121            return None
4122
4123        unit = self._parse_function() or (
4124            not self._match(TokenType.ALIAS, advance=False)
4125            and self._parse_var(any_token=True, upper=True)
4126        )
4127
4128        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4129        # each INTERVAL expression into this canonical form so it's easy to transpile
4130        if this and this.is_number:
4131            this = exp.Literal.string(this.name)
4132        elif this and this.is_string:
4133            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4134            if len(parts) == 1:
4135                if unit:
4136                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4137                    self._retreat(self._index - 1)
4138
4139                this = exp.Literal.string(parts[0][0])
4140                unit = self.expression(exp.Var, this=parts[0][1].upper())
4141
4142        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4143            unit = self.expression(
4144                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4145            )
4146
4147        interval = self.expression(exp.Interval, this=this, unit=unit)
4148
4149        index = self._index
4150        self._match(TokenType.PLUS)
4151
4152        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4153        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4154            return self.expression(
4155                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4156            )
4157
4158        self._retreat(index)
4159        return interval
4160
4161    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4162        this = self._parse_term()
4163
4164        while True:
4165            if self._match_set(self.BITWISE):
4166                this = self.expression(
4167                    self.BITWISE[self._prev.token_type],
4168                    this=this,
4169                    expression=self._parse_term(),
4170                )
4171            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4172                this = self.expression(
4173                    exp.DPipe,
4174                    this=this,
4175                    expression=self._parse_term(),
4176                    safe=not self.dialect.STRICT_STRING_CONCAT,
4177                )
4178            elif self._match(TokenType.DQMARK):
4179                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
4180            elif self._match_pair(TokenType.LT, TokenType.LT):
4181                this = self.expression(
4182                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4183                )
4184            elif self._match_pair(TokenType.GT, TokenType.GT):
4185                this = self.expression(
4186                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4187                )
4188            else:
4189                break
4190
4191        return this
4192
4193    def _parse_term(self) -> t.Optional[exp.Expression]:
4194        return self._parse_tokens(self._parse_factor, self.TERM)
4195
4196    def _parse_factor(self) -> t.Optional[exp.Expression]:
4197        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4198        this = parse_method()
4199
4200        while self._match_set(self.FACTOR):
4201            klass = self.FACTOR[self._prev.token_type]
4202            comments = self._prev_comments
4203            expression = parse_method()
4204
4205            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4206                self._retreat(self._index - 1)
4207                return this
4208
4209            this = self.expression(klass, this=this, comments=comments, expression=expression)
4210
4211            if isinstance(this, exp.Div):
4212                this.args["typed"] = self.dialect.TYPED_DIVISION
4213                this.args["safe"] = self.dialect.SAFE_DIVISION
4214
4215        return this
4216
4217    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4218        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4219
4220    def _parse_unary(self) -> t.Optional[exp.Expression]:
4221        if self._match_set(self.UNARY_PARSERS):
4222            return self.UNARY_PARSERS[self._prev.token_type](self)
4223        return self._parse_at_time_zone(self._parse_type())
4224
4225    def _parse_type(
4226        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4227    ) -> t.Optional[exp.Expression]:
4228        interval = parse_interval and self._parse_interval()
4229        if interval:
4230            return interval
4231
4232        index = self._index
4233        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4234
4235        if data_type:
4236            index2 = self._index
4237            this = self._parse_primary()
4238
4239            if isinstance(this, exp.Literal):
4240                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4241                if parser:
4242                    return parser(self, this, data_type)
4243
4244                return self.expression(exp.Cast, this=this, to=data_type)
4245
4246            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4247            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4248            #
4249            # If the index difference here is greater than 1, that means the parser itself must have
4250            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4251            #
4252            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4253            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4254            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4255            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4256            #
4257            # In these cases, we don't really want to return the converted type, but instead retreat
4258            # and try to parse a Column or Identifier in the section below.
4259            if data_type.expressions and index2 - index > 1:
4260                self._retreat(index2)
4261                return self._parse_column_ops(data_type)
4262
4263            self._retreat(index)
4264
4265        if fallback_to_identifier:
4266            return self._parse_id_var()
4267
4268        this = self._parse_column()
4269        return this and self._parse_column_ops(this)
4270
4271    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4272        this = self._parse_type()
4273        if not this:
4274            return None
4275
4276        if isinstance(this, exp.Column) and not this.table:
4277            this = exp.var(this.name.upper())
4278
4279        return self.expression(
4280            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4281        )
4282
4283    def _parse_types(
4284        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4285    ) -> t.Optional[exp.Expression]:
4286        index = self._index
4287
4288        this: t.Optional[exp.Expression] = None
4289        prefix = self._match_text_seq("SYSUDTLIB", ".")
4290
4291        if not self._match_set(self.TYPE_TOKENS):
4292            identifier = allow_identifiers and self._parse_id_var(
4293                any_token=False, tokens=(TokenType.VAR,)
4294            )
4295            if identifier:
4296                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4297
4298                if len(tokens) != 1:
4299                    self.raise_error("Unexpected identifier", self._prev)
4300
4301                if tokens[0].token_type in self.TYPE_TOKENS:
4302                    self._prev = tokens[0]
4303                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4304                    type_name = identifier.name
4305
4306                    while self._match(TokenType.DOT):
4307                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4308
4309                    this = exp.DataType.build(type_name, udt=True)
4310                else:
4311                    self._retreat(self._index - 1)
4312                    return None
4313            else:
4314                return None
4315
4316        type_token = self._prev.token_type
4317
4318        if type_token == TokenType.PSEUDO_TYPE:
4319            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4320
4321        if type_token == TokenType.OBJECT_IDENTIFIER:
4322            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4323
4324        # https://materialize.com/docs/sql/types/map/
4325        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4326            key_type = self._parse_types(
4327                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4328            )
4329            if not self._match(TokenType.FARROW):
4330                self._retreat(index)
4331                return None
4332
4333            value_type = self._parse_types(
4334                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4335            )
4336            if not self._match(TokenType.R_BRACKET):
4337                self._retreat(index)
4338                return None
4339
4340            return exp.DataType(
4341                this=exp.DataType.Type.MAP,
4342                expressions=[key_type, value_type],
4343                nested=True,
4344                prefix=prefix,
4345            )
4346
4347        nested = type_token in self.NESTED_TYPE_TOKENS
4348        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4349        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4350        expressions = None
4351        maybe_func = False
4352
4353        if self._match(TokenType.L_PAREN):
4354            if is_struct:
4355                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4356            elif nested:
4357                expressions = self._parse_csv(
4358                    lambda: self._parse_types(
4359                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4360                    )
4361                )
4362            elif type_token in self.ENUM_TYPE_TOKENS:
4363                expressions = self._parse_csv(self._parse_equality)
4364            elif is_aggregate:
4365                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4366                    any_token=False, tokens=(TokenType.VAR,)
4367                )
4368                if not func_or_ident or not self._match(TokenType.COMMA):
4369                    return None
4370                expressions = self._parse_csv(
4371                    lambda: self._parse_types(
4372                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4373                    )
4374                )
4375                expressions.insert(0, func_or_ident)
4376            else:
4377                expressions = self._parse_csv(self._parse_type_size)
4378
4379            if not expressions or not self._match(TokenType.R_PAREN):
4380                self._retreat(index)
4381                return None
4382
4383            maybe_func = True
4384
4385        values: t.Optional[t.List[exp.Expression]] = None
4386
4387        if nested and self._match(TokenType.LT):
4388            if is_struct:
4389                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4390            else:
4391                expressions = self._parse_csv(
4392                    lambda: self._parse_types(
4393                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4394                    )
4395                )
4396
4397            if not self._match(TokenType.GT):
4398                self.raise_error("Expecting >")
4399
4400            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4401                values = self._parse_csv(self._parse_assignment)
4402                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4403
4404        if type_token in self.TIMESTAMPS:
4405            if self._match_text_seq("WITH", "TIME", "ZONE"):
4406                maybe_func = False
4407                tz_type = (
4408                    exp.DataType.Type.TIMETZ
4409                    if type_token in self.TIMES
4410                    else exp.DataType.Type.TIMESTAMPTZ
4411                )
4412                this = exp.DataType(this=tz_type, expressions=expressions)
4413            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4414                maybe_func = False
4415                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4416            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4417                maybe_func = False
4418        elif type_token == TokenType.INTERVAL:
4419            unit = self._parse_var(upper=True)
4420            if unit:
4421                if self._match_text_seq("TO"):
4422                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4423
4424                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4425            else:
4426                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4427
4428        if maybe_func and check_func:
4429            index2 = self._index
4430            peek = self._parse_string()
4431
4432            if not peek:
4433                self._retreat(index)
4434                return None
4435
4436            self._retreat(index2)
4437
4438        if not this:
4439            if self._match_text_seq("UNSIGNED"):
4440                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4441                if not unsigned_type_token:
4442                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4443
4444                type_token = unsigned_type_token or type_token
4445
4446            this = exp.DataType(
4447                this=exp.DataType.Type[type_token.value],
4448                expressions=expressions,
4449                nested=nested,
4450                values=values,
4451                prefix=prefix,
4452            )
4453        elif expressions:
4454            this.set("expressions", expressions)
4455
4456        # https://materialize.com/docs/sql/types/list/#type-name
4457        while self._match(TokenType.LIST):
4458            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4459
4460        index = self._index
4461
4462        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4463        matched_array = self._match(TokenType.ARRAY)
4464
4465        while self._curr:
4466            matched_l_bracket = self._match(TokenType.L_BRACKET)
4467            if not matched_l_bracket and not matched_array:
4468                break
4469
4470            matched_array = False
4471            values = self._parse_csv(self._parse_assignment) or None
4472            if values and not schema:
4473                self._retreat(index)
4474                break
4475
4476            this = exp.DataType(
4477                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4478            )
4479            self._match(TokenType.R_BRACKET)
4480
4481        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4482            converter = self.TYPE_CONVERTERS.get(this.this)
4483            if converter:
4484                this = converter(t.cast(exp.DataType, this))
4485
4486        return this
4487
4488    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4489        index = self._index
4490
4491        if (
4492            self._curr
4493            and self._next
4494            and self._curr.token_type in self.TYPE_TOKENS
4495            and self._next.token_type in self.TYPE_TOKENS
4496        ):
4497            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4498            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4499            this = self._parse_id_var()
4500        else:
4501            this = (
4502                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4503                or self._parse_id_var()
4504            )
4505
4506        self._match(TokenType.COLON)
4507
4508        if (
4509            type_required
4510            and not isinstance(this, exp.DataType)
4511            and not self._match_set(self.TYPE_TOKENS, advance=False)
4512        ):
4513            self._retreat(index)
4514            return self._parse_types()
4515
4516        return self._parse_column_def(this)
4517
4518    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4519        if not self._match_text_seq("AT", "TIME", "ZONE"):
4520            return this
4521        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4522
4523    def _parse_column(self) -> t.Optional[exp.Expression]:
4524        this = self._parse_column_reference()
4525        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
4526
4527        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
4528            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
4529
4530        return column
4531
4532    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4533        this = self._parse_field()
4534        if (
4535            not this
4536            and self._match(TokenType.VALUES, advance=False)
4537            and self.VALUES_FOLLOWED_BY_PAREN
4538            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4539        ):
4540            this = self._parse_id_var()
4541
4542        if isinstance(this, exp.Identifier):
4543            # We bubble up comments from the Identifier to the Column
4544            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4545
4546        return this
4547
4548    def _parse_colon_as_json_extract(
4549        self, this: t.Optional[exp.Expression]
4550    ) -> t.Optional[exp.Expression]:
4551        casts = []
4552        json_path = []
4553
4554        while self._match(TokenType.COLON):
4555            start_index = self._index
4556
4557            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
4558            path = self._parse_column_ops(
4559                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
4560            )
4561
4562            # The cast :: operator has a lower precedence than the extraction operator :, so
4563            # we rearrange the AST appropriately to avoid casting the JSON path
4564            while isinstance(path, exp.Cast):
4565                casts.append(path.to)
4566                path = path.this
4567
4568            if casts:
4569                dcolon_offset = next(
4570                    i
4571                    for i, t in enumerate(self._tokens[start_index:])
4572                    if t.token_type == TokenType.DCOLON
4573                )
4574                end_token = self._tokens[start_index + dcolon_offset - 1]
4575            else:
4576                end_token = self._prev
4577
4578            if path:
4579                json_path.append(self._find_sql(self._tokens[start_index], end_token))
4580
4581        if json_path:
4582            this = self.expression(
4583                exp.JSONExtract,
4584                this=this,
4585                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
4586            )
4587
4588            while casts:
4589                this = self.expression(exp.Cast, this=this, to=casts.pop())
4590
4591        return this
4592
4593    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4594        this = self._parse_bracket(this)
4595
4596        while self._match_set(self.COLUMN_OPERATORS):
4597            op_token = self._prev.token_type
4598            op = self.COLUMN_OPERATORS.get(op_token)
4599
4600            if op_token == TokenType.DCOLON:
4601                field = self._parse_types()
4602                if not field:
4603                    self.raise_error("Expected type")
4604            elif op and self._curr:
4605                field = self._parse_column_reference()
4606            else:
4607                field = self._parse_field(any_token=True, anonymous_func=True)
4608
4609            if isinstance(field, exp.Func) and this:
4610                # bigquery allows function calls like x.y.count(...)
4611                # SAFE.SUBSTR(...)
4612                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4613                this = exp.replace_tree(
4614                    this,
4615                    lambda n: (
4616                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4617                        if n.table
4618                        else n.this
4619                    )
4620                    if isinstance(n, exp.Column)
4621                    else n,
4622                )
4623
4624            if op:
4625                this = op(self, this, field)
4626            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4627                this = self.expression(
4628                    exp.Column,
4629                    this=field,
4630                    table=this.this,
4631                    db=this.args.get("table"),
4632                    catalog=this.args.get("db"),
4633                )
4634            else:
4635                this = self.expression(exp.Dot, this=this, expression=field)
4636
4637            this = self._parse_bracket(this)
4638
4639        return self._parse_colon_as_json_extract(this) if self.COLON_IS_JSON_EXTRACT else this
4640
4641    def _parse_primary(self) -> t.Optional[exp.Expression]:
4642        if self._match_set(self.PRIMARY_PARSERS):
4643            token_type = self._prev.token_type
4644            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4645
4646            if token_type == TokenType.STRING:
4647                expressions = [primary]
4648                while self._match(TokenType.STRING):
4649                    expressions.append(exp.Literal.string(self._prev.text))
4650
4651                if len(expressions) > 1:
4652                    return self.expression(exp.Concat, expressions=expressions)
4653
4654            return primary
4655
4656        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4657            return exp.Literal.number(f"0.{self._prev.text}")
4658
4659        if self._match(TokenType.L_PAREN):
4660            comments = self._prev_comments
4661            query = self._parse_select()
4662
4663            if query:
4664                expressions = [query]
4665            else:
4666                expressions = self._parse_expressions()
4667
4668            this = self._parse_query_modifiers(seq_get(expressions, 0))
4669
4670            if not this and self._match(TokenType.R_PAREN, advance=False):
4671                this = self.expression(exp.Tuple)
4672            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4673                this = self._parse_subquery(this=this, parse_alias=False)
4674            elif isinstance(this, exp.Subquery):
4675                this = self._parse_subquery(
4676                    this=self._parse_set_operations(this), parse_alias=False
4677                )
4678            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4679                this = self.expression(exp.Tuple, expressions=expressions)
4680            else:
4681                this = self.expression(exp.Paren, this=this)
4682
4683            if this:
4684                this.add_comments(comments)
4685
4686            self._match_r_paren(expression=this)
4687            return this
4688
4689        return None
4690
4691    def _parse_field(
4692        self,
4693        any_token: bool = False,
4694        tokens: t.Optional[t.Collection[TokenType]] = None,
4695        anonymous_func: bool = False,
4696    ) -> t.Optional[exp.Expression]:
4697        if anonymous_func:
4698            field = (
4699                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4700                or self._parse_primary()
4701            )
4702        else:
4703            field = self._parse_primary() or self._parse_function(
4704                anonymous=anonymous_func, any_token=any_token
4705            )
4706        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4707
4708    def _parse_function(
4709        self,
4710        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4711        anonymous: bool = False,
4712        optional_parens: bool = True,
4713        any_token: bool = False,
4714    ) -> t.Optional[exp.Expression]:
4715        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4716        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4717        fn_syntax = False
4718        if (
4719            self._match(TokenType.L_BRACE, advance=False)
4720            and self._next
4721            and self._next.text.upper() == "FN"
4722        ):
4723            self._advance(2)
4724            fn_syntax = True
4725
4726        func = self._parse_function_call(
4727            functions=functions,
4728            anonymous=anonymous,
4729            optional_parens=optional_parens,
4730            any_token=any_token,
4731        )
4732
4733        if fn_syntax:
4734            self._match(TokenType.R_BRACE)
4735
4736        return func
4737
4738    def _parse_function_call(
4739        self,
4740        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4741        anonymous: bool = False,
4742        optional_parens: bool = True,
4743        any_token: bool = False,
4744    ) -> t.Optional[exp.Expression]:
4745        if not self._curr:
4746            return None
4747
4748        comments = self._curr.comments
4749        token_type = self._curr.token_type
4750        this = self._curr.text
4751        upper = this.upper()
4752
4753        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4754        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4755            self._advance()
4756            return self._parse_window(parser(self))
4757
4758        if not self._next or self._next.token_type != TokenType.L_PAREN:
4759            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4760                self._advance()
4761                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4762
4763            return None
4764
4765        if any_token:
4766            if token_type in self.RESERVED_TOKENS:
4767                return None
4768        elif token_type not in self.FUNC_TOKENS:
4769            return None
4770
4771        self._advance(2)
4772
4773        parser = self.FUNCTION_PARSERS.get(upper)
4774        if parser and not anonymous:
4775            this = parser(self)
4776        else:
4777            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4778
4779            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4780                this = self.expression(subquery_predicate, this=self._parse_select())
4781                self._match_r_paren()
4782                return this
4783
4784            if functions is None:
4785                functions = self.FUNCTIONS
4786
4787            function = functions.get(upper)
4788
4789            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4790            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4791
4792            if alias:
4793                args = self._kv_to_prop_eq(args)
4794
4795            if function and not anonymous:
4796                if "dialect" in function.__code__.co_varnames:
4797                    func = function(args, dialect=self.dialect)
4798                else:
4799                    func = function(args)
4800
4801                func = self.validate_expression(func, args)
4802                if not self.dialect.NORMALIZE_FUNCTIONS:
4803                    func.meta["name"] = this
4804
4805                this = func
4806            else:
4807                if token_type == TokenType.IDENTIFIER:
4808                    this = exp.Identifier(this=this, quoted=True)
4809                this = self.expression(exp.Anonymous, this=this, expressions=args)
4810
4811        if isinstance(this, exp.Expression):
4812            this.add_comments(comments)
4813
4814        self._match_r_paren(this)
4815        return self._parse_window(this)
4816
4817    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4818        transformed = []
4819
4820        for e in expressions:
4821            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4822                if isinstance(e, exp.Alias):
4823                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4824
4825                if not isinstance(e, exp.PropertyEQ):
4826                    e = self.expression(
4827                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4828                    )
4829
4830                if isinstance(e.this, exp.Column):
4831                    e.this.replace(e.this.this)
4832
4833            transformed.append(e)
4834
4835        return transformed
4836
4837    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4838        return self._parse_column_def(self._parse_id_var())
4839
4840    def _parse_user_defined_function(
4841        self, kind: t.Optional[TokenType] = None
4842    ) -> t.Optional[exp.Expression]:
4843        this = self._parse_id_var()
4844
4845        while self._match(TokenType.DOT):
4846            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
4847
4848        if not self._match(TokenType.L_PAREN):
4849            return this
4850
4851        expressions = self._parse_csv(self._parse_function_parameter)
4852        self._match_r_paren()
4853        return self.expression(
4854            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
4855        )
4856
4857    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
4858        literal = self._parse_primary()
4859        if literal:
4860            return self.expression(exp.Introducer, this=token.text, expression=literal)
4861
4862        return self.expression(exp.Identifier, this=token.text)
4863
4864    def _parse_session_parameter(self) -> exp.SessionParameter:
4865        kind = None
4866        this = self._parse_id_var() or self._parse_primary()
4867
4868        if this and self._match(TokenType.DOT):
4869            kind = this.name
4870            this = self._parse_var() or self._parse_primary()
4871
4872        return self.expression(exp.SessionParameter, this=this, kind=kind)
4873
4874    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
4875        return self._parse_id_var()
4876
4877    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4878        index = self._index
4879
4880        if self._match(TokenType.L_PAREN):
4881            expressions = t.cast(
4882                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
4883            )
4884
4885            if not self._match(TokenType.R_PAREN):
4886                self._retreat(index)
4887        else:
4888            expressions = [self._parse_lambda_arg()]
4889
4890        if self._match_set(self.LAMBDAS):
4891            return self.LAMBDAS[self._prev.token_type](self, expressions)
4892
4893        self._retreat(index)
4894
4895        this: t.Optional[exp.Expression]
4896
4897        if self._match(TokenType.DISTINCT):
4898            this = self.expression(
4899                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
4900            )
4901        else:
4902            this = self._parse_select_or_expression(alias=alias)
4903
4904        return self._parse_limit(
4905            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
4906        )
4907
4908    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4909        index = self._index
4910        if not self._match(TokenType.L_PAREN):
4911            return this
4912
4913        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
4914        # expr can be of both types
4915        if self._match_set(self.SELECT_START_TOKENS):
4916            self._retreat(index)
4917            return this
4918        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4919        self._match_r_paren()
4920        return self.expression(exp.Schema, this=this, expressions=args)
4921
4922    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4923        return self._parse_column_def(self._parse_field(any_token=True))
4924
4925    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4926        # column defs are not really columns, they're identifiers
4927        if isinstance(this, exp.Column):
4928            this = this.this
4929
4930        kind = self._parse_types(schema=True)
4931
4932        if self._match_text_seq("FOR", "ORDINALITY"):
4933            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4934
4935        constraints: t.List[exp.Expression] = []
4936
4937        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
4938            ("ALIAS", "MATERIALIZED")
4939        ):
4940            persisted = self._prev.text.upper() == "MATERIALIZED"
4941            constraints.append(
4942                self.expression(
4943                    exp.ComputedColumnConstraint,
4944                    this=self._parse_assignment(),
4945                    persisted=persisted or self._match_text_seq("PERSISTED"),
4946                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4947                )
4948            )
4949        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4950            self._match(TokenType.ALIAS)
4951            constraints.append(
4952                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4953            )
4954
4955        while True:
4956            constraint = self._parse_column_constraint()
4957            if not constraint:
4958                break
4959            constraints.append(constraint)
4960
4961        if not kind and not constraints:
4962            return this
4963
4964        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4965
4966    def _parse_auto_increment(
4967        self,
4968    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4969        start = None
4970        increment = None
4971
4972        if self._match(TokenType.L_PAREN, advance=False):
4973            args = self._parse_wrapped_csv(self._parse_bitwise)
4974            start = seq_get(args, 0)
4975            increment = seq_get(args, 1)
4976        elif self._match_text_seq("START"):
4977            start = self._parse_bitwise()
4978            self._match_text_seq("INCREMENT")
4979            increment = self._parse_bitwise()
4980
4981        if start and increment:
4982            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4983
4984        return exp.AutoIncrementColumnConstraint()
4985
4986    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4987        if not self._match_text_seq("REFRESH"):
4988            self._retreat(self._index - 1)
4989            return None
4990        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4991
4992    def _parse_compress(self) -> exp.CompressColumnConstraint:
4993        if self._match(TokenType.L_PAREN, advance=False):
4994            return self.expression(
4995                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4996            )
4997
4998        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4999
5000    def _parse_generated_as_identity(
5001        self,
5002    ) -> (
5003        exp.GeneratedAsIdentityColumnConstraint
5004        | exp.ComputedColumnConstraint
5005        | exp.GeneratedAsRowColumnConstraint
5006    ):
5007        if self._match_text_seq("BY", "DEFAULT"):
5008            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5009            this = self.expression(
5010                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5011            )
5012        else:
5013            self._match_text_seq("ALWAYS")
5014            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5015
5016        self._match(TokenType.ALIAS)
5017
5018        if self._match_text_seq("ROW"):
5019            start = self._match_text_seq("START")
5020            if not start:
5021                self._match(TokenType.END)
5022            hidden = self._match_text_seq("HIDDEN")
5023            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5024
5025        identity = self._match_text_seq("IDENTITY")
5026
5027        if self._match(TokenType.L_PAREN):
5028            if self._match(TokenType.START_WITH):
5029                this.set("start", self._parse_bitwise())
5030            if self._match_text_seq("INCREMENT", "BY"):
5031                this.set("increment", self._parse_bitwise())
5032            if self._match_text_seq("MINVALUE"):
5033                this.set("minvalue", self._parse_bitwise())
5034            if self._match_text_seq("MAXVALUE"):
5035                this.set("maxvalue", self._parse_bitwise())
5036
5037            if self._match_text_seq("CYCLE"):
5038                this.set("cycle", True)
5039            elif self._match_text_seq("NO", "CYCLE"):
5040                this.set("cycle", False)
5041
5042            if not identity:
5043                this.set("expression", self._parse_range())
5044            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5045                args = self._parse_csv(self._parse_bitwise)
5046                this.set("start", seq_get(args, 0))
5047                this.set("increment", seq_get(args, 1))
5048
5049            self._match_r_paren()
5050
5051        return this
5052
5053    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5054        self._match_text_seq("LENGTH")
5055        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5056
5057    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5058        if self._match_text_seq("NULL"):
5059            return self.expression(exp.NotNullColumnConstraint)
5060        if self._match_text_seq("CASESPECIFIC"):
5061            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5062        if self._match_text_seq("FOR", "REPLICATION"):
5063            return self.expression(exp.NotForReplicationColumnConstraint)
5064        return None
5065
5066    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5067        if self._match(TokenType.CONSTRAINT):
5068            this = self._parse_id_var()
5069        else:
5070            this = None
5071
5072        if self._match_texts(self.CONSTRAINT_PARSERS):
5073            return self.expression(
5074                exp.ColumnConstraint,
5075                this=this,
5076                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5077            )
5078
5079        return this
5080
5081    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5082        if not self._match(TokenType.CONSTRAINT):
5083            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5084
5085        return self.expression(
5086            exp.Constraint,
5087            this=self._parse_id_var(),
5088            expressions=self._parse_unnamed_constraints(),
5089        )
5090
5091    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5092        constraints = []
5093        while True:
5094            constraint = self._parse_unnamed_constraint() or self._parse_function()
5095            if not constraint:
5096                break
5097            constraints.append(constraint)
5098
5099        return constraints
5100
5101    def _parse_unnamed_constraint(
5102        self, constraints: t.Optional[t.Collection[str]] = None
5103    ) -> t.Optional[exp.Expression]:
5104        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5105            constraints or self.CONSTRAINT_PARSERS
5106        ):
5107            return None
5108
5109        constraint = self._prev.text.upper()
5110        if constraint not in self.CONSTRAINT_PARSERS:
5111            self.raise_error(f"No parser found for schema constraint {constraint}.")
5112
5113        return self.CONSTRAINT_PARSERS[constraint](self)
5114
5115    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5116        self._match_text_seq("KEY")
5117        return self.expression(
5118            exp.UniqueColumnConstraint,
5119            this=self._parse_schema(self._parse_id_var(any_token=False)),
5120            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5121            on_conflict=self._parse_on_conflict(),
5122        )
5123
5124    def _parse_key_constraint_options(self) -> t.List[str]:
5125        options = []
5126        while True:
5127            if not self._curr:
5128                break
5129
5130            if self._match(TokenType.ON):
5131                action = None
5132                on = self._advance_any() and self._prev.text
5133
5134                if self._match_text_seq("NO", "ACTION"):
5135                    action = "NO ACTION"
5136                elif self._match_text_seq("CASCADE"):
5137                    action = "CASCADE"
5138                elif self._match_text_seq("RESTRICT"):
5139                    action = "RESTRICT"
5140                elif self._match_pair(TokenType.SET, TokenType.NULL):
5141                    action = "SET NULL"
5142                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5143                    action = "SET DEFAULT"
5144                else:
5145                    self.raise_error("Invalid key constraint")
5146
5147                options.append(f"ON {on} {action}")
5148            elif self._match_text_seq("NOT", "ENFORCED"):
5149                options.append("NOT ENFORCED")
5150            elif self._match_text_seq("DEFERRABLE"):
5151                options.append("DEFERRABLE")
5152            elif self._match_text_seq("INITIALLY", "DEFERRED"):
5153                options.append("INITIALLY DEFERRED")
5154            elif self._match_text_seq("NORELY"):
5155                options.append("NORELY")
5156            elif self._match_text_seq("MATCH", "FULL"):
5157                options.append("MATCH FULL")
5158            else:
5159                break
5160
5161        return options
5162
5163    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5164        if match and not self._match(TokenType.REFERENCES):
5165            return None
5166
5167        expressions = None
5168        this = self._parse_table(schema=True)
5169        options = self._parse_key_constraint_options()
5170        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5171
5172    def _parse_foreign_key(self) -> exp.ForeignKey:
5173        expressions = self._parse_wrapped_id_vars()
5174        reference = self._parse_references()
5175        options = {}
5176
5177        while self._match(TokenType.ON):
5178            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5179                self.raise_error("Expected DELETE or UPDATE")
5180
5181            kind = self._prev.text.lower()
5182
5183            if self._match_text_seq("NO", "ACTION"):
5184                action = "NO ACTION"
5185            elif self._match(TokenType.SET):
5186                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5187                action = "SET " + self._prev.text.upper()
5188            else:
5189                self._advance()
5190                action = self._prev.text.upper()
5191
5192            options[kind] = action
5193
5194        return self.expression(
5195            exp.ForeignKey,
5196            expressions=expressions,
5197            reference=reference,
5198            **options,  # type: ignore
5199        )
5200
5201    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5202        return self._parse_field()
5203
5204    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5205        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5206            self._retreat(self._index - 1)
5207            return None
5208
5209        id_vars = self._parse_wrapped_id_vars()
5210        return self.expression(
5211            exp.PeriodForSystemTimeConstraint,
5212            this=seq_get(id_vars, 0),
5213            expression=seq_get(id_vars, 1),
5214        )
5215
5216    def _parse_primary_key(
5217        self, wrapped_optional: bool = False, in_props: bool = False
5218    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5219        desc = (
5220            self._match_set((TokenType.ASC, TokenType.DESC))
5221            and self._prev.token_type == TokenType.DESC
5222        )
5223
5224        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5225            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5226
5227        expressions = self._parse_wrapped_csv(
5228            self._parse_primary_key_part, optional=wrapped_optional
5229        )
5230        options = self._parse_key_constraint_options()
5231        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5232
5233    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5234        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5235
5236    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5237        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5238            return this
5239
5240        bracket_kind = self._prev.token_type
5241        expressions = self._parse_csv(
5242            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5243        )
5244
5245        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5246            self.raise_error("Expected ]")
5247        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5248            self.raise_error("Expected }")
5249
5250        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5251        if bracket_kind == TokenType.L_BRACE:
5252            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5253        elif not this:
5254            this = self.expression(exp.Array, expressions=expressions)
5255        else:
5256            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5257            if constructor_type:
5258                return self.expression(constructor_type, expressions=expressions)
5259
5260            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5261            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5262
5263        self._add_comments(this)
5264        return self._parse_bracket(this)
5265
5266    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5267        if self._match(TokenType.COLON):
5268            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5269        return this
5270
5271    def _parse_case(self) -> t.Optional[exp.Expression]:
5272        ifs = []
5273        default = None
5274
5275        comments = self._prev_comments
5276        expression = self._parse_assignment()
5277
5278        while self._match(TokenType.WHEN):
5279            this = self._parse_assignment()
5280            self._match(TokenType.THEN)
5281            then = self._parse_assignment()
5282            ifs.append(self.expression(exp.If, this=this, true=then))
5283
5284        if self._match(TokenType.ELSE):
5285            default = self._parse_assignment()
5286
5287        if not self._match(TokenType.END):
5288            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5289                default = exp.column("interval")
5290            else:
5291                self.raise_error("Expected END after CASE", self._prev)
5292
5293        return self.expression(
5294            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5295        )
5296
5297    def _parse_if(self) -> t.Optional[exp.Expression]:
5298        if self._match(TokenType.L_PAREN):
5299            args = self._parse_csv(self._parse_assignment)
5300            this = self.validate_expression(exp.If.from_arg_list(args), args)
5301            self._match_r_paren()
5302        else:
5303            index = self._index - 1
5304
5305            if self.NO_PAREN_IF_COMMANDS and index == 0:
5306                return self._parse_as_command(self._prev)
5307
5308            condition = self._parse_assignment()
5309
5310            if not condition:
5311                self._retreat(index)
5312                return None
5313
5314            self._match(TokenType.THEN)
5315            true = self._parse_assignment()
5316            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5317            self._match(TokenType.END)
5318            this = self.expression(exp.If, this=condition, true=true, false=false)
5319
5320        return this
5321
5322    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5323        if not self._match_text_seq("VALUE", "FOR"):
5324            self._retreat(self._index - 1)
5325            return None
5326
5327        return self.expression(
5328            exp.NextValueFor,
5329            this=self._parse_column(),
5330            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5331        )
5332
5333    def _parse_extract(self) -> exp.Extract:
5334        this = self._parse_function() or self._parse_var() or self._parse_type()
5335
5336        if self._match(TokenType.FROM):
5337            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5338
5339        if not self._match(TokenType.COMMA):
5340            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5341
5342        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5343
5344    def _parse_gap_fill(self) -> exp.GapFill:
5345        self._match(TokenType.TABLE)
5346        this = self._parse_table()
5347
5348        self._match(TokenType.COMMA)
5349        args = [this, *self._parse_csv(self._parse_lambda)]
5350
5351        gap_fill = exp.GapFill.from_arg_list(args)
5352        return self.validate_expression(gap_fill, args)
5353
5354    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5355        this = self._parse_assignment()
5356
5357        if not self._match(TokenType.ALIAS):
5358            if self._match(TokenType.COMMA):
5359                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5360
5361            self.raise_error("Expected AS after CAST")
5362
5363        fmt = None
5364        to = self._parse_types()
5365
5366        if self._match(TokenType.FORMAT):
5367            fmt_string = self._parse_string()
5368            fmt = self._parse_at_time_zone(fmt_string)
5369
5370            if not to:
5371                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5372            if to.this in exp.DataType.TEMPORAL_TYPES:
5373                this = self.expression(
5374                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5375                    this=this,
5376                    format=exp.Literal.string(
5377                        format_time(
5378                            fmt_string.this if fmt_string else "",
5379                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5380                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5381                        )
5382                    ),
5383                )
5384
5385                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5386                    this.set("zone", fmt.args["zone"])
5387                return this
5388        elif not to:
5389            self.raise_error("Expected TYPE after CAST")
5390        elif isinstance(to, exp.Identifier):
5391            to = exp.DataType.build(to.name, udt=True)
5392        elif to.this == exp.DataType.Type.CHAR:
5393            if self._match(TokenType.CHARACTER_SET):
5394                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5395
5396        return self.expression(
5397            exp.Cast if strict else exp.TryCast,
5398            this=this,
5399            to=to,
5400            format=fmt,
5401            safe=safe,
5402            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5403        )
5404
5405    def _parse_string_agg(self) -> exp.Expression:
5406        if self._match(TokenType.DISTINCT):
5407            args: t.List[t.Optional[exp.Expression]] = [
5408                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5409            ]
5410            if self._match(TokenType.COMMA):
5411                args.extend(self._parse_csv(self._parse_assignment))
5412        else:
5413            args = self._parse_csv(self._parse_assignment)  # type: ignore
5414
5415        index = self._index
5416        if not self._match(TokenType.R_PAREN) and args:
5417            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5418            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5419            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5420            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5421
5422        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5423        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5424        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5425        if not self._match_text_seq("WITHIN", "GROUP"):
5426            self._retreat(index)
5427            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5428
5429        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5430        order = self._parse_order(this=seq_get(args, 0))
5431        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5432
5433    def _parse_convert(
5434        self, strict: bool, safe: t.Optional[bool] = None
5435    ) -> t.Optional[exp.Expression]:
5436        this = self._parse_bitwise()
5437
5438        if self._match(TokenType.USING):
5439            to: t.Optional[exp.Expression] = self.expression(
5440                exp.CharacterSet, this=self._parse_var()
5441            )
5442        elif self._match(TokenType.COMMA):
5443            to = self._parse_types()
5444        else:
5445            to = None
5446
5447        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5448
5449    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5450        """
5451        There are generally two variants of the DECODE function:
5452
5453        - DECODE(bin, charset)
5454        - DECODE(expression, search, result [, search, result] ... [, default])
5455
5456        The second variant will always be parsed into a CASE expression. Note that NULL
5457        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5458        instead of relying on pattern matching.
5459        """
5460        args = self._parse_csv(self._parse_assignment)
5461
5462        if len(args) < 3:
5463            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5464
5465        expression, *expressions = args
5466        if not expression:
5467            return None
5468
5469        ifs = []
5470        for search, result in zip(expressions[::2], expressions[1::2]):
5471            if not search or not result:
5472                return None
5473
5474            if isinstance(search, exp.Literal):
5475                ifs.append(
5476                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5477                )
5478            elif isinstance(search, exp.Null):
5479                ifs.append(
5480                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5481                )
5482            else:
5483                cond = exp.or_(
5484                    exp.EQ(this=expression.copy(), expression=search),
5485                    exp.and_(
5486                        exp.Is(this=expression.copy(), expression=exp.Null()),
5487                        exp.Is(this=search.copy(), expression=exp.Null()),
5488                        copy=False,
5489                    ),
5490                    copy=False,
5491                )
5492                ifs.append(exp.If(this=cond, true=result))
5493
5494        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5495
5496    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5497        self._match_text_seq("KEY")
5498        key = self._parse_column()
5499        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5500        self._match_text_seq("VALUE")
5501        value = self._parse_bitwise()
5502
5503        if not key and not value:
5504            return None
5505        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5506
5507    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5508        if not this or not self._match_text_seq("FORMAT", "JSON"):
5509            return this
5510
5511        return self.expression(exp.FormatJson, this=this)
5512
5513    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5514        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5515        for value in values:
5516            if self._match_text_seq(value, "ON", on):
5517                return f"{value} ON {on}"
5518
5519        return None
5520
5521    @t.overload
5522    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5523
5524    @t.overload
5525    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5526
5527    def _parse_json_object(self, agg=False):
5528        star = self._parse_star()
5529        expressions = (
5530            [star]
5531            if star
5532            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5533        )
5534        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5535
5536        unique_keys = None
5537        if self._match_text_seq("WITH", "UNIQUE"):
5538            unique_keys = True
5539        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5540            unique_keys = False
5541
5542        self._match_text_seq("KEYS")
5543
5544        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5545            self._parse_type()
5546        )
5547        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5548
5549        return self.expression(
5550            exp.JSONObjectAgg if agg else exp.JSONObject,
5551            expressions=expressions,
5552            null_handling=null_handling,
5553            unique_keys=unique_keys,
5554            return_type=return_type,
5555            encoding=encoding,
5556        )
5557
5558    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5559    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5560        if not self._match_text_seq("NESTED"):
5561            this = self._parse_id_var()
5562            kind = self._parse_types(allow_identifiers=False)
5563            nested = None
5564        else:
5565            this = None
5566            kind = None
5567            nested = True
5568
5569        path = self._match_text_seq("PATH") and self._parse_string()
5570        nested_schema = nested and self._parse_json_schema()
5571
5572        return self.expression(
5573            exp.JSONColumnDef,
5574            this=this,
5575            kind=kind,
5576            path=path,
5577            nested_schema=nested_schema,
5578        )
5579
5580    def _parse_json_schema(self) -> exp.JSONSchema:
5581        self._match_text_seq("COLUMNS")
5582        return self.expression(
5583            exp.JSONSchema,
5584            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5585        )
5586
5587    def _parse_json_table(self) -> exp.JSONTable:
5588        this = self._parse_format_json(self._parse_bitwise())
5589        path = self._match(TokenType.COMMA) and self._parse_string()
5590        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5591        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5592        schema = self._parse_json_schema()
5593
5594        return exp.JSONTable(
5595            this=this,
5596            schema=schema,
5597            path=path,
5598            error_handling=error_handling,
5599            empty_handling=empty_handling,
5600        )
5601
5602    def _parse_match_against(self) -> exp.MatchAgainst:
5603        expressions = self._parse_csv(self._parse_column)
5604
5605        self._match_text_seq(")", "AGAINST", "(")
5606
5607        this = self._parse_string()
5608
5609        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5610            modifier = "IN NATURAL LANGUAGE MODE"
5611            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5612                modifier = f"{modifier} WITH QUERY EXPANSION"
5613        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5614            modifier = "IN BOOLEAN MODE"
5615        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5616            modifier = "WITH QUERY EXPANSION"
5617        else:
5618            modifier = None
5619
5620        return self.expression(
5621            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5622        )
5623
5624    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5625    def _parse_open_json(self) -> exp.OpenJSON:
5626        this = self._parse_bitwise()
5627        path = self._match(TokenType.COMMA) and self._parse_string()
5628
5629        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5630            this = self._parse_field(any_token=True)
5631            kind = self._parse_types()
5632            path = self._parse_string()
5633            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5634
5635            return self.expression(
5636                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5637            )
5638
5639        expressions = None
5640        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5641            self._match_l_paren()
5642            expressions = self._parse_csv(_parse_open_json_column_def)
5643
5644        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5645
5646    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5647        args = self._parse_csv(self._parse_bitwise)
5648
5649        if self._match(TokenType.IN):
5650            return self.expression(
5651                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5652            )
5653
5654        if haystack_first:
5655            haystack = seq_get(args, 0)
5656            needle = seq_get(args, 1)
5657        else:
5658            needle = seq_get(args, 0)
5659            haystack = seq_get(args, 1)
5660
5661        return self.expression(
5662            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5663        )
5664
5665    def _parse_predict(self) -> exp.Predict:
5666        self._match_text_seq("MODEL")
5667        this = self._parse_table()
5668
5669        self._match(TokenType.COMMA)
5670        self._match_text_seq("TABLE")
5671
5672        return self.expression(
5673            exp.Predict,
5674            this=this,
5675            expression=self._parse_table(),
5676            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5677        )
5678
5679    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5680        args = self._parse_csv(self._parse_table)
5681        return exp.JoinHint(this=func_name.upper(), expressions=args)
5682
5683    def _parse_substring(self) -> exp.Substring:
5684        # Postgres supports the form: substring(string [from int] [for int])
5685        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5686
5687        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5688
5689        if self._match(TokenType.FROM):
5690            args.append(self._parse_bitwise())
5691        if self._match(TokenType.FOR):
5692            if len(args) == 1:
5693                args.append(exp.Literal.number(1))
5694            args.append(self._parse_bitwise())
5695
5696        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5697
5698    def _parse_trim(self) -> exp.Trim:
5699        # https://www.w3resource.com/sql/character-functions/trim.php
5700        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5701
5702        position = None
5703        collation = None
5704        expression = None
5705
5706        if self._match_texts(self.TRIM_TYPES):
5707            position = self._prev.text.upper()
5708
5709        this = self._parse_bitwise()
5710        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5711            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5712            expression = self._parse_bitwise()
5713
5714            if invert_order:
5715                this, expression = expression, this
5716
5717        if self._match(TokenType.COLLATE):
5718            collation = self._parse_bitwise()
5719
5720        return self.expression(
5721            exp.Trim, this=this, position=position, expression=expression, collation=collation
5722        )
5723
5724    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5725        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5726
5727    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5728        return self._parse_window(self._parse_id_var(), alias=True)
5729
5730    def _parse_respect_or_ignore_nulls(
5731        self, this: t.Optional[exp.Expression]
5732    ) -> t.Optional[exp.Expression]:
5733        if self._match_text_seq("IGNORE", "NULLS"):
5734            return self.expression(exp.IgnoreNulls, this=this)
5735        if self._match_text_seq("RESPECT", "NULLS"):
5736            return self.expression(exp.RespectNulls, this=this)
5737        return this
5738
5739    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5740        if self._match(TokenType.HAVING):
5741            self._match_texts(("MAX", "MIN"))
5742            max = self._prev.text.upper() != "MIN"
5743            return self.expression(
5744                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5745            )
5746
5747        return this
5748
5749    def _parse_window(
5750        self, this: t.Optional[exp.Expression], alias: bool = False
5751    ) -> t.Optional[exp.Expression]:
5752        func = this
5753        comments = func.comments if isinstance(func, exp.Expression) else None
5754
5755        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5756            self._match(TokenType.WHERE)
5757            this = self.expression(
5758                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5759            )
5760            self._match_r_paren()
5761
5762        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5763        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5764        if self._match_text_seq("WITHIN", "GROUP"):
5765            order = self._parse_wrapped(self._parse_order)
5766            this = self.expression(exp.WithinGroup, this=this, expression=order)
5767
5768        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5769        # Some dialects choose to implement and some do not.
5770        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5771
5772        # There is some code above in _parse_lambda that handles
5773        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5774
5775        # The below changes handle
5776        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5777
5778        # Oracle allows both formats
5779        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5780        #   and Snowflake chose to do the same for familiarity
5781        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5782        if isinstance(this, exp.AggFunc):
5783            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5784
5785            if ignore_respect and ignore_respect is not this:
5786                ignore_respect.replace(ignore_respect.this)
5787                this = self.expression(ignore_respect.__class__, this=this)
5788
5789        this = self._parse_respect_or_ignore_nulls(this)
5790
5791        # bigquery select from window x AS (partition by ...)
5792        if alias:
5793            over = None
5794            self._match(TokenType.ALIAS)
5795        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5796            return this
5797        else:
5798            over = self._prev.text.upper()
5799
5800        if comments and isinstance(func, exp.Expression):
5801            func.pop_comments()
5802
5803        if not self._match(TokenType.L_PAREN):
5804            return self.expression(
5805                exp.Window,
5806                comments=comments,
5807                this=this,
5808                alias=self._parse_id_var(False),
5809                over=over,
5810            )
5811
5812        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5813
5814        first = self._match(TokenType.FIRST)
5815        if self._match_text_seq("LAST"):
5816            first = False
5817
5818        partition, order = self._parse_partition_and_order()
5819        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5820
5821        if kind:
5822            self._match(TokenType.BETWEEN)
5823            start = self._parse_window_spec()
5824            self._match(TokenType.AND)
5825            end = self._parse_window_spec()
5826
5827            spec = self.expression(
5828                exp.WindowSpec,
5829                kind=kind,
5830                start=start["value"],
5831                start_side=start["side"],
5832                end=end["value"],
5833                end_side=end["side"],
5834            )
5835        else:
5836            spec = None
5837
5838        self._match_r_paren()
5839
5840        window = self.expression(
5841            exp.Window,
5842            comments=comments,
5843            this=this,
5844            partition_by=partition,
5845            order=order,
5846            spec=spec,
5847            alias=window_alias,
5848            over=over,
5849            first=first,
5850        )
5851
5852        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
5853        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
5854            return self._parse_window(window, alias=alias)
5855
5856        return window
5857
5858    def _parse_partition_and_order(
5859        self,
5860    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
5861        return self._parse_partition_by(), self._parse_order()
5862
5863    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
5864        self._match(TokenType.BETWEEN)
5865
5866        return {
5867            "value": (
5868                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
5869                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
5870                or self._parse_bitwise()
5871            ),
5872            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
5873        }
5874
5875    def _parse_alias(
5876        self, this: t.Optional[exp.Expression], explicit: bool = False
5877    ) -> t.Optional[exp.Expression]:
5878        any_token = self._match(TokenType.ALIAS)
5879        comments = self._prev_comments or []
5880
5881        if explicit and not any_token:
5882            return this
5883
5884        if self._match(TokenType.L_PAREN):
5885            aliases = self.expression(
5886                exp.Aliases,
5887                comments=comments,
5888                this=this,
5889                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
5890            )
5891            self._match_r_paren(aliases)
5892            return aliases
5893
5894        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
5895            self.STRING_ALIASES and self._parse_string_as_identifier()
5896        )
5897
5898        if alias:
5899            comments.extend(alias.pop_comments())
5900            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
5901            column = this.this
5902
5903            # Moves the comment next to the alias in `expr /* comment */ AS alias`
5904            if not this.comments and column and column.comments:
5905                this.comments = column.pop_comments()
5906
5907        return this
5908
5909    def _parse_id_var(
5910        self,
5911        any_token: bool = True,
5912        tokens: t.Optional[t.Collection[TokenType]] = None,
5913    ) -> t.Optional[exp.Expression]:
5914        expression = self._parse_identifier()
5915        if not expression and (
5916            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
5917        ):
5918            quoted = self._prev.token_type == TokenType.STRING
5919            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
5920
5921        return expression
5922
5923    def _parse_string(self) -> t.Optional[exp.Expression]:
5924        if self._match_set(self.STRING_PARSERS):
5925            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
5926        return self._parse_placeholder()
5927
5928    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5929        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5930
5931    def _parse_number(self) -> t.Optional[exp.Expression]:
5932        if self._match_set(self.NUMERIC_PARSERS):
5933            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
5934        return self._parse_placeholder()
5935
5936    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5937        if self._match(TokenType.IDENTIFIER):
5938            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5939        return self._parse_placeholder()
5940
5941    def _parse_var(
5942        self,
5943        any_token: bool = False,
5944        tokens: t.Optional[t.Collection[TokenType]] = None,
5945        upper: bool = False,
5946    ) -> t.Optional[exp.Expression]:
5947        if (
5948            (any_token and self._advance_any())
5949            or self._match(TokenType.VAR)
5950            or (self._match_set(tokens) if tokens else False)
5951        ):
5952            return self.expression(
5953                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5954            )
5955        return self._parse_placeholder()
5956
5957    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5958        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5959            self._advance()
5960            return self._prev
5961        return None
5962
5963    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5964        return self._parse_var() or self._parse_string()
5965
5966    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
5967        return self._parse_primary() or self._parse_var(any_token=True)
5968
5969    def _parse_null(self) -> t.Optional[exp.Expression]:
5970        if self._match_set(self.NULL_TOKENS):
5971            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5972        return self._parse_placeholder()
5973
5974    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5975        if self._match(TokenType.TRUE):
5976            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5977        if self._match(TokenType.FALSE):
5978            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5979        return self._parse_placeholder()
5980
5981    def _parse_star(self) -> t.Optional[exp.Expression]:
5982        if self._match(TokenType.STAR):
5983            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5984        return self._parse_placeholder()
5985
5986    def _parse_parameter(self) -> exp.Parameter:
5987        this = self._parse_identifier() or self._parse_primary_or_var()
5988        return self.expression(exp.Parameter, this=this)
5989
5990    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5991        if self._match_set(self.PLACEHOLDER_PARSERS):
5992            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5993            if placeholder:
5994                return placeholder
5995            self._advance(-1)
5996        return None
5997
5998    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
5999        if not self._match_texts(keywords):
6000            return None
6001        if self._match(TokenType.L_PAREN, advance=False):
6002            return self._parse_wrapped_csv(self._parse_expression)
6003
6004        expression = self._parse_expression()
6005        return [expression] if expression else None
6006
6007    def _parse_csv(
6008        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6009    ) -> t.List[exp.Expression]:
6010        parse_result = parse_method()
6011        items = [parse_result] if parse_result is not None else []
6012
6013        while self._match(sep):
6014            self._add_comments(parse_result)
6015            parse_result = parse_method()
6016            if parse_result is not None:
6017                items.append(parse_result)
6018
6019        return items
6020
6021    def _parse_tokens(
6022        self, parse_method: t.Callable, expressions: t.Dict
6023    ) -> t.Optional[exp.Expression]:
6024        this = parse_method()
6025
6026        while self._match_set(expressions):
6027            this = self.expression(
6028                expressions[self._prev.token_type],
6029                this=this,
6030                comments=self._prev_comments,
6031                expression=parse_method(),
6032            )
6033
6034        return this
6035
6036    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6037        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6038
6039    def _parse_wrapped_csv(
6040        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6041    ) -> t.List[exp.Expression]:
6042        return self._parse_wrapped(
6043            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6044        )
6045
6046    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6047        wrapped = self._match(TokenType.L_PAREN)
6048        if not wrapped and not optional:
6049            self.raise_error("Expecting (")
6050        parse_result = parse_method()
6051        if wrapped:
6052            self._match_r_paren()
6053        return parse_result
6054
6055    def _parse_expressions(self) -> t.List[exp.Expression]:
6056        return self._parse_csv(self._parse_expression)
6057
6058    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6059        return self._parse_select() or self._parse_set_operations(
6060            self._parse_expression() if alias else self._parse_assignment()
6061        )
6062
6063    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6064        return self._parse_query_modifiers(
6065            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6066        )
6067
6068    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6069        this = None
6070        if self._match_texts(self.TRANSACTION_KIND):
6071            this = self._prev.text
6072
6073        self._match_texts(("TRANSACTION", "WORK"))
6074
6075        modes = []
6076        while True:
6077            mode = []
6078            while self._match(TokenType.VAR):
6079                mode.append(self._prev.text)
6080
6081            if mode:
6082                modes.append(" ".join(mode))
6083            if not self._match(TokenType.COMMA):
6084                break
6085
6086        return self.expression(exp.Transaction, this=this, modes=modes)
6087
6088    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6089        chain = None
6090        savepoint = None
6091        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6092
6093        self._match_texts(("TRANSACTION", "WORK"))
6094
6095        if self._match_text_seq("TO"):
6096            self._match_text_seq("SAVEPOINT")
6097            savepoint = self._parse_id_var()
6098
6099        if self._match(TokenType.AND):
6100            chain = not self._match_text_seq("NO")
6101            self._match_text_seq("CHAIN")
6102
6103        if is_rollback:
6104            return self.expression(exp.Rollback, savepoint=savepoint)
6105
6106        return self.expression(exp.Commit, chain=chain)
6107
6108    def _parse_refresh(self) -> exp.Refresh:
6109        self._match(TokenType.TABLE)
6110        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6111
6112    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6113        if not self._match_text_seq("ADD"):
6114            return None
6115
6116        self._match(TokenType.COLUMN)
6117        exists_column = self._parse_exists(not_=True)
6118        expression = self._parse_field_def()
6119
6120        if expression:
6121            expression.set("exists", exists_column)
6122
6123            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6124            if self._match_texts(("FIRST", "AFTER")):
6125                position = self._prev.text
6126                column_position = self.expression(
6127                    exp.ColumnPosition, this=self._parse_column(), position=position
6128                )
6129                expression.set("position", column_position)
6130
6131        return expression
6132
6133    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6134        drop = self._match(TokenType.DROP) and self._parse_drop()
6135        if drop and not isinstance(drop, exp.Command):
6136            drop.set("kind", drop.args.get("kind", "COLUMN"))
6137        return drop
6138
6139    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6140    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6141        return self.expression(
6142            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6143        )
6144
6145    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6146        index = self._index - 1
6147
6148        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6149            return self._parse_csv(
6150                lambda: self.expression(
6151                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6152                )
6153            )
6154
6155        self._retreat(index)
6156        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6157            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6158        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6159
6160    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6161        if self._match_texts(self.ALTER_ALTER_PARSERS):
6162            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6163
6164        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6165        # keyword after ALTER we default to parsing this statement
6166        self._match(TokenType.COLUMN)
6167        column = self._parse_field(any_token=True)
6168
6169        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6170            return self.expression(exp.AlterColumn, this=column, drop=True)
6171        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6172            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6173        if self._match(TokenType.COMMENT):
6174            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6175        if self._match_text_seq("DROP", "NOT", "NULL"):
6176            return self.expression(
6177                exp.AlterColumn,
6178                this=column,
6179                drop=True,
6180                allow_null=True,
6181            )
6182        if self._match_text_seq("SET", "NOT", "NULL"):
6183            return self.expression(
6184                exp.AlterColumn,
6185                this=column,
6186                allow_null=False,
6187            )
6188        self._match_text_seq("SET", "DATA")
6189        self._match_text_seq("TYPE")
6190        return self.expression(
6191            exp.AlterColumn,
6192            this=column,
6193            dtype=self._parse_types(),
6194            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6195            using=self._match(TokenType.USING) and self._parse_assignment(),
6196        )
6197
6198    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6199        if self._match_texts(("ALL", "EVEN", "AUTO")):
6200            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6201
6202        self._match_text_seq("KEY", "DISTKEY")
6203        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6204
6205    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6206        if compound:
6207            self._match_text_seq("SORTKEY")
6208
6209        if self._match(TokenType.L_PAREN, advance=False):
6210            return self.expression(
6211                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6212            )
6213
6214        self._match_texts(("AUTO", "NONE"))
6215        return self.expression(
6216            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6217        )
6218
6219    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6220        index = self._index - 1
6221
6222        partition_exists = self._parse_exists()
6223        if self._match(TokenType.PARTITION, advance=False):
6224            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6225
6226        self._retreat(index)
6227        return self._parse_csv(self._parse_drop_column)
6228
6229    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
6230        if self._match(TokenType.COLUMN):
6231            exists = self._parse_exists()
6232            old_column = self._parse_column()
6233            to = self._match_text_seq("TO")
6234            new_column = self._parse_column()
6235
6236            if old_column is None or to is None or new_column is None:
6237                return None
6238
6239            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6240
6241        self._match_text_seq("TO")
6242        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
6243
6244    def _parse_alter_table_set(self) -> exp.AlterSet:
6245        alter_set = self.expression(exp.AlterSet)
6246
6247        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6248            "TABLE", "PROPERTIES"
6249        ):
6250            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6251        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6252            alter_set.set("expressions", [self._parse_assignment()])
6253        elif self._match_texts(("LOGGED", "UNLOGGED")):
6254            alter_set.set("option", exp.var(self._prev.text.upper()))
6255        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6256            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6257        elif self._match_text_seq("LOCATION"):
6258            alter_set.set("location", self._parse_field())
6259        elif self._match_text_seq("ACCESS", "METHOD"):
6260            alter_set.set("access_method", self._parse_field())
6261        elif self._match_text_seq("TABLESPACE"):
6262            alter_set.set("tablespace", self._parse_field())
6263        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6264            alter_set.set("file_format", [self._parse_field()])
6265        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6266            alter_set.set("file_format", self._parse_wrapped_options())
6267        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6268            alter_set.set("copy_options", self._parse_wrapped_options())
6269        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6270            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6271        else:
6272            if self._match_text_seq("SERDE"):
6273                alter_set.set("serde", self._parse_field())
6274
6275            alter_set.set("expressions", [self._parse_properties()])
6276
6277        return alter_set
6278
6279    def _parse_alter(self) -> exp.AlterTable | exp.Command:
6280        start = self._prev
6281
6282        if not self._match(TokenType.TABLE):
6283            return self._parse_as_command(start)
6284
6285        exists = self._parse_exists()
6286        only = self._match_text_seq("ONLY")
6287        this = self._parse_table(schema=True)
6288        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6289
6290        if self._next:
6291            self._advance()
6292
6293        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6294        if parser:
6295            actions = ensure_list(parser(self))
6296            options = self._parse_csv(self._parse_property)
6297
6298            if not self._curr and actions:
6299                return self.expression(
6300                    exp.AlterTable,
6301                    this=this,
6302                    exists=exists,
6303                    actions=actions,
6304                    only=only,
6305                    options=options,
6306                    cluster=cluster,
6307                )
6308
6309        return self._parse_as_command(start)
6310
6311    def _parse_merge(self) -> exp.Merge:
6312        self._match(TokenType.INTO)
6313        target = self._parse_table()
6314
6315        if target and self._match(TokenType.ALIAS, advance=False):
6316            target.set("alias", self._parse_table_alias())
6317
6318        self._match(TokenType.USING)
6319        using = self._parse_table()
6320
6321        self._match(TokenType.ON)
6322        on = self._parse_assignment()
6323
6324        return self.expression(
6325            exp.Merge,
6326            this=target,
6327            using=using,
6328            on=on,
6329            expressions=self._parse_when_matched(),
6330        )
6331
6332    def _parse_when_matched(self) -> t.List[exp.When]:
6333        whens = []
6334
6335        while self._match(TokenType.WHEN):
6336            matched = not self._match(TokenType.NOT)
6337            self._match_text_seq("MATCHED")
6338            source = (
6339                False
6340                if self._match_text_seq("BY", "TARGET")
6341                else self._match_text_seq("BY", "SOURCE")
6342            )
6343            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6344
6345            self._match(TokenType.THEN)
6346
6347            if self._match(TokenType.INSERT):
6348                _this = self._parse_star()
6349                if _this:
6350                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
6351                else:
6352                    then = self.expression(
6353                        exp.Insert,
6354                        this=self._parse_value(),
6355                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6356                    )
6357            elif self._match(TokenType.UPDATE):
6358                expressions = self._parse_star()
6359                if expressions:
6360                    then = self.expression(exp.Update, expressions=expressions)
6361                else:
6362                    then = self.expression(
6363                        exp.Update,
6364                        expressions=self._match(TokenType.SET)
6365                        and self._parse_csv(self._parse_equality),
6366                    )
6367            elif self._match(TokenType.DELETE):
6368                then = self.expression(exp.Var, this=self._prev.text)
6369            else:
6370                then = None
6371
6372            whens.append(
6373                self.expression(
6374                    exp.When,
6375                    matched=matched,
6376                    source=source,
6377                    condition=condition,
6378                    then=then,
6379                )
6380            )
6381        return whens
6382
6383    def _parse_show(self) -> t.Optional[exp.Expression]:
6384        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
6385        if parser:
6386            return parser(self)
6387        return self._parse_as_command(self._prev)
6388
6389    def _parse_set_item_assignment(
6390        self, kind: t.Optional[str] = None
6391    ) -> t.Optional[exp.Expression]:
6392        index = self._index
6393
6394        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
6395            return self._parse_set_transaction(global_=kind == "GLOBAL")
6396
6397        left = self._parse_primary() or self._parse_column()
6398        assignment_delimiter = self._match_texts(("=", "TO"))
6399
6400        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
6401            self._retreat(index)
6402            return None
6403
6404        right = self._parse_statement() or self._parse_id_var()
6405        if isinstance(right, (exp.Column, exp.Identifier)):
6406            right = exp.var(right.name)
6407
6408        this = self.expression(exp.EQ, this=left, expression=right)
6409        return self.expression(exp.SetItem, this=this, kind=kind)
6410
6411    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
6412        self._match_text_seq("TRANSACTION")
6413        characteristics = self._parse_csv(
6414            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
6415        )
6416        return self.expression(
6417            exp.SetItem,
6418            expressions=characteristics,
6419            kind="TRANSACTION",
6420            **{"global": global_},  # type: ignore
6421        )
6422
6423    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6424        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6425        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6426
6427    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6428        index = self._index
6429        set_ = self.expression(
6430            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6431        )
6432
6433        if self._curr:
6434            self._retreat(index)
6435            return self._parse_as_command(self._prev)
6436
6437        return set_
6438
6439    def _parse_var_from_options(
6440        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6441    ) -> t.Optional[exp.Var]:
6442        start = self._curr
6443        if not start:
6444            return None
6445
6446        option = start.text.upper()
6447        continuations = options.get(option)
6448
6449        index = self._index
6450        self._advance()
6451        for keywords in continuations or []:
6452            if isinstance(keywords, str):
6453                keywords = (keywords,)
6454
6455            if self._match_text_seq(*keywords):
6456                option = f"{option} {' '.join(keywords)}"
6457                break
6458        else:
6459            if continuations or continuations is None:
6460                if raise_unmatched:
6461                    self.raise_error(f"Unknown option {option}")
6462
6463                self._retreat(index)
6464                return None
6465
6466        return exp.var(option)
6467
6468    def _parse_as_command(self, start: Token) -> exp.Command:
6469        while self._curr:
6470            self._advance()
6471        text = self._find_sql(start, self._prev)
6472        size = len(start.text)
6473        self._warn_unsupported()
6474        return exp.Command(this=text[:size], expression=text[size:])
6475
6476    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6477        settings = []
6478
6479        self._match_l_paren()
6480        kind = self._parse_id_var()
6481
6482        if self._match(TokenType.L_PAREN):
6483            while True:
6484                key = self._parse_id_var()
6485                value = self._parse_primary()
6486
6487                if not key and value is None:
6488                    break
6489                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6490            self._match(TokenType.R_PAREN)
6491
6492        self._match_r_paren()
6493
6494        return self.expression(
6495            exp.DictProperty,
6496            this=this,
6497            kind=kind.this if kind else None,
6498            settings=settings,
6499        )
6500
6501    def _parse_dict_range(self, this: str) -> exp.DictRange:
6502        self._match_l_paren()
6503        has_min = self._match_text_seq("MIN")
6504        if has_min:
6505            min = self._parse_var() or self._parse_primary()
6506            self._match_text_seq("MAX")
6507            max = self._parse_var() or self._parse_primary()
6508        else:
6509            max = self._parse_var() or self._parse_primary()
6510            min = exp.Literal.number(0)
6511        self._match_r_paren()
6512        return self.expression(exp.DictRange, this=this, min=min, max=max)
6513
6514    def _parse_comprehension(
6515        self, this: t.Optional[exp.Expression]
6516    ) -> t.Optional[exp.Comprehension]:
6517        index = self._index
6518        expression = self._parse_column()
6519        if not self._match(TokenType.IN):
6520            self._retreat(index - 1)
6521            return None
6522        iterator = self._parse_column()
6523        condition = self._parse_assignment() if self._match_text_seq("IF") else None
6524        return self.expression(
6525            exp.Comprehension,
6526            this=this,
6527            expression=expression,
6528            iterator=iterator,
6529            condition=condition,
6530        )
6531
6532    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6533        if self._match(TokenType.HEREDOC_STRING):
6534            return self.expression(exp.Heredoc, this=self._prev.text)
6535
6536        if not self._match_text_seq("$"):
6537            return None
6538
6539        tags = ["$"]
6540        tag_text = None
6541
6542        if self._is_connected():
6543            self._advance()
6544            tags.append(self._prev.text.upper())
6545        else:
6546            self.raise_error("No closing $ found")
6547
6548        if tags[-1] != "$":
6549            if self._is_connected() and self._match_text_seq("$"):
6550                tag_text = tags[-1]
6551                tags.append("$")
6552            else:
6553                self.raise_error("No closing $ found")
6554
6555        heredoc_start = self._curr
6556
6557        while self._curr:
6558            if self._match_text_seq(*tags, advance=False):
6559                this = self._find_sql(heredoc_start, self._prev)
6560                self._advance(len(tags))
6561                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6562
6563            self._advance()
6564
6565        self.raise_error(f"No closing {''.join(tags)} found")
6566        return None
6567
6568    def _find_parser(
6569        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6570    ) -> t.Optional[t.Callable]:
6571        if not self._curr:
6572            return None
6573
6574        index = self._index
6575        this = []
6576        while True:
6577            # The current token might be multiple words
6578            curr = self._curr.text.upper()
6579            key = curr.split(" ")
6580            this.append(curr)
6581
6582            self._advance()
6583            result, trie = in_trie(trie, key)
6584            if result == TrieResult.FAILED:
6585                break
6586
6587            if result == TrieResult.EXISTS:
6588                subparser = parsers[" ".join(this)]
6589                return subparser
6590
6591        self._retreat(index)
6592        return None
6593
6594    def _match(self, token_type, advance=True, expression=None):
6595        if not self._curr:
6596            return None
6597
6598        if self._curr.token_type == token_type:
6599            if advance:
6600                self._advance()
6601            self._add_comments(expression)
6602            return True
6603
6604        return None
6605
6606    def _match_set(self, types, advance=True):
6607        if not self._curr:
6608            return None
6609
6610        if self._curr.token_type in types:
6611            if advance:
6612                self._advance()
6613            return True
6614
6615        return None
6616
6617    def _match_pair(self, token_type_a, token_type_b, advance=True):
6618        if not self._curr or not self._next:
6619            return None
6620
6621        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6622            if advance:
6623                self._advance(2)
6624            return True
6625
6626        return None
6627
6628    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6629        if not self._match(TokenType.L_PAREN, expression=expression):
6630            self.raise_error("Expecting (")
6631
6632    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6633        if not self._match(TokenType.R_PAREN, expression=expression):
6634            self.raise_error("Expecting )")
6635
6636    def _match_texts(self, texts, advance=True):
6637        if self._curr and self._curr.text.upper() in texts:
6638            if advance:
6639                self._advance()
6640            return True
6641        return None
6642
6643    def _match_text_seq(self, *texts, advance=True):
6644        index = self._index
6645        for text in texts:
6646            if self._curr and self._curr.text.upper() == text:
6647                self._advance()
6648            else:
6649                self._retreat(index)
6650                return None
6651
6652        if not advance:
6653            self._retreat(index)
6654
6655        return True
6656
6657    def _replace_lambda(
6658        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
6659    ) -> t.Optional[exp.Expression]:
6660        if not node:
6661            return node
6662
6663        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
6664
6665        for column in node.find_all(exp.Column):
6666            typ = lambda_types.get(column.parts[0].name)
6667            if typ is not None:
6668                dot_or_id = column.to_dot() if column.table else column.this
6669
6670                if typ:
6671                    dot_or_id = self.expression(
6672                        exp.Cast,
6673                        this=dot_or_id,
6674                        to=typ,
6675                    )
6676
6677                parent = column.parent
6678
6679                while isinstance(parent, exp.Dot):
6680                    if not isinstance(parent.parent, exp.Dot):
6681                        parent.replace(dot_or_id)
6682                        break
6683                    parent = parent.parent
6684                else:
6685                    if column is node:
6686                        node = dot_or_id
6687                    else:
6688                        column.replace(dot_or_id)
6689        return node
6690
6691    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6692        start = self._prev
6693
6694        # Not to be confused with TRUNCATE(number, decimals) function call
6695        if self._match(TokenType.L_PAREN):
6696            self._retreat(self._index - 2)
6697            return self._parse_function()
6698
6699        # Clickhouse supports TRUNCATE DATABASE as well
6700        is_database = self._match(TokenType.DATABASE)
6701
6702        self._match(TokenType.TABLE)
6703
6704        exists = self._parse_exists(not_=False)
6705
6706        expressions = self._parse_csv(
6707            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6708        )
6709
6710        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6711
6712        if self._match_text_seq("RESTART", "IDENTITY"):
6713            identity = "RESTART"
6714        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6715            identity = "CONTINUE"
6716        else:
6717            identity = None
6718
6719        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6720            option = self._prev.text
6721        else:
6722            option = None
6723
6724        partition = self._parse_partition()
6725
6726        # Fallback case
6727        if self._curr:
6728            return self._parse_as_command(start)
6729
6730        return self.expression(
6731            exp.TruncateTable,
6732            expressions=expressions,
6733            is_database=is_database,
6734            exists=exists,
6735            cluster=cluster,
6736            identity=identity,
6737            option=option,
6738            partition=partition,
6739        )
6740
6741    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6742        this = self._parse_ordered(self._parse_opclass)
6743
6744        if not self._match(TokenType.WITH):
6745            return this
6746
6747        op = self._parse_var(any_token=True)
6748
6749        return self.expression(exp.WithOperator, this=this, op=op)
6750
6751    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6752        self._match(TokenType.EQ)
6753        self._match(TokenType.L_PAREN)
6754
6755        opts: t.List[t.Optional[exp.Expression]] = []
6756        while self._curr and not self._match(TokenType.R_PAREN):
6757            if self._match_text_seq("FORMAT_NAME", "="):
6758                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
6759                # so we parse it separately to use _parse_field()
6760                prop = self.expression(
6761                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
6762                )
6763                opts.append(prop)
6764            else:
6765                opts.append(self._parse_property())
6766
6767            self._match(TokenType.COMMA)
6768
6769        return opts
6770
6771    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6772        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6773
6774        options = []
6775        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6776            option = self._parse_var(any_token=True)
6777            prev = self._prev.text.upper()
6778
6779            # Different dialects might separate options and values by white space, "=" and "AS"
6780            self._match(TokenType.EQ)
6781            self._match(TokenType.ALIAS)
6782
6783            param = self.expression(exp.CopyParameter, this=option)
6784
6785            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
6786                TokenType.L_PAREN, advance=False
6787            ):
6788                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
6789                param.set("expressions", self._parse_wrapped_options())
6790            elif prev == "FILE_FORMAT":
6791                # T-SQL's external file format case
6792                param.set("expression", self._parse_field())
6793            else:
6794                param.set("expression", self._parse_unquoted_field())
6795
6796            options.append(param)
6797            self._match(sep)
6798
6799        return options
6800
6801    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6802        expr = self.expression(exp.Credentials)
6803
6804        if self._match_text_seq("STORAGE_INTEGRATION", "="):
6805            expr.set("storage", self._parse_field())
6806        if self._match_text_seq("CREDENTIALS"):
6807            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
6808            creds = (
6809                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6810            )
6811            expr.set("credentials", creds)
6812        if self._match_text_seq("ENCRYPTION"):
6813            expr.set("encryption", self._parse_wrapped_options())
6814        if self._match_text_seq("IAM_ROLE"):
6815            expr.set("iam_role", self._parse_field())
6816        if self._match_text_seq("REGION"):
6817            expr.set("region", self._parse_field())
6818
6819        return expr
6820
6821    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6822        return self._parse_field()
6823
6824    def _parse_copy(self) -> exp.Copy | exp.Command:
6825        start = self._prev
6826
6827        self._match(TokenType.INTO)
6828
6829        this = (
6830            self._parse_select(nested=True, parse_subquery_alias=False)
6831            if self._match(TokenType.L_PAREN, advance=False)
6832            else self._parse_table(schema=True)
6833        )
6834
6835        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
6836
6837        files = self._parse_csv(self._parse_file_location)
6838        credentials = self._parse_credentials()
6839
6840        self._match_text_seq("WITH")
6841
6842        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
6843
6844        # Fallback case
6845        if self._curr:
6846            return self._parse_as_command(start)
6847
6848        return self.expression(
6849            exp.Copy,
6850            this=this,
6851            kind=kind,
6852            credentials=credentials,
6853            files=files,
6854            params=params,
6855        )

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: The amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
  • max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3
Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None)
1234    def __init__(
1235        self,
1236        error_level: t.Optional[ErrorLevel] = None,
1237        error_message_context: int = 100,
1238        max_errors: int = 3,
1239        dialect: DialectType = None,
1240    ):
1241        from sqlglot.dialects import Dialect
1242
1243        self.error_level = error_level or ErrorLevel.IMMEDIATE
1244        self.error_message_context = error_message_context
1245        self.max_errors = max_errors
1246        self.dialect = Dialect.get_or_raise(dialect)
1247        self.reset()
FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONSTRUCT_COMPACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConstructCompact'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_HAS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_CONTAINS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'ARRAY_HAS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, '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_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <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_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, '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'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, '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'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Datetime'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, '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': <function build_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'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, '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': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, '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'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, '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': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, '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'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, '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_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, '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'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function build_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>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>}
NESTED_TYPE_TOKENS = {<TokenType.MAP: 'MAP'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LIST: 'LIST'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATE: 'DATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.COMMA: 'COMMA'>, <TokenType.SELECT: 'SELECT'>, <TokenType.GT: 'GT'>, <TokenType.DOT: 'DOT'>, <TokenType.CARET: 'CARET'>, <TokenType.PLUS: 'PLUS'>, <TokenType.STAR: 'STAR'>, <TokenType.PIPE: 'PIPE'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.LT: 'LT'>, <TokenType.DASH: 'DASH'>, <TokenType.NOT: 'NOT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.TILDA: 'TILDA'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.MOD: 'MOD'>, <TokenType.EQ: 'EQ'>, <TokenType.COLON: 'COLON'>, <TokenType.HASH: 'HASH'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.AMP: 'AMP'>, <TokenType.R_PAREN: 'R_PAREN'>}
DB_CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TAG: 'TAG'>}
CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TAG: 'TAG'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
ID_VAR_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
INTERVAL_VARS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
TABLE_ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.FIRST: 'FIRST'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATE: 'DATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.FIRST: 'FIRST'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DATE: 'DATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LIKE: 'LIKE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.VAR: 'VAR'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LIST: 'LIST'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.XOR: 'XOR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.INSERT: 'INSERT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GLOB: 'GLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATE: 'DATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
CONJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>}
ASSIGNMENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>}
DISJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<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'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.SEMI: 'SEMI'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>}
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.When'>: <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.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <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>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <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>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <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>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'FOREIGN KEY', 'CHECK', 'LIKE', 'EXCLUDE', 'PERIOD', 'UNIQUE', 'PRIMARY KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
INSERT_ALTERNATIVES = {'ROLLBACK', 'IGNORE', 'ABORT', 'REPLACE', 'FAIL'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'STREAM', 'STATEMENT', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'WITH', 'DESC', 'NULLS'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>}
VIEW_ATTRIBUTES = {'VIEW_METADATA', 'ENCRYPTION', 'SCHEMABINDING'}
WINDOW_ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>}
FETCH_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.KEY: 'KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SUPER: 'SUPER'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FALSE: 'FALSE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NULL: 'NULL'>, <TokenType.UINT: 'UINT'>, <TokenType.INET: 'INET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USE: 'USE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT: 'INT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CASE: 'CASE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.KILL: 'KILL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.VAR: 'VAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TRUE: 'TRUE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ALL: 'ALL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROWS: 'ROWS'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.ANY: 'ANY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LIST: 'LIST'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATE: 'DATE'>, <TokenType.INT256: 'INT256'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FULL: 'FULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COPY: 'COPY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TAG: 'TAG'>, <TokenType.SOME: 'SOME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MODEL: 'MODEL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SET: 'SET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.END: 'END'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UUID: 'UUID'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.IS: 'IS'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'COPY_OPTIONS', 'CREDENTIAL', 'FORMAT_OPTIONS', 'FILE_FORMAT'}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'limit', 'offset', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_JSON_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1249    def reset(self):
1250        self.sql = ""
1251        self.errors = []
1252        self._tokens = []
1253        self._index = 0
1254        self._curr = None
1255        self._next = None
1256        self._prev = None
1257        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1259    def parse(
1260        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1261    ) -> t.List[t.Optional[exp.Expression]]:
1262        """
1263        Parses a list of tokens and returns a list of syntax trees, one tree
1264        per parsed SQL statement.
1265
1266        Args:
1267            raw_tokens: The list of tokens.
1268            sql: The original SQL string, used to produce helpful debug messages.
1269
1270        Returns:
1271            The list of the produced syntax trees.
1272        """
1273        return self._parse(
1274            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1275        )

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]]:
1277    def parse_into(
1278        self,
1279        expression_types: exp.IntoType,
1280        raw_tokens: t.List[Token],
1281        sql: t.Optional[str] = None,
1282    ) -> t.List[t.Optional[exp.Expression]]:
1283        """
1284        Parses a list of tokens into a given Expression type. If a collection of Expression
1285        types is given instead, this method will try to parse the token list into each one
1286        of them, stopping at the first for which the parsing succeeds.
1287
1288        Args:
1289            expression_types: The expression type(s) to try and parse the token list into.
1290            raw_tokens: The list of tokens.
1291            sql: The original SQL string, used to produce helpful debug messages.
1292
1293        Returns:
1294            The target Expression.
1295        """
1296        errors = []
1297        for expression_type in ensure_list(expression_types):
1298            parser = self.EXPRESSION_PARSERS.get(expression_type)
1299            if not parser:
1300                raise TypeError(f"No parser registered for {expression_type}")
1301
1302            try:
1303                return self._parse(parser, raw_tokens, sql)
1304            except ParseError as e:
1305                e.errors[0]["into_expression"] = expression_type
1306                errors.append(e)
1307
1308        raise ParseError(
1309            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1310            errors=merge_errors(errors),
1311        ) 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:
1351    def check_errors(self) -> None:
1352        """Logs or raises any found errors, depending on the chosen error level setting."""
1353        if self.error_level == ErrorLevel.WARN:
1354            for error in self.errors:
1355                logger.error(str(error))
1356        elif self.error_level == ErrorLevel.RAISE and self.errors:
1357            raise ParseError(
1358                concat_messages(self.errors, self.max_errors),
1359                errors=merge_errors(self.errors),
1360            )

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:
1362    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1363        """
1364        Appends an error in the list of recorded errors or raises it, depending on the chosen
1365        error level setting.
1366        """
1367        token = token or self._curr or self._prev or Token.string("")
1368        start = token.start
1369        end = token.end + 1
1370        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1371        highlight = self.sql[start:end]
1372        end_context = self.sql[end : end + self.error_message_context]
1373
1374        error = ParseError.new(
1375            f"{message}. Line {token.line}, Col: {token.col}.\n"
1376            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1377            description=message,
1378            line=token.line,
1379            col=token.col,
1380            start_context=start_context,
1381            highlight=highlight,
1382            end_context=end_context,
1383        )
1384
1385        if self.error_level == ErrorLevel.IMMEDIATE:
1386            raise error
1387
1388        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:
1390    def expression(
1391        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1392    ) -> E:
1393        """
1394        Creates a new, validated Expression.
1395
1396        Args:
1397            exp_class: The expression class to instantiate.
1398            comments: An optional list of comments to attach to the expression.
1399            kwargs: The arguments to set for the expression along with their respective values.
1400
1401        Returns:
1402            The target expression.
1403        """
1404        instance = exp_class(**kwargs)
1405        instance.add_comments(comments) if comments else self._add_comments(instance)
1406        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:
1413    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1414        """
1415        Validates an Expression, making sure that all its mandatory arguments are set.
1416
1417        Args:
1418            expression: The expression to validate.
1419            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1420
1421        Returns:
1422            The validated expression.
1423        """
1424        if self.error_level != ErrorLevel.IGNORE:
1425            for error_message in expression.error_messages(args):
1426                self.raise_error(error_message)
1427
1428        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