sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

       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    TCeilFloor = t.TypeVar("TCeilFloor", exp.Ceil, exp.Floor)
      20
      21logger = logging.getLogger("sqlglot")
      22
      23OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
      24
      25
      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))
      37
      38
      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
      42
      43
      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
      56
      57
      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)
      69
      70
      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)
      74
      75
      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)
      80
      81
      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)
      86
      87
      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
      99
     100
     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)
     110
     111
     112def build_pad(args: t.List, is_left: bool = True):
     113    return exp.Pad(
     114        this=seq_get(args, 0),
     115        expression=seq_get(args, 1),
     116        fill_pattern=seq_get(args, 2),
     117        is_left=is_left,
     118    )
     119
     120
     121def build_array_constructor(
     122    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
     123) -> exp.Expression:
     124    array_exp = exp_class(expressions=args)
     125
     126    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
     127        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
     128
     129    return array_exp
     130
     131
     132def build_convert_timezone(
     133    args: t.List, default_source_tz: t.Optional[str] = None
     134) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
     135    if len(args) == 2:
     136        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
     137        return exp.ConvertTimezone(
     138            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
     139        )
     140
     141    return exp.ConvertTimezone.from_arg_list(args)
     142
     143
     144def build_trim(args: t.List, is_left: bool = True):
     145    return exp.Trim(
     146        this=seq_get(args, 0),
     147        expression=seq_get(args, 1),
     148        position="LEADING" if is_left else "TRAILING",
     149    )
     150
     151
     152def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
     153    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)
     154
     155
     156def build_locate_strposition(args: t.List):
     157    return exp.StrPosition(
     158        this=seq_get(args, 1),
     159        substr=seq_get(args, 0),
     160        position=seq_get(args, 2),
     161    )
     162
     163
     164class _Parser(type):
     165    def __new__(cls, clsname, bases, attrs):
     166        klass = super().__new__(cls, clsname, bases, attrs)
     167
     168        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
     169        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
     170
     171        return klass
     172
     173
     174class Parser(metaclass=_Parser):
     175    """
     176    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     177
     178    Args:
     179        error_level: The desired error level.
     180            Default: ErrorLevel.IMMEDIATE
     181        error_message_context: The amount of context to capture from a query string when displaying
     182            the error message (in number of characters).
     183            Default: 100
     184        max_errors: Maximum number of error messages to include in a raised ParseError.
     185            This is only relevant if error_level is ErrorLevel.RAISE.
     186            Default: 3
     187    """
     188
     189    FUNCTIONS: t.Dict[str, t.Callable] = {
     190        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     191        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
     192        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
     193        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
     194            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     195        ),
     196        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
     197            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     198        ),
     199        "CHAR": lambda args: exp.Chr(expressions=args),
     200        "CHR": lambda args: exp.Chr(expressions=args),
     201        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
     202        "CONCAT": lambda args, dialect: exp.Concat(
     203            expressions=args,
     204            safe=not dialect.STRICT_STRING_CONCAT,
     205            coalesce=dialect.CONCAT_COALESCE,
     206        ),
     207        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     208            expressions=args,
     209            safe=not dialect.STRICT_STRING_CONCAT,
     210            coalesce=dialect.CONCAT_COALESCE,
     211        ),
     212        "CONVERT_TIMEZONE": build_convert_timezone,
     213        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     214            this=seq_get(args, 0),
     215            to=exp.DataType(this=exp.DataType.Type.TEXT),
     216        ),
     217        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
     218            start=seq_get(args, 0),
     219            end=seq_get(args, 1),
     220            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
     221        ),
     222        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     223        "HEX": build_hex,
     224        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     225        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     226        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     227        "LIKE": build_like,
     228        "LOG": build_logarithm,
     229        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     230        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     231        "LOWER": build_lower,
     232        "LPAD": lambda args: build_pad(args),
     233        "LEFTPAD": lambda args: build_pad(args),
     234        "LTRIM": lambda args: build_trim(args),
     235        "MOD": build_mod,
     236        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
     237        "RPAD": lambda args: build_pad(args, is_left=False),
     238        "RTRIM": lambda args: build_trim(args, is_left=False),
     239        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
     240        if len(args) != 2
     241        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
     242        "STRPOS": exp.StrPosition.from_arg_list,
     243        "CHARINDEX": lambda args: build_locate_strposition(args),
     244        "INSTR": exp.StrPosition.from_arg_list,
     245        "LOCATE": lambda args: build_locate_strposition(args),
     246        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     247            this=seq_get(args, 0),
     248            to=exp.DataType(this=exp.DataType.Type.TEXT),
     249        ),
     250        "TO_HEX": build_hex,
     251        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     252            this=exp.Cast(
     253                this=seq_get(args, 0),
     254                to=exp.DataType(this=exp.DataType.Type.TEXT),
     255            ),
     256            start=exp.Literal.number(1),
     257            length=exp.Literal.number(10),
     258        ),
     259        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
     260        "UPPER": build_upper,
     261        "VAR_MAP": build_var_map,
     262    }
     263
     264    NO_PAREN_FUNCTIONS = {
     265        TokenType.CURRENT_DATE: exp.CurrentDate,
     266        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     267        TokenType.CURRENT_TIME: exp.CurrentTime,
     268        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     269        TokenType.CURRENT_USER: exp.CurrentUser,
     270    }
     271
     272    STRUCT_TYPE_TOKENS = {
     273        TokenType.NESTED,
     274        TokenType.OBJECT,
     275        TokenType.STRUCT,
     276        TokenType.UNION,
     277    }
     278
     279    NESTED_TYPE_TOKENS = {
     280        TokenType.ARRAY,
     281        TokenType.LIST,
     282        TokenType.LOWCARDINALITY,
     283        TokenType.MAP,
     284        TokenType.NULLABLE,
     285        TokenType.RANGE,
     286        *STRUCT_TYPE_TOKENS,
     287    }
     288
     289    ENUM_TYPE_TOKENS = {
     290        TokenType.DYNAMIC,
     291        TokenType.ENUM,
     292        TokenType.ENUM8,
     293        TokenType.ENUM16,
     294    }
     295
     296    AGGREGATE_TYPE_TOKENS = {
     297        TokenType.AGGREGATEFUNCTION,
     298        TokenType.SIMPLEAGGREGATEFUNCTION,
     299    }
     300
     301    TYPE_TOKENS = {
     302        TokenType.BIT,
     303        TokenType.BOOLEAN,
     304        TokenType.TINYINT,
     305        TokenType.UTINYINT,
     306        TokenType.SMALLINT,
     307        TokenType.USMALLINT,
     308        TokenType.INT,
     309        TokenType.UINT,
     310        TokenType.BIGINT,
     311        TokenType.UBIGINT,
     312        TokenType.INT128,
     313        TokenType.UINT128,
     314        TokenType.INT256,
     315        TokenType.UINT256,
     316        TokenType.MEDIUMINT,
     317        TokenType.UMEDIUMINT,
     318        TokenType.FIXEDSTRING,
     319        TokenType.FLOAT,
     320        TokenType.DOUBLE,
     321        TokenType.UDOUBLE,
     322        TokenType.CHAR,
     323        TokenType.NCHAR,
     324        TokenType.VARCHAR,
     325        TokenType.NVARCHAR,
     326        TokenType.BPCHAR,
     327        TokenType.TEXT,
     328        TokenType.MEDIUMTEXT,
     329        TokenType.LONGTEXT,
     330        TokenType.MEDIUMBLOB,
     331        TokenType.LONGBLOB,
     332        TokenType.BINARY,
     333        TokenType.VARBINARY,
     334        TokenType.JSON,
     335        TokenType.JSONB,
     336        TokenType.INTERVAL,
     337        TokenType.TINYBLOB,
     338        TokenType.TINYTEXT,
     339        TokenType.TIME,
     340        TokenType.TIMETZ,
     341        TokenType.TIMESTAMP,
     342        TokenType.TIMESTAMP_S,
     343        TokenType.TIMESTAMP_MS,
     344        TokenType.TIMESTAMP_NS,
     345        TokenType.TIMESTAMPTZ,
     346        TokenType.TIMESTAMPLTZ,
     347        TokenType.TIMESTAMPNTZ,
     348        TokenType.DATETIME,
     349        TokenType.DATETIME2,
     350        TokenType.DATETIME64,
     351        TokenType.SMALLDATETIME,
     352        TokenType.DATE,
     353        TokenType.DATE32,
     354        TokenType.INT4RANGE,
     355        TokenType.INT4MULTIRANGE,
     356        TokenType.INT8RANGE,
     357        TokenType.INT8MULTIRANGE,
     358        TokenType.NUMRANGE,
     359        TokenType.NUMMULTIRANGE,
     360        TokenType.TSRANGE,
     361        TokenType.TSMULTIRANGE,
     362        TokenType.TSTZRANGE,
     363        TokenType.TSTZMULTIRANGE,
     364        TokenType.DATERANGE,
     365        TokenType.DATEMULTIRANGE,
     366        TokenType.DECIMAL,
     367        TokenType.DECIMAL32,
     368        TokenType.DECIMAL64,
     369        TokenType.DECIMAL128,
     370        TokenType.DECIMAL256,
     371        TokenType.UDECIMAL,
     372        TokenType.BIGDECIMAL,
     373        TokenType.UUID,
     374        TokenType.GEOGRAPHY,
     375        TokenType.GEOMETRY,
     376        TokenType.POINT,
     377        TokenType.RING,
     378        TokenType.LINESTRING,
     379        TokenType.MULTILINESTRING,
     380        TokenType.POLYGON,
     381        TokenType.MULTIPOLYGON,
     382        TokenType.HLLSKETCH,
     383        TokenType.HSTORE,
     384        TokenType.PSEUDO_TYPE,
     385        TokenType.SUPER,
     386        TokenType.SERIAL,
     387        TokenType.SMALLSERIAL,
     388        TokenType.BIGSERIAL,
     389        TokenType.XML,
     390        TokenType.YEAR,
     391        TokenType.USERDEFINED,
     392        TokenType.MONEY,
     393        TokenType.SMALLMONEY,
     394        TokenType.ROWVERSION,
     395        TokenType.IMAGE,
     396        TokenType.VARIANT,
     397        TokenType.VECTOR,
     398        TokenType.OBJECT,
     399        TokenType.OBJECT_IDENTIFIER,
     400        TokenType.INET,
     401        TokenType.IPADDRESS,
     402        TokenType.IPPREFIX,
     403        TokenType.IPV4,
     404        TokenType.IPV6,
     405        TokenType.UNKNOWN,
     406        TokenType.NULL,
     407        TokenType.NAME,
     408        TokenType.TDIGEST,
     409        TokenType.DYNAMIC,
     410        *ENUM_TYPE_TOKENS,
     411        *NESTED_TYPE_TOKENS,
     412        *AGGREGATE_TYPE_TOKENS,
     413    }
     414
     415    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     416        TokenType.BIGINT: TokenType.UBIGINT,
     417        TokenType.INT: TokenType.UINT,
     418        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     419        TokenType.SMALLINT: TokenType.USMALLINT,
     420        TokenType.TINYINT: TokenType.UTINYINT,
     421        TokenType.DECIMAL: TokenType.UDECIMAL,
     422        TokenType.DOUBLE: TokenType.UDOUBLE,
     423    }
     424
     425    SUBQUERY_PREDICATES = {
     426        TokenType.ANY: exp.Any,
     427        TokenType.ALL: exp.All,
     428        TokenType.EXISTS: exp.Exists,
     429        TokenType.SOME: exp.Any,
     430    }
     431
     432    RESERVED_TOKENS = {
     433        *Tokenizer.SINGLE_TOKENS.values(),
     434        TokenType.SELECT,
     435    } - {TokenType.IDENTIFIER}
     436
     437    DB_CREATABLES = {
     438        TokenType.DATABASE,
     439        TokenType.DICTIONARY,
     440        TokenType.MODEL,
     441        TokenType.NAMESPACE,
     442        TokenType.SCHEMA,
     443        TokenType.SEQUENCE,
     444        TokenType.SINK,
     445        TokenType.SOURCE,
     446        TokenType.STORAGE_INTEGRATION,
     447        TokenType.STREAMLIT,
     448        TokenType.TABLE,
     449        TokenType.TAG,
     450        TokenType.VIEW,
     451        TokenType.WAREHOUSE,
     452    }
     453
     454    CREATABLES = {
     455        TokenType.COLUMN,
     456        TokenType.CONSTRAINT,
     457        TokenType.FOREIGN_KEY,
     458        TokenType.FUNCTION,
     459        TokenType.INDEX,
     460        TokenType.PROCEDURE,
     461        *DB_CREATABLES,
     462    }
     463
     464    ALTERABLES = {
     465        TokenType.INDEX,
     466        TokenType.TABLE,
     467        TokenType.VIEW,
     468    }
     469
     470    # Tokens that can represent identifiers
     471    ID_VAR_TOKENS = {
     472        TokenType.ALL,
     473        TokenType.ATTACH,
     474        TokenType.VAR,
     475        TokenType.ANTI,
     476        TokenType.APPLY,
     477        TokenType.ASC,
     478        TokenType.ASOF,
     479        TokenType.AUTO_INCREMENT,
     480        TokenType.BEGIN,
     481        TokenType.BPCHAR,
     482        TokenType.CACHE,
     483        TokenType.CASE,
     484        TokenType.COLLATE,
     485        TokenType.COMMAND,
     486        TokenType.COMMENT,
     487        TokenType.COMMIT,
     488        TokenType.CONSTRAINT,
     489        TokenType.COPY,
     490        TokenType.CUBE,
     491        TokenType.CURRENT_SCHEMA,
     492        TokenType.DEFAULT,
     493        TokenType.DELETE,
     494        TokenType.DESC,
     495        TokenType.DESCRIBE,
     496        TokenType.DETACH,
     497        TokenType.DICTIONARY,
     498        TokenType.DIV,
     499        TokenType.END,
     500        TokenType.EXECUTE,
     501        TokenType.EXPORT,
     502        TokenType.ESCAPE,
     503        TokenType.FALSE,
     504        TokenType.FIRST,
     505        TokenType.FILTER,
     506        TokenType.FINAL,
     507        TokenType.FORMAT,
     508        TokenType.FULL,
     509        TokenType.IDENTIFIER,
     510        TokenType.IS,
     511        TokenType.ISNULL,
     512        TokenType.INTERVAL,
     513        TokenType.KEEP,
     514        TokenType.KILL,
     515        TokenType.LEFT,
     516        TokenType.LIMIT,
     517        TokenType.LOAD,
     518        TokenType.MERGE,
     519        TokenType.NATURAL,
     520        TokenType.NEXT,
     521        TokenType.OFFSET,
     522        TokenType.OPERATOR,
     523        TokenType.ORDINALITY,
     524        TokenType.OVERLAPS,
     525        TokenType.OVERWRITE,
     526        TokenType.PARTITION,
     527        TokenType.PERCENT,
     528        TokenType.PIVOT,
     529        TokenType.PRAGMA,
     530        TokenType.RANGE,
     531        TokenType.RECURSIVE,
     532        TokenType.REFERENCES,
     533        TokenType.REFRESH,
     534        TokenType.RENAME,
     535        TokenType.REPLACE,
     536        TokenType.RIGHT,
     537        TokenType.ROLLUP,
     538        TokenType.ROW,
     539        TokenType.ROWS,
     540        TokenType.SEMI,
     541        TokenType.SET,
     542        TokenType.SETTINGS,
     543        TokenType.SHOW,
     544        TokenType.TEMPORARY,
     545        TokenType.TOP,
     546        TokenType.TRUE,
     547        TokenType.TRUNCATE,
     548        TokenType.UNIQUE,
     549        TokenType.UNNEST,
     550        TokenType.UNPIVOT,
     551        TokenType.UPDATE,
     552        TokenType.USE,
     553        TokenType.VOLATILE,
     554        TokenType.WINDOW,
     555        *CREATABLES,
     556        *SUBQUERY_PREDICATES,
     557        *TYPE_TOKENS,
     558        *NO_PAREN_FUNCTIONS,
     559    }
     560    ID_VAR_TOKENS.remove(TokenType.UNION)
     561
     562    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     563        TokenType.ANTI,
     564        TokenType.APPLY,
     565        TokenType.ASOF,
     566        TokenType.FULL,
     567        TokenType.LEFT,
     568        TokenType.LOCK,
     569        TokenType.NATURAL,
     570        TokenType.RIGHT,
     571        TokenType.SEMI,
     572        TokenType.WINDOW,
     573    }
     574
     575    ALIAS_TOKENS = ID_VAR_TOKENS
     576
     577    ARRAY_CONSTRUCTORS = {
     578        "ARRAY": exp.Array,
     579        "LIST": exp.List,
     580    }
     581
     582    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     583
     584    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     585
     586    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     587
     588    FUNC_TOKENS = {
     589        TokenType.COLLATE,
     590        TokenType.COMMAND,
     591        TokenType.CURRENT_DATE,
     592        TokenType.CURRENT_DATETIME,
     593        TokenType.CURRENT_SCHEMA,
     594        TokenType.CURRENT_TIMESTAMP,
     595        TokenType.CURRENT_TIME,
     596        TokenType.CURRENT_USER,
     597        TokenType.FILTER,
     598        TokenType.FIRST,
     599        TokenType.FORMAT,
     600        TokenType.GLOB,
     601        TokenType.IDENTIFIER,
     602        TokenType.INDEX,
     603        TokenType.ISNULL,
     604        TokenType.ILIKE,
     605        TokenType.INSERT,
     606        TokenType.LIKE,
     607        TokenType.MERGE,
     608        TokenType.NEXT,
     609        TokenType.OFFSET,
     610        TokenType.PRIMARY_KEY,
     611        TokenType.RANGE,
     612        TokenType.REPLACE,
     613        TokenType.RLIKE,
     614        TokenType.ROW,
     615        TokenType.UNNEST,
     616        TokenType.VAR,
     617        TokenType.LEFT,
     618        TokenType.RIGHT,
     619        TokenType.SEQUENCE,
     620        TokenType.DATE,
     621        TokenType.DATETIME,
     622        TokenType.TABLE,
     623        TokenType.TIMESTAMP,
     624        TokenType.TIMESTAMPTZ,
     625        TokenType.TRUNCATE,
     626        TokenType.WINDOW,
     627        TokenType.XOR,
     628        *TYPE_TOKENS,
     629        *SUBQUERY_PREDICATES,
     630    }
     631
     632    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     633        TokenType.AND: exp.And,
     634    }
     635
     636    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     637        TokenType.COLON_EQ: exp.PropertyEQ,
     638    }
     639
     640    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     641        TokenType.OR: exp.Or,
     642    }
     643
     644    EQUALITY = {
     645        TokenType.EQ: exp.EQ,
     646        TokenType.NEQ: exp.NEQ,
     647        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     648    }
     649
     650    COMPARISON = {
     651        TokenType.GT: exp.GT,
     652        TokenType.GTE: exp.GTE,
     653        TokenType.LT: exp.LT,
     654        TokenType.LTE: exp.LTE,
     655    }
     656
     657    BITWISE = {
     658        TokenType.AMP: exp.BitwiseAnd,
     659        TokenType.CARET: exp.BitwiseXor,
     660        TokenType.PIPE: exp.BitwiseOr,
     661    }
     662
     663    TERM = {
     664        TokenType.DASH: exp.Sub,
     665        TokenType.PLUS: exp.Add,
     666        TokenType.MOD: exp.Mod,
     667        TokenType.COLLATE: exp.Collate,
     668    }
     669
     670    FACTOR = {
     671        TokenType.DIV: exp.IntDiv,
     672        TokenType.LR_ARROW: exp.Distance,
     673        TokenType.SLASH: exp.Div,
     674        TokenType.STAR: exp.Mul,
     675    }
     676
     677    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     678
     679    TIMES = {
     680        TokenType.TIME,
     681        TokenType.TIMETZ,
     682    }
     683
     684    TIMESTAMPS = {
     685        TokenType.TIMESTAMP,
     686        TokenType.TIMESTAMPTZ,
     687        TokenType.TIMESTAMPLTZ,
     688        *TIMES,
     689    }
     690
     691    SET_OPERATIONS = {
     692        TokenType.UNION,
     693        TokenType.INTERSECT,
     694        TokenType.EXCEPT,
     695    }
     696
     697    JOIN_METHODS = {
     698        TokenType.ASOF,
     699        TokenType.NATURAL,
     700        TokenType.POSITIONAL,
     701    }
     702
     703    JOIN_SIDES = {
     704        TokenType.LEFT,
     705        TokenType.RIGHT,
     706        TokenType.FULL,
     707    }
     708
     709    JOIN_KINDS = {
     710        TokenType.ANTI,
     711        TokenType.CROSS,
     712        TokenType.INNER,
     713        TokenType.OUTER,
     714        TokenType.SEMI,
     715        TokenType.STRAIGHT_JOIN,
     716    }
     717
     718    JOIN_HINTS: t.Set[str] = set()
     719
     720    LAMBDAS = {
     721        TokenType.ARROW: lambda self, expressions: self.expression(
     722            exp.Lambda,
     723            this=self._replace_lambda(
     724                self._parse_assignment(),
     725                expressions,
     726            ),
     727            expressions=expressions,
     728        ),
     729        TokenType.FARROW: lambda self, expressions: self.expression(
     730            exp.Kwarg,
     731            this=exp.var(expressions[0].name),
     732            expression=self._parse_assignment(),
     733        ),
     734    }
     735
     736    COLUMN_OPERATORS = {
     737        TokenType.DOT: None,
     738        TokenType.DOTCOLON: lambda self, this, to: self.expression(
     739            exp.JSONCast,
     740            this=this,
     741            to=to,
     742        ),
     743        TokenType.DCOLON: lambda self, this, to: self.expression(
     744            exp.Cast if self.STRICT_CAST else exp.TryCast,
     745            this=this,
     746            to=to,
     747        ),
     748        TokenType.ARROW: lambda self, this, path: self.expression(
     749            exp.JSONExtract,
     750            this=this,
     751            expression=self.dialect.to_json_path(path),
     752            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     753        ),
     754        TokenType.DARROW: lambda self, this, path: self.expression(
     755            exp.JSONExtractScalar,
     756            this=this,
     757            expression=self.dialect.to_json_path(path),
     758            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     759        ),
     760        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     761            exp.JSONBExtract,
     762            this=this,
     763            expression=path,
     764        ),
     765        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     766            exp.JSONBExtractScalar,
     767            this=this,
     768            expression=path,
     769        ),
     770        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     771            exp.JSONBContains,
     772            this=this,
     773            expression=key,
     774        ),
     775    }
     776
     777    EXPRESSION_PARSERS = {
     778        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     779        exp.Column: lambda self: self._parse_column(),
     780        exp.Condition: lambda self: self._parse_assignment(),
     781        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
     782        exp.Expression: lambda self: self._parse_expression(),
     783        exp.From: lambda self: self._parse_from(joins=True),
     784        exp.Group: lambda self: self._parse_group(),
     785        exp.Having: lambda self: self._parse_having(),
     786        exp.Hint: lambda self: self._parse_hint_body(),
     787        exp.Identifier: lambda self: self._parse_id_var(),
     788        exp.Join: lambda self: self._parse_join(),
     789        exp.Lambda: lambda self: self._parse_lambda(),
     790        exp.Lateral: lambda self: self._parse_lateral(),
     791        exp.Limit: lambda self: self._parse_limit(),
     792        exp.Offset: lambda self: self._parse_offset(),
     793        exp.Order: lambda self: self._parse_order(),
     794        exp.Ordered: lambda self: self._parse_ordered(),
     795        exp.Properties: lambda self: self._parse_properties(),
     796        exp.Qualify: lambda self: self._parse_qualify(),
     797        exp.Returning: lambda self: self._parse_returning(),
     798        exp.Select: lambda self: self._parse_select(),
     799        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     800        exp.Table: lambda self: self._parse_table_parts(),
     801        exp.TableAlias: lambda self: self._parse_table_alias(),
     802        exp.Tuple: lambda self: self._parse_value(),
     803        exp.Whens: lambda self: self._parse_when_matched(),
     804        exp.Where: lambda self: self._parse_where(),
     805        exp.Window: lambda self: self._parse_named_window(),
     806        exp.With: lambda self: self._parse_with(),
     807        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     808    }
     809
     810    STATEMENT_PARSERS = {
     811        TokenType.ALTER: lambda self: self._parse_alter(),
     812        TokenType.ANALYZE: lambda self: self._parse_analyze(),
     813        TokenType.BEGIN: lambda self: self._parse_transaction(),
     814        TokenType.CACHE: lambda self: self._parse_cache(),
     815        TokenType.COMMENT: lambda self: self._parse_comment(),
     816        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     817        TokenType.COPY: lambda self: self._parse_copy(),
     818        TokenType.CREATE: lambda self: self._parse_create(),
     819        TokenType.DELETE: lambda self: self._parse_delete(),
     820        TokenType.DESC: lambda self: self._parse_describe(),
     821        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     822        TokenType.DROP: lambda self: self._parse_drop(),
     823        TokenType.GRANT: lambda self: self._parse_grant(),
     824        TokenType.INSERT: lambda self: self._parse_insert(),
     825        TokenType.KILL: lambda self: self._parse_kill(),
     826        TokenType.LOAD: lambda self: self._parse_load(),
     827        TokenType.MERGE: lambda self: self._parse_merge(),
     828        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     829        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     830        TokenType.REFRESH: lambda self: self._parse_refresh(),
     831        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     832        TokenType.SET: lambda self: self._parse_set(),
     833        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     834        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     835        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
     836        TokenType.UPDATE: lambda self: self._parse_update(),
     837        TokenType.USE: lambda self: self._parse_use(),
     838        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
     839    }
     840
     841    UNARY_PARSERS = {
     842        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     843        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     844        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     845        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     846        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     847        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     848    }
     849
     850    STRING_PARSERS = {
     851        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     852            exp.RawString, this=token.text
     853        ),
     854        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     855            exp.National, this=token.text
     856        ),
     857        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     858        TokenType.STRING: lambda self, token: self.expression(
     859            exp.Literal, this=token.text, is_string=True
     860        ),
     861        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     862            exp.UnicodeString,
     863            this=token.text,
     864            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     865        ),
     866    }
     867
     868    NUMERIC_PARSERS = {
     869        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     870        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     871        TokenType.HEX_STRING: lambda self, token: self.expression(
     872            exp.HexString,
     873            this=token.text,
     874            is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
     875        ),
     876        TokenType.NUMBER: lambda self, token: self.expression(
     877            exp.Literal, this=token.text, is_string=False
     878        ),
     879    }
     880
     881    PRIMARY_PARSERS = {
     882        **STRING_PARSERS,
     883        **NUMERIC_PARSERS,
     884        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     885        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     886        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     887        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     888        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     889        TokenType.STAR: lambda self, _: self._parse_star_ops(),
     890    }
     891
     892    PLACEHOLDER_PARSERS = {
     893        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     894        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     895        TokenType.COLON: lambda self: (
     896            self.expression(exp.Placeholder, this=self._prev.text)
     897            if self._match_set(self.ID_VAR_TOKENS)
     898            else None
     899        ),
     900    }
     901
     902    RANGE_PARSERS = {
     903        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
     904        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     905        TokenType.GLOB: binary_range_parser(exp.Glob),
     906        TokenType.ILIKE: binary_range_parser(exp.ILike),
     907        TokenType.IN: lambda self, this: self._parse_in(this),
     908        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     909        TokenType.IS: lambda self, this: self._parse_is(this),
     910        TokenType.LIKE: binary_range_parser(exp.Like),
     911        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
     912        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     913        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     914        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     915        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     916    }
     917
     918    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     919        "ALLOWED_VALUES": lambda self: self.expression(
     920            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     921        ),
     922        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     923        "AUTO": lambda self: self._parse_auto_property(),
     924        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     925        "BACKUP": lambda self: self.expression(
     926            exp.BackupProperty, this=self._parse_var(any_token=True)
     927        ),
     928        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     929        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     930        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     931        "CHECKSUM": lambda self: self._parse_checksum(),
     932        "CLUSTER BY": lambda self: self._parse_cluster(),
     933        "CLUSTERED": lambda self: self._parse_clustered_by(),
     934        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     935            exp.CollateProperty, **kwargs
     936        ),
     937        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     938        "CONTAINS": lambda self: self._parse_contains_property(),
     939        "COPY": lambda self: self._parse_copy_property(),
     940        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     941        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     942        "DEFINER": lambda self: self._parse_definer(),
     943        "DETERMINISTIC": lambda self: self.expression(
     944            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     945        ),
     946        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
     947        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
     948        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
     949        "DISTKEY": lambda self: self._parse_distkey(),
     950        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     951        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
     952        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     953        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     954        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     955        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     956        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     957        "FREESPACE": lambda self: self._parse_freespace(),
     958        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     959        "HEAP": lambda self: self.expression(exp.HeapProperty),
     960        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     961        "IMMUTABLE": lambda self: self.expression(
     962            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     963        ),
     964        "INHERITS": lambda self: self.expression(
     965            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     966        ),
     967        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     968        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     969        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     970        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     971        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     972        "LIKE": lambda self: self._parse_create_like(),
     973        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     974        "LOCK": lambda self: self._parse_locking(),
     975        "LOCKING": lambda self: self._parse_locking(),
     976        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     977        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     978        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     979        "MODIFIES": lambda self: self._parse_modifies_property(),
     980        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     981        "NO": lambda self: self._parse_no_property(),
     982        "ON": lambda self: self._parse_on_property(),
     983        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     984        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     985        "PARTITION": lambda self: self._parse_partitioned_of(),
     986        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     987        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     988        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     989        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     990        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     991        "READS": lambda self: self._parse_reads_property(),
     992        "REMOTE": lambda self: self._parse_remote_with_connection(),
     993        "RETURNS": lambda self: self._parse_returns(),
     994        "STRICT": lambda self: self.expression(exp.StrictProperty),
     995        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
     996        "ROW": lambda self: self._parse_row(),
     997        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     998        "SAMPLE": lambda self: self.expression(
     999            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
    1000        ),
    1001        "SECURE": lambda self: self.expression(exp.SecureProperty),
    1002        "SECURITY": lambda self: self._parse_security(),
    1003        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
    1004        "SETTINGS": lambda self: self._parse_settings_property(),
    1005        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
    1006        "SORTKEY": lambda self: self._parse_sortkey(),
    1007        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
    1008        "STABLE": lambda self: self.expression(
    1009            exp.StabilityProperty, this=exp.Literal.string("STABLE")
    1010        ),
    1011        "STORED": lambda self: self._parse_stored(),
    1012        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
    1013        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
    1014        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
    1015        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
    1016        "TO": lambda self: self._parse_to_table(),
    1017        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
    1018        "TRANSFORM": lambda self: self.expression(
    1019            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
    1020        ),
    1021        "TTL": lambda self: self._parse_ttl(),
    1022        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
    1023        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
    1024        "VOLATILE": lambda self: self._parse_volatile_property(),
    1025        "WITH": lambda self: self._parse_with_property(),
    1026    }
    1027
    1028    CONSTRAINT_PARSERS = {
    1029        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
    1030        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
    1031        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
    1032        "CHARACTER SET": lambda self: self.expression(
    1033            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
    1034        ),
    1035        "CHECK": lambda self: self.expression(
    1036            exp.CheckColumnConstraint,
    1037            this=self._parse_wrapped(self._parse_assignment),
    1038            enforced=self._match_text_seq("ENFORCED"),
    1039        ),
    1040        "COLLATE": lambda self: self.expression(
    1041            exp.CollateColumnConstraint,
    1042            this=self._parse_identifier() or self._parse_column(),
    1043        ),
    1044        "COMMENT": lambda self: self.expression(
    1045            exp.CommentColumnConstraint, this=self._parse_string()
    1046        ),
    1047        "COMPRESS": lambda self: self._parse_compress(),
    1048        "CLUSTERED": lambda self: self.expression(
    1049            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1050        ),
    1051        "NONCLUSTERED": lambda self: self.expression(
    1052            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1053        ),
    1054        "DEFAULT": lambda self: self.expression(
    1055            exp.DefaultColumnConstraint, this=self._parse_bitwise()
    1056        ),
    1057        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
    1058        "EPHEMERAL": lambda self: self.expression(
    1059            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
    1060        ),
    1061        "EXCLUDE": lambda self: self.expression(
    1062            exp.ExcludeColumnConstraint, this=self._parse_index_params()
    1063        ),
    1064        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
    1065        "FORMAT": lambda self: self.expression(
    1066            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
    1067        ),
    1068        "GENERATED": lambda self: self._parse_generated_as_identity(),
    1069        "IDENTITY": lambda self: self._parse_auto_increment(),
    1070        "INLINE": lambda self: self._parse_inline(),
    1071        "LIKE": lambda self: self._parse_create_like(),
    1072        "NOT": lambda self: self._parse_not_constraint(),
    1073        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
    1074        "ON": lambda self: (
    1075            self._match(TokenType.UPDATE)
    1076            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
    1077        )
    1078        or self.expression(exp.OnProperty, this=self._parse_id_var()),
    1079        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
    1080        "PERIOD": lambda self: self._parse_period_for_system_time(),
    1081        "PRIMARY KEY": lambda self: self._parse_primary_key(),
    1082        "REFERENCES": lambda self: self._parse_references(match=False),
    1083        "TITLE": lambda self: self.expression(
    1084            exp.TitleColumnConstraint, this=self._parse_var_or_string()
    1085        ),
    1086        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
    1087        "UNIQUE": lambda self: self._parse_unique(),
    1088        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
    1089        "WATERMARK": lambda self: self.expression(
    1090            exp.WatermarkColumnConstraint,
    1091            this=self._match(TokenType.FOR) and self._parse_column(),
    1092            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
    1093        ),
    1094        "WITH": lambda self: self.expression(
    1095            exp.Properties, expressions=self._parse_wrapped_properties()
    1096        ),
    1097    }
    1098
    1099    ALTER_PARSERS = {
    1100        "ADD": lambda self: self._parse_alter_table_add(),
    1101        "AS": lambda self: self._parse_select(),
    1102        "ALTER": lambda self: self._parse_alter_table_alter(),
    1103        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
    1104        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
    1105        "DROP": lambda self: self._parse_alter_table_drop(),
    1106        "RENAME": lambda self: self._parse_alter_table_rename(),
    1107        "SET": lambda self: self._parse_alter_table_set(),
    1108        "SWAP": lambda self: self.expression(
    1109            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
    1110        ),
    1111    }
    1112
    1113    ALTER_ALTER_PARSERS = {
    1114        "DISTKEY": lambda self: self._parse_alter_diststyle(),
    1115        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
    1116        "SORTKEY": lambda self: self._parse_alter_sortkey(),
    1117        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
    1118    }
    1119
    1120    SCHEMA_UNNAMED_CONSTRAINTS = {
    1121        "CHECK",
    1122        "EXCLUDE",
    1123        "FOREIGN KEY",
    1124        "LIKE",
    1125        "PERIOD",
    1126        "PRIMARY KEY",
    1127        "UNIQUE",
    1128        "WATERMARK",
    1129    }
    1130
    1131    NO_PAREN_FUNCTION_PARSERS = {
    1132        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
    1133        "CASE": lambda self: self._parse_case(),
    1134        "CONNECT_BY_ROOT": lambda self: self.expression(
    1135            exp.ConnectByRoot, this=self._parse_column()
    1136        ),
    1137        "IF": lambda self: self._parse_if(),
    1138    }
    1139
    1140    INVALID_FUNC_NAME_TOKENS = {
    1141        TokenType.IDENTIFIER,
    1142        TokenType.STRING,
    1143    }
    1144
    1145    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1146
    1147    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1148
    1149    FUNCTION_PARSERS = {
    1150        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1151        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
    1152        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1153        "DECODE": lambda self: self._parse_decode(),
    1154        "EXTRACT": lambda self: self._parse_extract(),
    1155        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
    1156        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1157        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1158        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1159        "JSON_TABLE": lambda self: self._parse_json_table(),
    1160        "MATCH": lambda self: self._parse_match_against(),
    1161        "NORMALIZE": lambda self: self._parse_normalize(),
    1162        "OPENJSON": lambda self: self._parse_open_json(),
    1163        "OVERLAY": lambda self: self._parse_overlay(),
    1164        "POSITION": lambda self: self._parse_position(),
    1165        "PREDICT": lambda self: self._parse_predict(),
    1166        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1167        "STRING_AGG": lambda self: self._parse_string_agg(),
    1168        "SUBSTRING": lambda self: self._parse_substring(),
    1169        "TRIM": lambda self: self._parse_trim(),
    1170        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1171        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1172        "XMLELEMENT": lambda self: self.expression(
    1173            exp.XMLElement,
    1174            this=self._match_text_seq("NAME") and self._parse_id_var(),
    1175            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
    1176        ),
    1177        "XMLTABLE": lambda self: self._parse_xml_table(),
    1178    }
    1179
    1180    QUERY_MODIFIER_PARSERS = {
    1181        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1182        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1183        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1184        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1185        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1186        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1187        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1188        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1189        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1190        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1191        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1192        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1193        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1194        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1195        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1196        TokenType.CLUSTER_BY: lambda self: (
    1197            "cluster",
    1198            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1199        ),
    1200        TokenType.DISTRIBUTE_BY: lambda self: (
    1201            "distribute",
    1202            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1203        ),
    1204        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1205        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1206        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1207    }
    1208
    1209    SET_PARSERS = {
    1210        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1211        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1212        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1213        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1214    }
    1215
    1216    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1217
    1218    TYPE_LITERAL_PARSERS = {
    1219        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1220    }
    1221
    1222    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1223
    1224    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1225
    1226    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1227
    1228    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1229    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1230        "ISOLATION": (
    1231            ("LEVEL", "REPEATABLE", "READ"),
    1232            ("LEVEL", "READ", "COMMITTED"),
    1233            ("LEVEL", "READ", "UNCOMITTED"),
    1234            ("LEVEL", "SERIALIZABLE"),
    1235        ),
    1236        "READ": ("WRITE", "ONLY"),
    1237    }
    1238
    1239    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1240        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1241    )
    1242    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1243
    1244    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1245        "SCALE": ("EXTEND", "NOEXTEND"),
    1246        "SHARD": ("EXTEND", "NOEXTEND"),
    1247        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1248        **dict.fromkeys(
    1249            (
    1250                "SESSION",
    1251                "GLOBAL",
    1252                "KEEP",
    1253                "NOKEEP",
    1254                "ORDER",
    1255                "NOORDER",
    1256                "NOCACHE",
    1257                "CYCLE",
    1258                "NOCYCLE",
    1259                "NOMINVALUE",
    1260                "NOMAXVALUE",
    1261                "NOSCALE",
    1262                "NOSHARD",
    1263            ),
    1264            tuple(),
    1265        ),
    1266    }
    1267
    1268    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1269
    1270    USABLES: OPTIONS_TYPE = dict.fromkeys(
    1271        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
    1272    )
    1273
    1274    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1275
    1276    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
    1277        "TYPE": ("EVOLUTION",),
    1278        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
    1279    }
    1280
    1281    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
    1282
    1283    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
    1284
    1285    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
    1286        "NOT": ("ENFORCED",),
    1287        "MATCH": (
    1288            "FULL",
    1289            "PARTIAL",
    1290            "SIMPLE",
    1291        ),
    1292        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
    1293        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
    1294    }
    1295
    1296    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1297
    1298    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1299    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
    1300    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1301
    1302    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1303
    1304    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1305
    1306    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1307
    1308    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1309
    1310    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1311    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1312    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1313
    1314    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1315
    1316    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1317
    1318    ADD_CONSTRAINT_TOKENS = {
    1319        TokenType.CONSTRAINT,
    1320        TokenType.FOREIGN_KEY,
    1321        TokenType.INDEX,
    1322        TokenType.KEY,
    1323        TokenType.PRIMARY_KEY,
    1324        TokenType.UNIQUE,
    1325    }
    1326
    1327    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1328
    1329    NULL_TOKENS = {TokenType.NULL}
    1330
    1331    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
    1332
    1333    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1334
    1335    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1336
    1337    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
    1338
    1339    ODBC_DATETIME_LITERALS = {
    1340        "d": exp.Date,
    1341        "t": exp.Time,
    1342        "ts": exp.Timestamp,
    1343    }
    1344
    1345    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
    1346
    1347    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
    1348
    1349    # The style options for the DESCRIBE statement
    1350    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
    1351
    1352    # The style options for the ANALYZE statement
    1353    ANALYZE_STYLES = {
    1354        "BUFFER_USAGE_LIMIT",
    1355        "FULL",
    1356        "LOCAL",
    1357        "NO_WRITE_TO_BINLOG",
    1358        "SAMPLE",
    1359        "SKIP_LOCKED",
    1360        "VERBOSE",
    1361    }
    1362
    1363    ANALYZE_EXPRESSION_PARSERS = {
    1364        "ALL": lambda self: self._parse_analyze_columns(),
    1365        "COMPUTE": lambda self: self._parse_analyze_statistics(),
    1366        "DELETE": lambda self: self._parse_analyze_delete(),
    1367        "DROP": lambda self: self._parse_analyze_histogram(),
    1368        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
    1369        "LIST": lambda self: self._parse_analyze_list(),
    1370        "PREDICATE": lambda self: self._parse_analyze_columns(),
    1371        "UPDATE": lambda self: self._parse_analyze_histogram(),
    1372        "VALIDATE": lambda self: self._parse_analyze_validate(),
    1373    }
    1374
    1375    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
    1376
    1377    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
    1378
    1379    OPERATION_MODIFIERS: t.Set[str] = set()
    1380
    1381    RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
    1382
    1383    STRICT_CAST = True
    1384
    1385    PREFIXED_PIVOT_COLUMNS = False
    1386    IDENTIFY_PIVOT_STRINGS = False
    1387
    1388    LOG_DEFAULTS_TO_LN = False
    1389
    1390    # Whether ADD is present for each column added by ALTER TABLE
    1391    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1392
    1393    # Whether the table sample clause expects CSV syntax
    1394    TABLESAMPLE_CSV = False
    1395
    1396    # The default method used for table sampling
    1397    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1398
    1399    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1400    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1401
    1402    # Whether the TRIM function expects the characters to trim as its first argument
    1403    TRIM_PATTERN_FIRST = False
    1404
    1405    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1406    STRING_ALIASES = False
    1407
    1408    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1409    MODIFIERS_ATTACHED_TO_SET_OP = True
    1410    SET_OP_MODIFIERS = {"order", "limit", "offset"}
    1411
    1412    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1413    NO_PAREN_IF_COMMANDS = True
    1414
    1415    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1416    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1417
    1418    # Whether the `:` operator is used to extract a value from a VARIANT column
    1419    COLON_IS_VARIANT_EXTRACT = False
    1420
    1421    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1422    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1423    VALUES_FOLLOWED_BY_PAREN = True
    1424
    1425    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1426    SUPPORTS_IMPLICIT_UNNEST = False
    1427
    1428    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1429    INTERVAL_SPANS = True
    1430
    1431    # Whether a PARTITION clause can follow a table reference
    1432    SUPPORTS_PARTITION_SELECTION = False
    1433
    1434    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
    1435    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
    1436
    1437    # Whether the 'AS' keyword is optional in the CTE definition syntax
    1438    OPTIONAL_ALIAS_TOKEN_CTE = True
    1439
    1440    __slots__ = (
    1441        "error_level",
    1442        "error_message_context",
    1443        "max_errors",
    1444        "dialect",
    1445        "sql",
    1446        "errors",
    1447        "_tokens",
    1448        "_index",
    1449        "_curr",
    1450        "_next",
    1451        "_prev",
    1452        "_prev_comments",
    1453    )
    1454
    1455    # Autofilled
    1456    SHOW_TRIE: t.Dict = {}
    1457    SET_TRIE: t.Dict = {}
    1458
    1459    def __init__(
    1460        self,
    1461        error_level: t.Optional[ErrorLevel] = None,
    1462        error_message_context: int = 100,
    1463        max_errors: int = 3,
    1464        dialect: DialectType = None,
    1465    ):
    1466        from sqlglot.dialects import Dialect
    1467
    1468        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1469        self.error_message_context = error_message_context
    1470        self.max_errors = max_errors
    1471        self.dialect = Dialect.get_or_raise(dialect)
    1472        self.reset()
    1473
    1474    def reset(self):
    1475        self.sql = ""
    1476        self.errors = []
    1477        self._tokens = []
    1478        self._index = 0
    1479        self._curr = None
    1480        self._next = None
    1481        self._prev = None
    1482        self._prev_comments = None
    1483
    1484    def parse(
    1485        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1486    ) -> t.List[t.Optional[exp.Expression]]:
    1487        """
    1488        Parses a list of tokens and returns a list of syntax trees, one tree
    1489        per parsed SQL statement.
    1490
    1491        Args:
    1492            raw_tokens: The list of tokens.
    1493            sql: The original SQL string, used to produce helpful debug messages.
    1494
    1495        Returns:
    1496            The list of the produced syntax trees.
    1497        """
    1498        return self._parse(
    1499            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1500        )
    1501
    1502    def parse_into(
    1503        self,
    1504        expression_types: exp.IntoType,
    1505        raw_tokens: t.List[Token],
    1506        sql: t.Optional[str] = None,
    1507    ) -> t.List[t.Optional[exp.Expression]]:
    1508        """
    1509        Parses a list of tokens into a given Expression type. If a collection of Expression
    1510        types is given instead, this method will try to parse the token list into each one
    1511        of them, stopping at the first for which the parsing succeeds.
    1512
    1513        Args:
    1514            expression_types: The expression type(s) to try and parse the token list into.
    1515            raw_tokens: The list of tokens.
    1516            sql: The original SQL string, used to produce helpful debug messages.
    1517
    1518        Returns:
    1519            The target Expression.
    1520        """
    1521        errors = []
    1522        for expression_type in ensure_list(expression_types):
    1523            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1524            if not parser:
    1525                raise TypeError(f"No parser registered for {expression_type}")
    1526
    1527            try:
    1528                return self._parse(parser, raw_tokens, sql)
    1529            except ParseError as e:
    1530                e.errors[0]["into_expression"] = expression_type
    1531                errors.append(e)
    1532
    1533        raise ParseError(
    1534            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1535            errors=merge_errors(errors),
    1536        ) from errors[-1]
    1537
    1538    def _parse(
    1539        self,
    1540        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1541        raw_tokens: t.List[Token],
    1542        sql: t.Optional[str] = None,
    1543    ) -> t.List[t.Optional[exp.Expression]]:
    1544        self.reset()
    1545        self.sql = sql or ""
    1546
    1547        total = len(raw_tokens)
    1548        chunks: t.List[t.List[Token]] = [[]]
    1549
    1550        for i, token in enumerate(raw_tokens):
    1551            if token.token_type == TokenType.SEMICOLON:
    1552                if token.comments:
    1553                    chunks.append([token])
    1554
    1555                if i < total - 1:
    1556                    chunks.append([])
    1557            else:
    1558                chunks[-1].append(token)
    1559
    1560        expressions = []
    1561
    1562        for tokens in chunks:
    1563            self._index = -1
    1564            self._tokens = tokens
    1565            self._advance()
    1566
    1567            expressions.append(parse_method(self))
    1568
    1569            if self._index < len(self._tokens):
    1570                self.raise_error("Invalid expression / Unexpected token")
    1571
    1572            self.check_errors()
    1573
    1574        return expressions
    1575
    1576    def check_errors(self) -> None:
    1577        """Logs or raises any found errors, depending on the chosen error level setting."""
    1578        if self.error_level == ErrorLevel.WARN:
    1579            for error in self.errors:
    1580                logger.error(str(error))
    1581        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1582            raise ParseError(
    1583                concat_messages(self.errors, self.max_errors),
    1584                errors=merge_errors(self.errors),
    1585            )
    1586
    1587    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1588        """
    1589        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1590        error level setting.
    1591        """
    1592        token = token or self._curr or self._prev or Token.string("")
    1593        start = token.start
    1594        end = token.end + 1
    1595        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1596        highlight = self.sql[start:end]
    1597        end_context = self.sql[end : end + self.error_message_context]
    1598
    1599        error = ParseError.new(
    1600            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1601            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1602            description=message,
    1603            line=token.line,
    1604            col=token.col,
    1605            start_context=start_context,
    1606            highlight=highlight,
    1607            end_context=end_context,
    1608        )
    1609
    1610        if self.error_level == ErrorLevel.IMMEDIATE:
    1611            raise error
    1612
    1613        self.errors.append(error)
    1614
    1615    def expression(
    1616        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1617    ) -> E:
    1618        """
    1619        Creates a new, validated Expression.
    1620
    1621        Args:
    1622            exp_class: The expression class to instantiate.
    1623            comments: An optional list of comments to attach to the expression.
    1624            kwargs: The arguments to set for the expression along with their respective values.
    1625
    1626        Returns:
    1627            The target expression.
    1628        """
    1629        instance = exp_class(**kwargs)
    1630        instance.add_comments(comments) if comments else self._add_comments(instance)
    1631        return self.validate_expression(instance)
    1632
    1633    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1634        if expression and self._prev_comments:
    1635            expression.add_comments(self._prev_comments)
    1636            self._prev_comments = None
    1637
    1638    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1639        """
    1640        Validates an Expression, making sure that all its mandatory arguments are set.
    1641
    1642        Args:
    1643            expression: The expression to validate.
    1644            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1645
    1646        Returns:
    1647            The validated expression.
    1648        """
    1649        if self.error_level != ErrorLevel.IGNORE:
    1650            for error_message in expression.error_messages(args):
    1651                self.raise_error(error_message)
    1652
    1653        return expression
    1654
    1655    def _find_sql(self, start: Token, end: Token) -> str:
    1656        return self.sql[start.start : end.end + 1]
    1657
    1658    def _is_connected(self) -> bool:
    1659        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1660
    1661    def _advance(self, times: int = 1) -> None:
    1662        self._index += times
    1663        self._curr = seq_get(self._tokens, self._index)
    1664        self._next = seq_get(self._tokens, self._index + 1)
    1665
    1666        if self._index > 0:
    1667            self._prev = self._tokens[self._index - 1]
    1668            self._prev_comments = self._prev.comments
    1669        else:
    1670            self._prev = None
    1671            self._prev_comments = None
    1672
    1673    def _retreat(self, index: int) -> None:
    1674        if index != self._index:
    1675            self._advance(index - self._index)
    1676
    1677    def _warn_unsupported(self) -> None:
    1678        if len(self._tokens) <= 1:
    1679            return
    1680
    1681        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1682        # interested in emitting a warning for the one being currently processed.
    1683        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1684
    1685        logger.warning(
    1686            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1687        )
    1688
    1689    def _parse_command(self) -> exp.Command:
    1690        self._warn_unsupported()
    1691        return self.expression(
    1692            exp.Command,
    1693            comments=self._prev_comments,
    1694            this=self._prev.text.upper(),
    1695            expression=self._parse_string(),
    1696        )
    1697
    1698    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1699        """
    1700        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
    1701        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
    1702        solve this by setting & resetting the parser state accordingly
    1703        """
    1704        index = self._index
    1705        error_level = self.error_level
    1706
    1707        self.error_level = ErrorLevel.IMMEDIATE
    1708        try:
    1709            this = parse_method()
    1710        except ParseError:
    1711            this = None
    1712        finally:
    1713            if not this or retreat:
    1714                self._retreat(index)
    1715            self.error_level = error_level
    1716
    1717        return this
    1718
    1719    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1720        start = self._prev
    1721        exists = self._parse_exists() if allow_exists else None
    1722
    1723        self._match(TokenType.ON)
    1724
    1725        materialized = self._match_text_seq("MATERIALIZED")
    1726        kind = self._match_set(self.CREATABLES) and self._prev
    1727        if not kind:
    1728            return self._parse_as_command(start)
    1729
    1730        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1731            this = self._parse_user_defined_function(kind=kind.token_type)
    1732        elif kind.token_type == TokenType.TABLE:
    1733            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1734        elif kind.token_type == TokenType.COLUMN:
    1735            this = self._parse_column()
    1736        else:
    1737            this = self._parse_id_var()
    1738
    1739        self._match(TokenType.IS)
    1740
    1741        return self.expression(
    1742            exp.Comment,
    1743            this=this,
    1744            kind=kind.text,
    1745            expression=self._parse_string(),
    1746            exists=exists,
    1747            materialized=materialized,
    1748        )
    1749
    1750    def _parse_to_table(
    1751        self,
    1752    ) -> exp.ToTableProperty:
    1753        table = self._parse_table_parts(schema=True)
    1754        return self.expression(exp.ToTableProperty, this=table)
    1755
    1756    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1757    def _parse_ttl(self) -> exp.Expression:
    1758        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1759            this = self._parse_bitwise()
    1760
    1761            if self._match_text_seq("DELETE"):
    1762                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1763            if self._match_text_seq("RECOMPRESS"):
    1764                return self.expression(
    1765                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1766                )
    1767            if self._match_text_seq("TO", "DISK"):
    1768                return self.expression(
    1769                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1770                )
    1771            if self._match_text_seq("TO", "VOLUME"):
    1772                return self.expression(
    1773                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1774                )
    1775
    1776            return this
    1777
    1778        expressions = self._parse_csv(_parse_ttl_action)
    1779        where = self._parse_where()
    1780        group = self._parse_group()
    1781
    1782        aggregates = None
    1783        if group and self._match(TokenType.SET):
    1784            aggregates = self._parse_csv(self._parse_set_item)
    1785
    1786        return self.expression(
    1787            exp.MergeTreeTTL,
    1788            expressions=expressions,
    1789            where=where,
    1790            group=group,
    1791            aggregates=aggregates,
    1792        )
    1793
    1794    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1795        if self._curr is None:
    1796            return None
    1797
    1798        if self._match_set(self.STATEMENT_PARSERS):
    1799            comments = self._prev_comments
    1800            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
    1801            stmt.add_comments(comments, prepend=True)
    1802            return stmt
    1803
    1804        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1805            return self._parse_command()
    1806
    1807        expression = self._parse_expression()
    1808        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1809        return self._parse_query_modifiers(expression)
    1810
    1811    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1812        start = self._prev
    1813        temporary = self._match(TokenType.TEMPORARY)
    1814        materialized = self._match_text_seq("MATERIALIZED")
    1815
    1816        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    1817        if not kind:
    1818            return self._parse_as_command(start)
    1819
    1820        concurrently = self._match_text_seq("CONCURRENTLY")
    1821        if_exists = exists or self._parse_exists()
    1822
    1823        if kind == "COLUMN":
    1824            this = self._parse_column()
    1825        else:
    1826            this = self._parse_table_parts(
    1827                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1828            )
    1829
    1830        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1831
    1832        if self._match(TokenType.L_PAREN, advance=False):
    1833            expressions = self._parse_wrapped_csv(self._parse_types)
    1834        else:
    1835            expressions = None
    1836
    1837        return self.expression(
    1838            exp.Drop,
    1839            exists=if_exists,
    1840            this=this,
    1841            expressions=expressions,
    1842            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
    1843            temporary=temporary,
    1844            materialized=materialized,
    1845            cascade=self._match_text_seq("CASCADE"),
    1846            constraints=self._match_text_seq("CONSTRAINTS"),
    1847            purge=self._match_text_seq("PURGE"),
    1848            cluster=cluster,
    1849            concurrently=concurrently,
    1850        )
    1851
    1852    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1853        return (
    1854            self._match_text_seq("IF")
    1855            and (not not_ or self._match(TokenType.NOT))
    1856            and self._match(TokenType.EXISTS)
    1857        )
    1858
    1859    def _parse_create(self) -> exp.Create | exp.Command:
    1860        # Note: this can't be None because we've matched a statement parser
    1861        start = self._prev
    1862
    1863        replace = (
    1864            start.token_type == TokenType.REPLACE
    1865            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1866            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1867        )
    1868        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
    1869
    1870        unique = self._match(TokenType.UNIQUE)
    1871
    1872        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
    1873            clustered = True
    1874        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
    1875            "COLUMNSTORE"
    1876        ):
    1877            clustered = False
    1878        else:
    1879            clustered = None
    1880
    1881        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1882            self._advance()
    1883
    1884        properties = None
    1885        create_token = self._match_set(self.CREATABLES) and self._prev
    1886
    1887        if not create_token:
    1888            # exp.Properties.Location.POST_CREATE
    1889            properties = self._parse_properties()
    1890            create_token = self._match_set(self.CREATABLES) and self._prev
    1891
    1892            if not properties or not create_token:
    1893                return self._parse_as_command(start)
    1894
    1895        concurrently = self._match_text_seq("CONCURRENTLY")
    1896        exists = self._parse_exists(not_=True)
    1897        this = None
    1898        expression: t.Optional[exp.Expression] = None
    1899        indexes = None
    1900        no_schema_binding = None
    1901        begin = None
    1902        end = None
    1903        clone = None
    1904
    1905        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1906            nonlocal properties
    1907            if properties and temp_props:
    1908                properties.expressions.extend(temp_props.expressions)
    1909            elif temp_props:
    1910                properties = temp_props
    1911
    1912        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1913            this = self._parse_user_defined_function(kind=create_token.token_type)
    1914
    1915            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1916            extend_props(self._parse_properties())
    1917
    1918            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1919            extend_props(self._parse_properties())
    1920
    1921            if not expression:
    1922                if self._match(TokenType.COMMAND):
    1923                    expression = self._parse_as_command(self._prev)
    1924                else:
    1925                    begin = self._match(TokenType.BEGIN)
    1926                    return_ = self._match_text_seq("RETURN")
    1927
    1928                    if self._match(TokenType.STRING, advance=False):
    1929                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1930                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1931                        expression = self._parse_string()
    1932                        extend_props(self._parse_properties())
    1933                    else:
    1934                        expression = self._parse_user_defined_function_expression()
    1935
    1936                    end = self._match_text_seq("END")
    1937
    1938                    if return_:
    1939                        expression = self.expression(exp.Return, this=expression)
    1940        elif create_token.token_type == TokenType.INDEX:
    1941            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1942            if not self._match(TokenType.ON):
    1943                index = self._parse_id_var()
    1944                anonymous = False
    1945            else:
    1946                index = None
    1947                anonymous = True
    1948
    1949            this = self._parse_index(index=index, anonymous=anonymous)
    1950        elif create_token.token_type in self.DB_CREATABLES:
    1951            table_parts = self._parse_table_parts(
    1952                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1953            )
    1954
    1955            # exp.Properties.Location.POST_NAME
    1956            self._match(TokenType.COMMA)
    1957            extend_props(self._parse_properties(before=True))
    1958
    1959            this = self._parse_schema(this=table_parts)
    1960
    1961            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1962            extend_props(self._parse_properties())
    1963
    1964            self._match(TokenType.ALIAS)
    1965            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1966                # exp.Properties.Location.POST_ALIAS
    1967                extend_props(self._parse_properties())
    1968
    1969            if create_token.token_type == TokenType.SEQUENCE:
    1970                expression = self._parse_types()
    1971                extend_props(self._parse_properties())
    1972            else:
    1973                expression = self._parse_ddl_select()
    1974
    1975            if create_token.token_type == TokenType.TABLE:
    1976                # exp.Properties.Location.POST_EXPRESSION
    1977                extend_props(self._parse_properties())
    1978
    1979                indexes = []
    1980                while True:
    1981                    index = self._parse_index()
    1982
    1983                    # exp.Properties.Location.POST_INDEX
    1984                    extend_props(self._parse_properties())
    1985                    if not index:
    1986                        break
    1987                    else:
    1988                        self._match(TokenType.COMMA)
    1989                        indexes.append(index)
    1990            elif create_token.token_type == TokenType.VIEW:
    1991                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1992                    no_schema_binding = True
    1993            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
    1994                extend_props(self._parse_properties())
    1995
    1996            shallow = self._match_text_seq("SHALLOW")
    1997
    1998            if self._match_texts(self.CLONE_KEYWORDS):
    1999                copy = self._prev.text.lower() == "copy"
    2000                clone = self.expression(
    2001                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    2002                )
    2003
    2004        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    2005            return self._parse_as_command(start)
    2006
    2007        create_kind_text = create_token.text.upper()
    2008        return self.expression(
    2009            exp.Create,
    2010            this=this,
    2011            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
    2012            replace=replace,
    2013            refresh=refresh,
    2014            unique=unique,
    2015            expression=expression,
    2016            exists=exists,
    2017            properties=properties,
    2018            indexes=indexes,
    2019            no_schema_binding=no_schema_binding,
    2020            begin=begin,
    2021            end=end,
    2022            clone=clone,
    2023            concurrently=concurrently,
    2024            clustered=clustered,
    2025        )
    2026
    2027    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    2028        seq = exp.SequenceProperties()
    2029
    2030        options = []
    2031        index = self._index
    2032
    2033        while self._curr:
    2034            self._match(TokenType.COMMA)
    2035            if self._match_text_seq("INCREMENT"):
    2036                self._match_text_seq("BY")
    2037                self._match_text_seq("=")
    2038                seq.set("increment", self._parse_term())
    2039            elif self._match_text_seq("MINVALUE"):
    2040                seq.set("minvalue", self._parse_term())
    2041            elif self._match_text_seq("MAXVALUE"):
    2042                seq.set("maxvalue", self._parse_term())
    2043            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    2044                self._match_text_seq("=")
    2045                seq.set("start", self._parse_term())
    2046            elif self._match_text_seq("CACHE"):
    2047                # T-SQL allows empty CACHE which is initialized dynamically
    2048                seq.set("cache", self._parse_number() or True)
    2049            elif self._match_text_seq("OWNED", "BY"):
    2050                # "OWNED BY NONE" is the default
    2051                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    2052            else:
    2053                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    2054                if opt:
    2055                    options.append(opt)
    2056                else:
    2057                    break
    2058
    2059        seq.set("options", options if options else None)
    2060        return None if self._index == index else seq
    2061
    2062    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    2063        # only used for teradata currently
    2064        self._match(TokenType.COMMA)
    2065
    2066        kwargs = {
    2067            "no": self._match_text_seq("NO"),
    2068            "dual": self._match_text_seq("DUAL"),
    2069            "before": self._match_text_seq("BEFORE"),
    2070            "default": self._match_text_seq("DEFAULT"),
    2071            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    2072            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    2073            "after": self._match_text_seq("AFTER"),
    2074            "minimum": self._match_texts(("MIN", "MINIMUM")),
    2075            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    2076        }
    2077
    2078        if self._match_texts(self.PROPERTY_PARSERS):
    2079            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    2080            try:
    2081                return parser(self, **{k: v for k, v in kwargs.items() if v})
    2082            except TypeError:
    2083                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    2084
    2085        return None
    2086
    2087    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    2088        return self._parse_wrapped_csv(self._parse_property)
    2089
    2090    def _parse_property(self) -> t.Optional[exp.Expression]:
    2091        if self._match_texts(self.PROPERTY_PARSERS):
    2092            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    2093
    2094        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    2095            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    2096
    2097        if self._match_text_seq("COMPOUND", "SORTKEY"):
    2098            return self._parse_sortkey(compound=True)
    2099
    2100        if self._match_text_seq("SQL", "SECURITY"):
    2101            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    2102
    2103        index = self._index
    2104        key = self._parse_column()
    2105
    2106        if not self._match(TokenType.EQ):
    2107            self._retreat(index)
    2108            return self._parse_sequence_properties()
    2109
    2110        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    2111        if isinstance(key, exp.Column):
    2112            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    2113
    2114        value = self._parse_bitwise() or self._parse_var(any_token=True)
    2115
    2116        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    2117        if isinstance(value, exp.Column):
    2118            value = exp.var(value.name)
    2119
    2120        return self.expression(exp.Property, this=key, value=value)
    2121
    2122    def _parse_stored(self) -> exp.FileFormatProperty:
    2123        self._match(TokenType.ALIAS)
    2124
    2125        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    2126        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    2127
    2128        return self.expression(
    2129            exp.FileFormatProperty,
    2130            this=(
    2131                self.expression(
    2132                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
    2133                )
    2134                if input_format or output_format
    2135                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    2136            ),
    2137        )
    2138
    2139    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    2140        field = self._parse_field()
    2141        if isinstance(field, exp.Identifier) and not field.quoted:
    2142            field = exp.var(field)
    2143
    2144        return field
    2145
    2146    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    2147        self._match(TokenType.EQ)
    2148        self._match(TokenType.ALIAS)
    2149
    2150        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    2151
    2152    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    2153        properties = []
    2154        while True:
    2155            if before:
    2156                prop = self._parse_property_before()
    2157            else:
    2158                prop = self._parse_property()
    2159            if not prop:
    2160                break
    2161            for p in ensure_list(prop):
    2162                properties.append(p)
    2163
    2164        if properties:
    2165            return self.expression(exp.Properties, expressions=properties)
    2166
    2167        return None
    2168
    2169    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    2170        return self.expression(
    2171            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    2172        )
    2173
    2174    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
    2175        if self._match_texts(("DEFINER", "INVOKER")):
    2176            security_specifier = self._prev.text.upper()
    2177            return self.expression(exp.SecurityProperty, this=security_specifier)
    2178        return None
    2179
    2180    def _parse_settings_property(self) -> exp.SettingsProperty:
    2181        return self.expression(
    2182            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
    2183        )
    2184
    2185    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    2186        if self._index >= 2:
    2187            pre_volatile_token = self._tokens[self._index - 2]
    2188        else:
    2189            pre_volatile_token = None
    2190
    2191        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    2192            return exp.VolatileProperty()
    2193
    2194        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    2195
    2196    def _parse_retention_period(self) -> exp.Var:
    2197        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    2198        number = self._parse_number()
    2199        number_str = f"{number} " if number else ""
    2200        unit = self._parse_var(any_token=True)
    2201        return exp.var(f"{number_str}{unit}")
    2202
    2203    def _parse_system_versioning_property(
    2204        self, with_: bool = False
    2205    ) -> exp.WithSystemVersioningProperty:
    2206        self._match(TokenType.EQ)
    2207        prop = self.expression(
    2208            exp.WithSystemVersioningProperty,
    2209            **{  # type: ignore
    2210                "on": True,
    2211                "with": with_,
    2212            },
    2213        )
    2214
    2215        if self._match_text_seq("OFF"):
    2216            prop.set("on", False)
    2217            return prop
    2218
    2219        self._match(TokenType.ON)
    2220        if self._match(TokenType.L_PAREN):
    2221            while self._curr and not self._match(TokenType.R_PAREN):
    2222                if self._match_text_seq("HISTORY_TABLE", "="):
    2223                    prop.set("this", self._parse_table_parts())
    2224                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    2225                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    2226                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    2227                    prop.set("retention_period", self._parse_retention_period())
    2228
    2229                self._match(TokenType.COMMA)
    2230
    2231        return prop
    2232
    2233    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    2234        self._match(TokenType.EQ)
    2235        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    2236        prop = self.expression(exp.DataDeletionProperty, on=on)
    2237
    2238        if self._match(TokenType.L_PAREN):
    2239            while self._curr and not self._match(TokenType.R_PAREN):
    2240                if self._match_text_seq("FILTER_COLUMN", "="):
    2241                    prop.set("filter_column", self._parse_column())
    2242                elif self._match_text_seq("RETENTION_PERIOD", "="):
    2243                    prop.set("retention_period", self._parse_retention_period())
    2244
    2245                self._match(TokenType.COMMA)
    2246
    2247        return prop
    2248
    2249    def _parse_distributed_property(self) -> exp.DistributedByProperty:
    2250        kind = "HASH"
    2251        expressions: t.Optional[t.List[exp.Expression]] = None
    2252        if self._match_text_seq("BY", "HASH"):
    2253            expressions = self._parse_wrapped_csv(self._parse_id_var)
    2254        elif self._match_text_seq("BY", "RANDOM"):
    2255            kind = "RANDOM"
    2256
    2257        # If the BUCKETS keyword is not present, the number of buckets is AUTO
    2258        buckets: t.Optional[exp.Expression] = None
    2259        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
    2260            buckets = self._parse_number()
    2261
    2262        return self.expression(
    2263            exp.DistributedByProperty,
    2264            expressions=expressions,
    2265            kind=kind,
    2266            buckets=buckets,
    2267            order=self._parse_order(),
    2268        )
    2269
    2270    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
    2271        self._match_text_seq("KEY")
    2272        expressions = self._parse_wrapped_id_vars()
    2273        return self.expression(expr_type, expressions=expressions)
    2274
    2275    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    2276        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    2277            prop = self._parse_system_versioning_property(with_=True)
    2278            self._match_r_paren()
    2279            return prop
    2280
    2281        if self._match(TokenType.L_PAREN, advance=False):
    2282            return self._parse_wrapped_properties()
    2283
    2284        if self._match_text_seq("JOURNAL"):
    2285            return self._parse_withjournaltable()
    2286
    2287        if self._match_texts(self.VIEW_ATTRIBUTES):
    2288            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    2289
    2290        if self._match_text_seq("DATA"):
    2291            return self._parse_withdata(no=False)
    2292        elif self._match_text_seq("NO", "DATA"):
    2293            return self._parse_withdata(no=True)
    2294
    2295        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    2296            return self._parse_serde_properties(with_=True)
    2297
    2298        if self._match(TokenType.SCHEMA):
    2299            return self.expression(
    2300                exp.WithSchemaBindingProperty,
    2301                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
    2302            )
    2303
    2304        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
    2305            return self.expression(
    2306                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
    2307            )
    2308
    2309        if not self._next:
    2310            return None
    2311
    2312        return self._parse_withisolatedloading()
    2313
    2314    def _parse_procedure_option(self) -> exp.Expression | None:
    2315        if self._match_text_seq("EXECUTE", "AS"):
    2316            return self.expression(
    2317                exp.ExecuteAsProperty,
    2318                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
    2319                or self._parse_string(),
    2320            )
    2321
    2322        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
    2323
    2324    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2325    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2326        self._match(TokenType.EQ)
    2327
    2328        user = self._parse_id_var()
    2329        self._match(TokenType.PARAMETER)
    2330        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2331
    2332        if not user or not host:
    2333            return None
    2334
    2335        return exp.DefinerProperty(this=f"{user}@{host}")
    2336
    2337    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2338        self._match(TokenType.TABLE)
    2339        self._match(TokenType.EQ)
    2340        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2341
    2342    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2343        return self.expression(exp.LogProperty, no=no)
    2344
    2345    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2346        return self.expression(exp.JournalProperty, **kwargs)
    2347
    2348    def _parse_checksum(self) -> exp.ChecksumProperty:
    2349        self._match(TokenType.EQ)
    2350
    2351        on = None
    2352        if self._match(TokenType.ON):
    2353            on = True
    2354        elif self._match_text_seq("OFF"):
    2355            on = False
    2356
    2357        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2358
    2359    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2360        return self.expression(
    2361            exp.Cluster,
    2362            expressions=(
    2363                self._parse_wrapped_csv(self._parse_ordered)
    2364                if wrapped
    2365                else self._parse_csv(self._parse_ordered)
    2366            ),
    2367        )
    2368
    2369    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2370        self._match_text_seq("BY")
    2371
    2372        self._match_l_paren()
    2373        expressions = self._parse_csv(self._parse_column)
    2374        self._match_r_paren()
    2375
    2376        if self._match_text_seq("SORTED", "BY"):
    2377            self._match_l_paren()
    2378            sorted_by = self._parse_csv(self._parse_ordered)
    2379            self._match_r_paren()
    2380        else:
    2381            sorted_by = None
    2382
    2383        self._match(TokenType.INTO)
    2384        buckets = self._parse_number()
    2385        self._match_text_seq("BUCKETS")
    2386
    2387        return self.expression(
    2388            exp.ClusteredByProperty,
    2389            expressions=expressions,
    2390            sorted_by=sorted_by,
    2391            buckets=buckets,
    2392        )
    2393
    2394    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2395        if not self._match_text_seq("GRANTS"):
    2396            self._retreat(self._index - 1)
    2397            return None
    2398
    2399        return self.expression(exp.CopyGrantsProperty)
    2400
    2401    def _parse_freespace(self) -> exp.FreespaceProperty:
    2402        self._match(TokenType.EQ)
    2403        return self.expression(
    2404            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2405        )
    2406
    2407    def _parse_mergeblockratio(
    2408        self, no: bool = False, default: bool = False
    2409    ) -> exp.MergeBlockRatioProperty:
    2410        if self._match(TokenType.EQ):
    2411            return self.expression(
    2412                exp.MergeBlockRatioProperty,
    2413                this=self._parse_number(),
    2414                percent=self._match(TokenType.PERCENT),
    2415            )
    2416
    2417        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2418
    2419    def _parse_datablocksize(
    2420        self,
    2421        default: t.Optional[bool] = None,
    2422        minimum: t.Optional[bool] = None,
    2423        maximum: t.Optional[bool] = None,
    2424    ) -> exp.DataBlocksizeProperty:
    2425        self._match(TokenType.EQ)
    2426        size = self._parse_number()
    2427
    2428        units = None
    2429        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2430            units = self._prev.text
    2431
    2432        return self.expression(
    2433            exp.DataBlocksizeProperty,
    2434            size=size,
    2435            units=units,
    2436            default=default,
    2437            minimum=minimum,
    2438            maximum=maximum,
    2439        )
    2440
    2441    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2442        self._match(TokenType.EQ)
    2443        always = self._match_text_seq("ALWAYS")
    2444        manual = self._match_text_seq("MANUAL")
    2445        never = self._match_text_seq("NEVER")
    2446        default = self._match_text_seq("DEFAULT")
    2447
    2448        autotemp = None
    2449        if self._match_text_seq("AUTOTEMP"):
    2450            autotemp = self._parse_schema()
    2451
    2452        return self.expression(
    2453            exp.BlockCompressionProperty,
    2454            always=always,
    2455            manual=manual,
    2456            never=never,
    2457            default=default,
    2458            autotemp=autotemp,
    2459        )
    2460
    2461    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2462        index = self._index
    2463        no = self._match_text_seq("NO")
    2464        concurrent = self._match_text_seq("CONCURRENT")
    2465
    2466        if not self._match_text_seq("ISOLATED", "LOADING"):
    2467            self._retreat(index)
    2468            return None
    2469
    2470        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2471        return self.expression(
    2472            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2473        )
    2474
    2475    def _parse_locking(self) -> exp.LockingProperty:
    2476        if self._match(TokenType.TABLE):
    2477            kind = "TABLE"
    2478        elif self._match(TokenType.VIEW):
    2479            kind = "VIEW"
    2480        elif self._match(TokenType.ROW):
    2481            kind = "ROW"
    2482        elif self._match_text_seq("DATABASE"):
    2483            kind = "DATABASE"
    2484        else:
    2485            kind = None
    2486
    2487        if kind in ("DATABASE", "TABLE", "VIEW"):
    2488            this = self._parse_table_parts()
    2489        else:
    2490            this = None
    2491
    2492        if self._match(TokenType.FOR):
    2493            for_or_in = "FOR"
    2494        elif self._match(TokenType.IN):
    2495            for_or_in = "IN"
    2496        else:
    2497            for_or_in = None
    2498
    2499        if self._match_text_seq("ACCESS"):
    2500            lock_type = "ACCESS"
    2501        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2502            lock_type = "EXCLUSIVE"
    2503        elif self._match_text_seq("SHARE"):
    2504            lock_type = "SHARE"
    2505        elif self._match_text_seq("READ"):
    2506            lock_type = "READ"
    2507        elif self._match_text_seq("WRITE"):
    2508            lock_type = "WRITE"
    2509        elif self._match_text_seq("CHECKSUM"):
    2510            lock_type = "CHECKSUM"
    2511        else:
    2512            lock_type = None
    2513
    2514        override = self._match_text_seq("OVERRIDE")
    2515
    2516        return self.expression(
    2517            exp.LockingProperty,
    2518            this=this,
    2519            kind=kind,
    2520            for_or_in=for_or_in,
    2521            lock_type=lock_type,
    2522            override=override,
    2523        )
    2524
    2525    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2526        if self._match(TokenType.PARTITION_BY):
    2527            return self._parse_csv(self._parse_assignment)
    2528        return []
    2529
    2530    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2531        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2532            if self._match_text_seq("MINVALUE"):
    2533                return exp.var("MINVALUE")
    2534            if self._match_text_seq("MAXVALUE"):
    2535                return exp.var("MAXVALUE")
    2536            return self._parse_bitwise()
    2537
    2538        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2539        expression = None
    2540        from_expressions = None
    2541        to_expressions = None
    2542
    2543        if self._match(TokenType.IN):
    2544            this = self._parse_wrapped_csv(self._parse_bitwise)
    2545        elif self._match(TokenType.FROM):
    2546            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2547            self._match_text_seq("TO")
    2548            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2549        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2550            this = self._parse_number()
    2551            self._match_text_seq(",", "REMAINDER")
    2552            expression = self._parse_number()
    2553            self._match_r_paren()
    2554        else:
    2555            self.raise_error("Failed to parse partition bound spec.")
    2556
    2557        return self.expression(
    2558            exp.PartitionBoundSpec,
    2559            this=this,
    2560            expression=expression,
    2561            from_expressions=from_expressions,
    2562            to_expressions=to_expressions,
    2563        )
    2564
    2565    # https://www.postgresql.org/docs/current/sql-createtable.html
    2566    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2567        if not self._match_text_seq("OF"):
    2568            self._retreat(self._index - 1)
    2569            return None
    2570
    2571        this = self._parse_table(schema=True)
    2572
    2573        if self._match(TokenType.DEFAULT):
    2574            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2575        elif self._match_text_seq("FOR", "VALUES"):
    2576            expression = self._parse_partition_bound_spec()
    2577        else:
    2578            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2579
    2580        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2581
    2582    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2583        self._match(TokenType.EQ)
    2584        return self.expression(
    2585            exp.PartitionedByProperty,
    2586            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2587        )
    2588
    2589    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2590        if self._match_text_seq("AND", "STATISTICS"):
    2591            statistics = True
    2592        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2593            statistics = False
    2594        else:
    2595            statistics = None
    2596
    2597        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2598
    2599    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2600        if self._match_text_seq("SQL"):
    2601            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2602        return None
    2603
    2604    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2605        if self._match_text_seq("SQL", "DATA"):
    2606            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2607        return None
    2608
    2609    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2610        if self._match_text_seq("PRIMARY", "INDEX"):
    2611            return exp.NoPrimaryIndexProperty()
    2612        if self._match_text_seq("SQL"):
    2613            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2614        return None
    2615
    2616    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2617        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2618            return exp.OnCommitProperty()
    2619        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2620            return exp.OnCommitProperty(delete=True)
    2621        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2622
    2623    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2624        if self._match_text_seq("SQL", "DATA"):
    2625            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2626        return None
    2627
    2628    def _parse_distkey(self) -> exp.DistKeyProperty:
    2629        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2630
    2631    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2632        table = self._parse_table(schema=True)
    2633
    2634        options = []
    2635        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2636            this = self._prev.text.upper()
    2637
    2638            id_var = self._parse_id_var()
    2639            if not id_var:
    2640                return None
    2641
    2642            options.append(
    2643                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2644            )
    2645
    2646        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2647
    2648    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2649        return self.expression(
    2650            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2651        )
    2652
    2653    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2654        self._match(TokenType.EQ)
    2655        return self.expression(
    2656            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2657        )
    2658
    2659    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2660        self._match_text_seq("WITH", "CONNECTION")
    2661        return self.expression(
    2662            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2663        )
    2664
    2665    def _parse_returns(self) -> exp.ReturnsProperty:
    2666        value: t.Optional[exp.Expression]
    2667        null = None
    2668        is_table = self._match(TokenType.TABLE)
    2669
    2670        if is_table:
    2671            if self._match(TokenType.LT):
    2672                value = self.expression(
    2673                    exp.Schema,
    2674                    this="TABLE",
    2675                    expressions=self._parse_csv(self._parse_struct_types),
    2676                )
    2677                if not self._match(TokenType.GT):
    2678                    self.raise_error("Expecting >")
    2679            else:
    2680                value = self._parse_schema(exp.var("TABLE"))
    2681        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2682            null = True
    2683            value = None
    2684        else:
    2685            value = self._parse_types()
    2686
    2687        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2688
    2689    def _parse_describe(self) -> exp.Describe:
    2690        kind = self._match_set(self.CREATABLES) and self._prev.text
    2691        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
    2692        if self._match(TokenType.DOT):
    2693            style = None
    2694            self._retreat(self._index - 2)
    2695
    2696        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
    2697
    2698        if self._match_set(self.STATEMENT_PARSERS, advance=False):
    2699            this = self._parse_statement()
    2700        else:
    2701            this = self._parse_table(schema=True)
    2702
    2703        properties = self._parse_properties()
    2704        expressions = properties.expressions if properties else None
    2705        partition = self._parse_partition()
    2706        return self.expression(
    2707            exp.Describe,
    2708            this=this,
    2709            style=style,
    2710            kind=kind,
    2711            expressions=expressions,
    2712            partition=partition,
    2713            format=format,
    2714        )
    2715
    2716    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
    2717        kind = self._prev.text.upper()
    2718        expressions = []
    2719
    2720        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
    2721            if self._match(TokenType.WHEN):
    2722                expression = self._parse_disjunction()
    2723                self._match(TokenType.THEN)
    2724            else:
    2725                expression = None
    2726
    2727            else_ = self._match(TokenType.ELSE)
    2728
    2729            if not self._match(TokenType.INTO):
    2730                return None
    2731
    2732            return self.expression(
    2733                exp.ConditionalInsert,
    2734                this=self.expression(
    2735                    exp.Insert,
    2736                    this=self._parse_table(schema=True),
    2737                    expression=self._parse_derived_table_values(),
    2738                ),
    2739                expression=expression,
    2740                else_=else_,
    2741            )
    2742
    2743        expression = parse_conditional_insert()
    2744        while expression is not None:
    2745            expressions.append(expression)
    2746            expression = parse_conditional_insert()
    2747
    2748        return self.expression(
    2749            exp.MultitableInserts,
    2750            kind=kind,
    2751            comments=comments,
    2752            expressions=expressions,
    2753            source=self._parse_table(),
    2754        )
    2755
    2756    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
    2757        comments = []
    2758        hint = self._parse_hint()
    2759        overwrite = self._match(TokenType.OVERWRITE)
    2760        ignore = self._match(TokenType.IGNORE)
    2761        local = self._match_text_seq("LOCAL")
    2762        alternative = None
    2763        is_function = None
    2764
    2765        if self._match_text_seq("DIRECTORY"):
    2766            this: t.Optional[exp.Expression] = self.expression(
    2767                exp.Directory,
    2768                this=self._parse_var_or_string(),
    2769                local=local,
    2770                row_format=self._parse_row_format(match_row=True),
    2771            )
    2772        else:
    2773            if self._match_set((TokenType.FIRST, TokenType.ALL)):
    2774                comments += ensure_list(self._prev_comments)
    2775                return self._parse_multitable_inserts(comments)
    2776
    2777            if self._match(TokenType.OR):
    2778                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2779
    2780            self._match(TokenType.INTO)
    2781            comments += ensure_list(self._prev_comments)
    2782            self._match(TokenType.TABLE)
    2783            is_function = self._match(TokenType.FUNCTION)
    2784
    2785            this = (
    2786                self._parse_table(schema=True, parse_partition=True)
    2787                if not is_function
    2788                else self._parse_function()
    2789            )
    2790            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
    2791                this.set("alias", self._parse_table_alias())
    2792
    2793        returning = self._parse_returning()
    2794
    2795        return self.expression(
    2796            exp.Insert,
    2797            comments=comments,
    2798            hint=hint,
    2799            is_function=is_function,
    2800            this=this,
    2801            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2802            by_name=self._match_text_seq("BY", "NAME"),
    2803            exists=self._parse_exists(),
    2804            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2805            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
    2806            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
    2807            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2808            conflict=self._parse_on_conflict(),
    2809            returning=returning or self._parse_returning(),
    2810            overwrite=overwrite,
    2811            alternative=alternative,
    2812            ignore=ignore,
    2813            source=self._match(TokenType.TABLE) and self._parse_table(),
    2814        )
    2815
    2816    def _parse_kill(self) -> exp.Kill:
    2817        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2818
    2819        return self.expression(
    2820            exp.Kill,
    2821            this=self._parse_primary(),
    2822            kind=kind,
    2823        )
    2824
    2825    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2826        conflict = self._match_text_seq("ON", "CONFLICT")
    2827        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2828
    2829        if not conflict and not duplicate:
    2830            return None
    2831
    2832        conflict_keys = None
    2833        constraint = None
    2834
    2835        if conflict:
    2836            if self._match_text_seq("ON", "CONSTRAINT"):
    2837                constraint = self._parse_id_var()
    2838            elif self._match(TokenType.L_PAREN):
    2839                conflict_keys = self._parse_csv(self._parse_id_var)
    2840                self._match_r_paren()
    2841
    2842        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2843        if self._prev.token_type == TokenType.UPDATE:
    2844            self._match(TokenType.SET)
    2845            expressions = self._parse_csv(self._parse_equality)
    2846        else:
    2847            expressions = None
    2848
    2849        return self.expression(
    2850            exp.OnConflict,
    2851            duplicate=duplicate,
    2852            expressions=expressions,
    2853            action=action,
    2854            conflict_keys=conflict_keys,
    2855            constraint=constraint,
    2856            where=self._parse_where(),
    2857        )
    2858
    2859    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2860        if not self._match(TokenType.RETURNING):
    2861            return None
    2862        return self.expression(
    2863            exp.Returning,
    2864            expressions=self._parse_csv(self._parse_expression),
    2865            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2866        )
    2867
    2868    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2869        if not self._match(TokenType.FORMAT):
    2870            return None
    2871        return self._parse_row_format()
    2872
    2873    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2874        index = self._index
    2875        with_ = with_ or self._match_text_seq("WITH")
    2876
    2877        if not self._match(TokenType.SERDE_PROPERTIES):
    2878            self._retreat(index)
    2879            return None
    2880        return self.expression(
    2881            exp.SerdeProperties,
    2882            **{  # type: ignore
    2883                "expressions": self._parse_wrapped_properties(),
    2884                "with": with_,
    2885            },
    2886        )
    2887
    2888    def _parse_row_format(
    2889        self, match_row: bool = False
    2890    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2891        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2892            return None
    2893
    2894        if self._match_text_seq("SERDE"):
    2895            this = self._parse_string()
    2896
    2897            serde_properties = self._parse_serde_properties()
    2898
    2899            return self.expression(
    2900                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2901            )
    2902
    2903        self._match_text_seq("DELIMITED")
    2904
    2905        kwargs = {}
    2906
    2907        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2908            kwargs["fields"] = self._parse_string()
    2909            if self._match_text_seq("ESCAPED", "BY"):
    2910                kwargs["escaped"] = self._parse_string()
    2911        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2912            kwargs["collection_items"] = self._parse_string()
    2913        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2914            kwargs["map_keys"] = self._parse_string()
    2915        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2916            kwargs["lines"] = self._parse_string()
    2917        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2918            kwargs["null"] = self._parse_string()
    2919
    2920        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2921
    2922    def _parse_load(self) -> exp.LoadData | exp.Command:
    2923        if self._match_text_seq("DATA"):
    2924            local = self._match_text_seq("LOCAL")
    2925            self._match_text_seq("INPATH")
    2926            inpath = self._parse_string()
    2927            overwrite = self._match(TokenType.OVERWRITE)
    2928            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2929
    2930            return self.expression(
    2931                exp.LoadData,
    2932                this=self._parse_table(schema=True),
    2933                local=local,
    2934                overwrite=overwrite,
    2935                inpath=inpath,
    2936                partition=self._parse_partition(),
    2937                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2938                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2939            )
    2940        return self._parse_as_command(self._prev)
    2941
    2942    def _parse_delete(self) -> exp.Delete:
    2943        # This handles MySQL's "Multiple-Table Syntax"
    2944        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2945        tables = None
    2946        if not self._match(TokenType.FROM, advance=False):
    2947            tables = self._parse_csv(self._parse_table) or None
    2948
    2949        returning = self._parse_returning()
    2950
    2951        return self.expression(
    2952            exp.Delete,
    2953            tables=tables,
    2954            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    2955            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    2956            cluster=self._match(TokenType.ON) and self._parse_on_property(),
    2957            where=self._parse_where(),
    2958            returning=returning or self._parse_returning(),
    2959            limit=self._parse_limit(),
    2960        )
    2961
    2962    def _parse_update(self) -> exp.Update:
    2963        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    2964        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    2965        returning = self._parse_returning()
    2966        return self.expression(
    2967            exp.Update,
    2968            **{  # type: ignore
    2969                "this": this,
    2970                "expressions": expressions,
    2971                "from": self._parse_from(joins=True),
    2972                "where": self._parse_where(),
    2973                "returning": returning or self._parse_returning(),
    2974                "order": self._parse_order(),
    2975                "limit": self._parse_limit(),
    2976            },
    2977        )
    2978
    2979    def _parse_use(self) -> exp.Use:
    2980        return self.expression(
    2981            exp.Use,
    2982            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
    2983            this=self._parse_table(schema=False),
    2984        )
    2985
    2986    def _parse_uncache(self) -> exp.Uncache:
    2987        if not self._match(TokenType.TABLE):
    2988            self.raise_error("Expecting TABLE after UNCACHE")
    2989
    2990        return self.expression(
    2991            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    2992        )
    2993
    2994    def _parse_cache(self) -> exp.Cache:
    2995        lazy = self._match_text_seq("LAZY")
    2996        self._match(TokenType.TABLE)
    2997        table = self._parse_table(schema=True)
    2998
    2999        options = []
    3000        if self._match_text_seq("OPTIONS"):
    3001            self._match_l_paren()
    3002            k = self._parse_string()
    3003            self._match(TokenType.EQ)
    3004            v = self._parse_string()
    3005            options = [k, v]
    3006            self._match_r_paren()
    3007
    3008        self._match(TokenType.ALIAS)
    3009        return self.expression(
    3010            exp.Cache,
    3011            this=table,
    3012            lazy=lazy,
    3013            options=options,
    3014            expression=self._parse_select(nested=True),
    3015        )
    3016
    3017    def _parse_partition(self) -> t.Optional[exp.Partition]:
    3018        if not self._match_texts(self.PARTITION_KEYWORDS):
    3019            return None
    3020
    3021        return self.expression(
    3022            exp.Partition,
    3023            subpartition=self._prev.text.upper() == "SUBPARTITION",
    3024            expressions=self._parse_wrapped_csv(self._parse_assignment),
    3025        )
    3026
    3027    def _parse_value(self) -> t.Optional[exp.Tuple]:
    3028        def _parse_value_expression() -> t.Optional[exp.Expression]:
    3029            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
    3030                return exp.var(self._prev.text.upper())
    3031            return self._parse_expression()
    3032
    3033        if self._match(TokenType.L_PAREN):
    3034            expressions = self._parse_csv(_parse_value_expression)
    3035            self._match_r_paren()
    3036            return self.expression(exp.Tuple, expressions=expressions)
    3037
    3038        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    3039        expression = self._parse_expression()
    3040        if expression:
    3041            return self.expression(exp.Tuple, expressions=[expression])
    3042        return None
    3043
    3044    def _parse_projections(self) -> t.List[exp.Expression]:
    3045        return self._parse_expressions()
    3046
    3047    def _parse_select(
    3048        self,
    3049        nested: bool = False,
    3050        table: bool = False,
    3051        parse_subquery_alias: bool = True,
    3052        parse_set_operation: bool = True,
    3053    ) -> t.Optional[exp.Expression]:
    3054        cte = self._parse_with()
    3055
    3056        if cte:
    3057            this = self._parse_statement()
    3058
    3059            if not this:
    3060                self.raise_error("Failed to parse any statement following CTE")
    3061                return cte
    3062
    3063            if "with" in this.arg_types:
    3064                this.set("with", cte)
    3065            else:
    3066                self.raise_error(f"{this.key} does not support CTE")
    3067                this = cte
    3068
    3069            return this
    3070
    3071        # duckdb supports leading with FROM x
    3072        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    3073
    3074        if self._match(TokenType.SELECT):
    3075            comments = self._prev_comments
    3076
    3077            hint = self._parse_hint()
    3078
    3079            if self._next and not self._next.token_type == TokenType.DOT:
    3080                all_ = self._match(TokenType.ALL)
    3081                distinct = self._match_set(self.DISTINCT_TOKENS)
    3082            else:
    3083                all_, distinct = None, None
    3084
    3085            kind = (
    3086                self._match(TokenType.ALIAS)
    3087                and self._match_texts(("STRUCT", "VALUE"))
    3088                and self._prev.text.upper()
    3089            )
    3090
    3091            if distinct:
    3092                distinct = self.expression(
    3093                    exp.Distinct,
    3094                    on=self._parse_value() if self._match(TokenType.ON) else None,
    3095                )
    3096
    3097            if all_ and distinct:
    3098                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    3099
    3100            operation_modifiers = []
    3101            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
    3102                operation_modifiers.append(exp.var(self._prev.text.upper()))
    3103
    3104            limit = self._parse_limit(top=True)
    3105            projections = self._parse_projections()
    3106
    3107            this = self.expression(
    3108                exp.Select,
    3109                kind=kind,
    3110                hint=hint,
    3111                distinct=distinct,
    3112                expressions=projections,
    3113                limit=limit,
    3114                operation_modifiers=operation_modifiers or None,
    3115            )
    3116            this.comments = comments
    3117
    3118            into = self._parse_into()
    3119            if into:
    3120                this.set("into", into)
    3121
    3122            if not from_:
    3123                from_ = self._parse_from()
    3124
    3125            if from_:
    3126                this.set("from", from_)
    3127
    3128            this = self._parse_query_modifiers(this)
    3129        elif (table or nested) and self._match(TokenType.L_PAREN):
    3130            if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
    3131                this = self._parse_simplified_pivot(
    3132                    is_unpivot=self._prev.token_type == TokenType.UNPIVOT
    3133                )
    3134            elif self._match(TokenType.FROM):
    3135                from_ = self._parse_from(skip_from_token=True)
    3136                # Support parentheses for duckdb FROM-first syntax
    3137                select = self._parse_select()
    3138                if select:
    3139                    select.set("from", from_)
    3140                    this = select
    3141                else:
    3142                    this = exp.select("*").from_(t.cast(exp.From, from_))
    3143            else:
    3144                this = (
    3145                    self._parse_table()
    3146                    if table
    3147                    else self._parse_select(nested=True, parse_set_operation=False)
    3148                )
    3149
    3150                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
    3151                # in case a modifier (e.g. join) is following
    3152                if table and isinstance(this, exp.Values) and this.alias:
    3153                    alias = this.args["alias"].pop()
    3154                    this = exp.Table(this=this, alias=alias)
    3155
    3156                this = self._parse_query_modifiers(self._parse_set_operations(this))
    3157
    3158            self._match_r_paren()
    3159
    3160            # We return early here so that the UNION isn't attached to the subquery by the
    3161            # following call to _parse_set_operations, but instead becomes the parent node
    3162            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    3163        elif self._match(TokenType.VALUES, advance=False):
    3164            this = self._parse_derived_table_values()
    3165        elif from_:
    3166            this = exp.select("*").from_(from_.this, copy=False)
    3167        elif self._match(TokenType.SUMMARIZE):
    3168            table = self._match(TokenType.TABLE)
    3169            this = self._parse_select() or self._parse_string() or self._parse_table()
    3170            return self.expression(exp.Summarize, this=this, table=table)
    3171        elif self._match(TokenType.DESCRIBE):
    3172            this = self._parse_describe()
    3173        elif self._match_text_seq("STREAM"):
    3174            this = self._parse_function()
    3175            if this:
    3176                this = self.expression(exp.Stream, this=this)
    3177            else:
    3178                self._retreat(self._index - 1)
    3179        else:
    3180            this = None
    3181
    3182        return self._parse_set_operations(this) if parse_set_operation else this
    3183
    3184    def _parse_recursive_with_search(self) -> t.Optional[exp.RecursiveWithSearch]:
    3185        self._match_text_seq("SEARCH")
    3186
    3187        kind = self._match_texts(self.RECURSIVE_CTE_SEARCH_KIND) and self._prev.text.upper()
    3188
    3189        if not kind:
    3190            return None
    3191
    3192        self._match_text_seq("FIRST", "BY")
    3193
    3194        return self.expression(
    3195            exp.RecursiveWithSearch,
    3196            kind=kind,
    3197            this=self._parse_id_var(),
    3198            expression=self._match_text_seq("SET") and self._parse_id_var(),
    3199            using=self._match_text_seq("USING") and self._parse_id_var(),
    3200        )
    3201
    3202    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    3203        if not skip_with_token and not self._match(TokenType.WITH):
    3204            return None
    3205
    3206        comments = self._prev_comments
    3207        recursive = self._match(TokenType.RECURSIVE)
    3208
    3209        last_comments = None
    3210        expressions = []
    3211        while True:
    3212            cte = self._parse_cte()
    3213            if isinstance(cte, exp.CTE):
    3214                expressions.append(cte)
    3215                if last_comments:
    3216                    cte.add_comments(last_comments)
    3217
    3218            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    3219                break
    3220            else:
    3221                self._match(TokenType.WITH)
    3222
    3223            last_comments = self._prev_comments
    3224
    3225        return self.expression(
    3226            exp.With,
    3227            comments=comments,
    3228            expressions=expressions,
    3229            recursive=recursive,
    3230            search=self._parse_recursive_with_search(),
    3231        )
    3232
    3233    def _parse_cte(self) -> t.Optional[exp.CTE]:
    3234        index = self._index
    3235
    3236        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    3237        if not alias or not alias.this:
    3238            self.raise_error("Expected CTE to have alias")
    3239
    3240        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
    3241            self._retreat(index)
    3242            return None
    3243
    3244        comments = self._prev_comments
    3245
    3246        if self._match_text_seq("NOT", "MATERIALIZED"):
    3247            materialized = False
    3248        elif self._match_text_seq("MATERIALIZED"):
    3249            materialized = True
    3250        else:
    3251            materialized = None
    3252
    3253        cte = self.expression(
    3254            exp.CTE,
    3255            this=self._parse_wrapped(self._parse_statement),
    3256            alias=alias,
    3257            materialized=materialized,
    3258            comments=comments,
    3259        )
    3260
    3261        if isinstance(cte.this, exp.Values):
    3262            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
    3263
    3264        return cte
    3265
    3266    def _parse_table_alias(
    3267        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    3268    ) -> t.Optional[exp.TableAlias]:
    3269        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    3270        # so this section tries to parse the clause version and if it fails, it treats the token
    3271        # as an identifier (alias)
    3272        if self._can_parse_limit_or_offset():
    3273            return None
    3274
    3275        any_token = self._match(TokenType.ALIAS)
    3276        alias = (
    3277            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3278            or self._parse_string_as_identifier()
    3279        )
    3280
    3281        index = self._index
    3282        if self._match(TokenType.L_PAREN):
    3283            columns = self._parse_csv(self._parse_function_parameter)
    3284            self._match_r_paren() if columns else self._retreat(index)
    3285        else:
    3286            columns = None
    3287
    3288        if not alias and not columns:
    3289            return None
    3290
    3291        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    3292
    3293        # We bubble up comments from the Identifier to the TableAlias
    3294        if isinstance(alias, exp.Identifier):
    3295            table_alias.add_comments(alias.pop_comments())
    3296
    3297        return table_alias
    3298
    3299    def _parse_subquery(
    3300        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    3301    ) -> t.Optional[exp.Subquery]:
    3302        if not this:
    3303            return None
    3304
    3305        return self.expression(
    3306            exp.Subquery,
    3307            this=this,
    3308            pivots=self._parse_pivots(),
    3309            alias=self._parse_table_alias() if parse_alias else None,
    3310            sample=self._parse_table_sample(),
    3311        )
    3312
    3313    def _implicit_unnests_to_explicit(self, this: E) -> E:
    3314        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    3315
    3316        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    3317        for i, join in enumerate(this.args.get("joins") or []):
    3318            table = join.this
    3319            normalized_table = table.copy()
    3320            normalized_table.meta["maybe_column"] = True
    3321            normalized_table = _norm(normalized_table, dialect=self.dialect)
    3322
    3323            if isinstance(table, exp.Table) and not join.args.get("on"):
    3324                if normalized_table.parts[0].name in refs:
    3325                    table_as_column = table.to_column()
    3326                    unnest = exp.Unnest(expressions=[table_as_column])
    3327
    3328                    # Table.to_column creates a parent Alias node that we want to convert to
    3329                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    3330                    if isinstance(table.args.get("alias"), exp.TableAlias):
    3331                        table_as_column.replace(table_as_column.this)
    3332                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    3333
    3334                    table.replace(unnest)
    3335
    3336            refs.add(normalized_table.alias_or_name)
    3337
    3338        return this
    3339
    3340    def _parse_query_modifiers(
    3341        self, this: t.Optional[exp.Expression]
    3342    ) -> t.Optional[exp.Expression]:
    3343        if isinstance(this, (exp.Query, exp.Table)):
    3344            for join in self._parse_joins():
    3345                this.append("joins", join)
    3346            for lateral in iter(self._parse_lateral, None):
    3347                this.append("laterals", lateral)
    3348
    3349            while True:
    3350                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    3351                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    3352                    key, expression = parser(self)
    3353
    3354                    if expression:
    3355                        this.set(key, expression)
    3356                        if key == "limit":
    3357                            offset = expression.args.pop("offset", None)
    3358
    3359                            if offset:
    3360                                offset = exp.Offset(expression=offset)
    3361                                this.set("offset", offset)
    3362
    3363                                limit_by_expressions = expression.expressions
    3364                                expression.set("expressions", None)
    3365                                offset.set("expressions", limit_by_expressions)
    3366                        continue
    3367                break
    3368
    3369        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
    3370            this = self._implicit_unnests_to_explicit(this)
    3371
    3372        return this
    3373
    3374    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
    3375        start = self._curr
    3376        while self._curr:
    3377            self._advance()
    3378
    3379        end = self._tokens[self._index - 1]
    3380        return exp.Hint(expressions=[self._find_sql(start, end)])
    3381
    3382    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
    3383        return self._parse_function_call()
    3384
    3385    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
    3386        start_index = self._index
    3387        should_fallback_to_string = False
    3388
    3389        hints = []
    3390        try:
    3391            for hint in iter(
    3392                lambda: self._parse_csv(
    3393                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
    3394                ),
    3395                [],
    3396            ):
    3397                hints.extend(hint)
    3398        except ParseError:
    3399            should_fallback_to_string = True
    3400
    3401        if should_fallback_to_string or self._curr:
    3402            self._retreat(start_index)
    3403            return self._parse_hint_fallback_to_string()
    3404
    3405        return self.expression(exp.Hint, expressions=hints)
    3406
    3407    def _parse_hint(self) -> t.Optional[exp.Hint]:
    3408        if self._match(TokenType.HINT) and self._prev_comments:
    3409            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
    3410
    3411        return None
    3412
    3413    def _parse_into(self) -> t.Optional[exp.Into]:
    3414        if not self._match(TokenType.INTO):
    3415            return None
    3416
    3417        temp = self._match(TokenType.TEMPORARY)
    3418        unlogged = self._match_text_seq("UNLOGGED")
    3419        self._match(TokenType.TABLE)
    3420
    3421        return self.expression(
    3422            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    3423        )
    3424
    3425    def _parse_from(
    3426        self, joins: bool = False, skip_from_token: bool = False
    3427    ) -> t.Optional[exp.From]:
    3428        if not skip_from_token and not self._match(TokenType.FROM):
    3429            return None
    3430
    3431        return self.expression(
    3432            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    3433        )
    3434
    3435    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    3436        return self.expression(
    3437            exp.MatchRecognizeMeasure,
    3438            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    3439            this=self._parse_expression(),
    3440        )
    3441
    3442    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    3443        if not self._match(TokenType.MATCH_RECOGNIZE):
    3444            return None
    3445
    3446        self._match_l_paren()
    3447
    3448        partition = self._parse_partition_by()
    3449        order = self._parse_order()
    3450
    3451        measures = (
    3452            self._parse_csv(self._parse_match_recognize_measure)
    3453            if self._match_text_seq("MEASURES")
    3454            else None
    3455        )
    3456
    3457        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    3458            rows = exp.var("ONE ROW PER MATCH")
    3459        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    3460            text = "ALL ROWS PER MATCH"
    3461            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    3462                text += " SHOW EMPTY MATCHES"
    3463            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    3464                text += " OMIT EMPTY MATCHES"
    3465            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    3466                text += " WITH UNMATCHED ROWS"
    3467            rows = exp.var(text)
    3468        else:
    3469            rows = None
    3470
    3471        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    3472            text = "AFTER MATCH SKIP"
    3473            if self._match_text_seq("PAST", "LAST", "ROW"):
    3474                text += " PAST LAST ROW"
    3475            elif self._match_text_seq("TO", "NEXT", "ROW"):
    3476                text += " TO NEXT ROW"
    3477            elif self._match_text_seq("TO", "FIRST"):
    3478                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    3479            elif self._match_text_seq("TO", "LAST"):
    3480                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    3481            after = exp.var(text)
    3482        else:
    3483            after = None
    3484
    3485        if self._match_text_seq("PATTERN"):
    3486            self._match_l_paren()
    3487
    3488            if not self._curr:
    3489                self.raise_error("Expecting )", self._curr)
    3490
    3491            paren = 1
    3492            start = self._curr
    3493
    3494            while self._curr and paren > 0:
    3495                if self._curr.token_type == TokenType.L_PAREN:
    3496                    paren += 1
    3497                if self._curr.token_type == TokenType.R_PAREN:
    3498                    paren -= 1
    3499
    3500                end = self._prev
    3501                self._advance()
    3502
    3503            if paren > 0:
    3504                self.raise_error("Expecting )", self._curr)
    3505
    3506            pattern = exp.var(self._find_sql(start, end))
    3507        else:
    3508            pattern = None
    3509
    3510        define = (
    3511            self._parse_csv(self._parse_name_as_expression)
    3512            if self._match_text_seq("DEFINE")
    3513            else None
    3514        )
    3515
    3516        self._match_r_paren()
    3517
    3518        return self.expression(
    3519            exp.MatchRecognize,
    3520            partition_by=partition,
    3521            order=order,
    3522            measures=measures,
    3523            rows=rows,
    3524            after=after,
    3525            pattern=pattern,
    3526            define=define,
    3527            alias=self._parse_table_alias(),
    3528        )
    3529
    3530    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3531        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3532        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3533            cross_apply = False
    3534
    3535        if cross_apply is not None:
    3536            this = self._parse_select(table=True)
    3537            view = None
    3538            outer = None
    3539        elif self._match(TokenType.LATERAL):
    3540            this = self._parse_select(table=True)
    3541            view = self._match(TokenType.VIEW)
    3542            outer = self._match(TokenType.OUTER)
    3543        else:
    3544            return None
    3545
    3546        if not this:
    3547            this = (
    3548                self._parse_unnest()
    3549                or self._parse_function()
    3550                or self._parse_id_var(any_token=False)
    3551            )
    3552
    3553            while self._match(TokenType.DOT):
    3554                this = exp.Dot(
    3555                    this=this,
    3556                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3557                )
    3558
    3559        if view:
    3560            table = self._parse_id_var(any_token=False)
    3561            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3562            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3563                exp.TableAlias, this=table, columns=columns
    3564            )
    3565        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3566            # We move the alias from the lateral's child node to the lateral itself
    3567            table_alias = this.args["alias"].pop()
    3568        else:
    3569            table_alias = self._parse_table_alias()
    3570
    3571        return self.expression(
    3572            exp.Lateral,
    3573            this=this,
    3574            view=view,
    3575            outer=outer,
    3576            alias=table_alias,
    3577            cross_apply=cross_apply,
    3578        )
    3579
    3580    def _parse_join_parts(
    3581        self,
    3582    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3583        return (
    3584            self._match_set(self.JOIN_METHODS) and self._prev,
    3585            self._match_set(self.JOIN_SIDES) and self._prev,
    3586            self._match_set(self.JOIN_KINDS) and self._prev,
    3587        )
    3588
    3589    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
    3590        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
    3591            this = self._parse_column()
    3592            if isinstance(this, exp.Column):
    3593                return this.this
    3594            return this
    3595
    3596        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
    3597
    3598    def _parse_join(
    3599        self, skip_join_token: bool = False, parse_bracket: bool = False
    3600    ) -> t.Optional[exp.Join]:
    3601        if self._match(TokenType.COMMA):
    3602            return self.expression(exp.Join, this=self._parse_table())
    3603
    3604        index = self._index
    3605        method, side, kind = self._parse_join_parts()
    3606        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3607        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
    3608
    3609        if not skip_join_token and not join:
    3610            self._retreat(index)
    3611            kind = None
    3612            method = None
    3613            side = None
    3614
    3615        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3616        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3617
    3618        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3619            return None
    3620
    3621        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3622        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
    3623            kwargs["expressions"] = self._parse_csv(
    3624                lambda: self._parse_table(parse_bracket=parse_bracket)
    3625            )
    3626
    3627        if method:
    3628            kwargs["method"] = method.text
    3629        if side:
    3630            kwargs["side"] = side.text
    3631        if kind:
    3632            kwargs["kind"] = kind.text
    3633        if hint:
    3634            kwargs["hint"] = hint
    3635
    3636        if self._match(TokenType.MATCH_CONDITION):
    3637            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3638
    3639        if self._match(TokenType.ON):
    3640            kwargs["on"] = self._parse_assignment()
    3641        elif self._match(TokenType.USING):
    3642            kwargs["using"] = self._parse_using_identifiers()
    3643        elif (
    3644            not (outer_apply or cross_apply)
    3645            and not isinstance(kwargs["this"], exp.Unnest)
    3646            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
    3647        ):
    3648            index = self._index
    3649            joins: t.Optional[list] = list(self._parse_joins())
    3650
    3651            if joins and self._match(TokenType.ON):
    3652                kwargs["on"] = self._parse_assignment()
    3653            elif joins and self._match(TokenType.USING):
    3654                kwargs["using"] = self._parse_using_identifiers()
    3655            else:
    3656                joins = None
    3657                self._retreat(index)
    3658
    3659            kwargs["this"].set("joins", joins if joins else None)
    3660
    3661        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3662        return self.expression(exp.Join, comments=comments, **kwargs)
    3663
    3664    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3665        this = self._parse_assignment()
    3666
    3667        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3668            return this
    3669
    3670        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3671            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3672
    3673        return this
    3674
    3675    def _parse_index_params(self) -> exp.IndexParameters:
    3676        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3677
    3678        if self._match(TokenType.L_PAREN, advance=False):
    3679            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3680        else:
    3681            columns = None
    3682
    3683        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3684        partition_by = self._parse_partition_by()
    3685        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3686        tablespace = (
    3687            self._parse_var(any_token=True)
    3688            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3689            else None
    3690        )
    3691        where = self._parse_where()
    3692
    3693        on = self._parse_field() if self._match(TokenType.ON) else None
    3694
    3695        return self.expression(
    3696            exp.IndexParameters,
    3697            using=using,
    3698            columns=columns,
    3699            include=include,
    3700            partition_by=partition_by,
    3701            where=where,
    3702            with_storage=with_storage,
    3703            tablespace=tablespace,
    3704            on=on,
    3705        )
    3706
    3707    def _parse_index(
    3708        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3709    ) -> t.Optional[exp.Index]:
    3710        if index or anonymous:
    3711            unique = None
    3712            primary = None
    3713            amp = None
    3714
    3715            self._match(TokenType.ON)
    3716            self._match(TokenType.TABLE)  # hive
    3717            table = self._parse_table_parts(schema=True)
    3718        else:
    3719            unique = self._match(TokenType.UNIQUE)
    3720            primary = self._match_text_seq("PRIMARY")
    3721            amp = self._match_text_seq("AMP")
    3722
    3723            if not self._match(TokenType.INDEX):
    3724                return None
    3725
    3726            index = self._parse_id_var()
    3727            table = None
    3728
    3729        params = self._parse_index_params()
    3730
    3731        return self.expression(
    3732            exp.Index,
    3733            this=index,
    3734            table=table,
    3735            unique=unique,
    3736            primary=primary,
    3737            amp=amp,
    3738            params=params,
    3739        )
    3740
    3741    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3742        hints: t.List[exp.Expression] = []
    3743        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3744            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3745            hints.append(
    3746                self.expression(
    3747                    exp.WithTableHint,
    3748                    expressions=self._parse_csv(
    3749                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3750                    ),
    3751                )
    3752            )
    3753            self._match_r_paren()
    3754        else:
    3755            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3756            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3757                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3758
    3759                self._match_set((TokenType.INDEX, TokenType.KEY))
    3760                if self._match(TokenType.FOR):
    3761                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3762
    3763                hint.set("expressions", self._parse_wrapped_id_vars())
    3764                hints.append(hint)
    3765
    3766        return hints or None
    3767
    3768    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3769        return (
    3770            (not schema and self._parse_function(optional_parens=False))
    3771            or self._parse_id_var(any_token=False)
    3772            or self._parse_string_as_identifier()
    3773            or self._parse_placeholder()
    3774        )
    3775
    3776    def _parse_table_parts(
    3777        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3778    ) -> exp.Table:
    3779        catalog = None
    3780        db = None
    3781        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3782
    3783        while self._match(TokenType.DOT):
    3784            if catalog:
    3785                # This allows nesting the table in arbitrarily many dot expressions if needed
    3786                table = self.expression(
    3787                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3788                )
    3789            else:
    3790                catalog = db
    3791                db = table
    3792                # "" used for tsql FROM a..b case
    3793                table = self._parse_table_part(schema=schema) or ""
    3794
    3795        if (
    3796            wildcard
    3797            and self._is_connected()
    3798            and (isinstance(table, exp.Identifier) or not table)
    3799            and self._match(TokenType.STAR)
    3800        ):
    3801            if isinstance(table, exp.Identifier):
    3802                table.args["this"] += "*"
    3803            else:
    3804                table = exp.Identifier(this="*")
    3805
    3806        # We bubble up comments from the Identifier to the Table
    3807        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3808
    3809        if is_db_reference:
    3810            catalog = db
    3811            db = table
    3812            table = None
    3813
    3814        if not table and not is_db_reference:
    3815            self.raise_error(f"Expected table name but got {self._curr}")
    3816        if not db and is_db_reference:
    3817            self.raise_error(f"Expected database name but got {self._curr}")
    3818
    3819        table = self.expression(
    3820            exp.Table,
    3821            comments=comments,
    3822            this=table,
    3823            db=db,
    3824            catalog=catalog,
    3825        )
    3826
    3827        changes = self._parse_changes()
    3828        if changes:
    3829            table.set("changes", changes)
    3830
    3831        at_before = self._parse_historical_data()
    3832        if at_before:
    3833            table.set("when", at_before)
    3834
    3835        pivots = self._parse_pivots()
    3836        if pivots:
    3837            table.set("pivots", pivots)
    3838
    3839        return table
    3840
    3841    def _parse_table(
    3842        self,
    3843        schema: bool = False,
    3844        joins: bool = False,
    3845        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3846        parse_bracket: bool = False,
    3847        is_db_reference: bool = False,
    3848        parse_partition: bool = False,
    3849    ) -> t.Optional[exp.Expression]:
    3850        lateral = self._parse_lateral()
    3851        if lateral:
    3852            return lateral
    3853
    3854        unnest = self._parse_unnest()
    3855        if unnest:
    3856            return unnest
    3857
    3858        values = self._parse_derived_table_values()
    3859        if values:
    3860            return values
    3861
    3862        subquery = self._parse_select(table=True)
    3863        if subquery:
    3864            if not subquery.args.get("pivots"):
    3865                subquery.set("pivots", self._parse_pivots())
    3866            return subquery
    3867
    3868        bracket = parse_bracket and self._parse_bracket(None)
    3869        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3870
    3871        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
    3872            self._parse_table
    3873        )
    3874        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
    3875
    3876        only = self._match(TokenType.ONLY)
    3877
    3878        this = t.cast(
    3879            exp.Expression,
    3880            bracket
    3881            or rows_from
    3882            or self._parse_bracket(
    3883                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3884            ),
    3885        )
    3886
    3887        if only:
    3888            this.set("only", only)
    3889
    3890        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3891        self._match_text_seq("*")
    3892
    3893        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3894        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3895            this.set("partition", self._parse_partition())
    3896
    3897        if schema:
    3898            return self._parse_schema(this=this)
    3899
    3900        version = self._parse_version()
    3901
    3902        if version:
    3903            this.set("version", version)
    3904
    3905        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3906            this.set("sample", self._parse_table_sample())
    3907
    3908        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3909        if alias:
    3910            this.set("alias", alias)
    3911
    3912        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3913            return self.expression(
    3914                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3915            )
    3916
    3917        this.set("hints", self._parse_table_hints())
    3918
    3919        if not this.args.get("pivots"):
    3920            this.set("pivots", self._parse_pivots())
    3921
    3922        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3923            this.set("sample", self._parse_table_sample())
    3924
    3925        if joins:
    3926            for join in self._parse_joins():
    3927                this.append("joins", join)
    3928
    3929        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3930            this.set("ordinality", True)
    3931            this.set("alias", self._parse_table_alias())
    3932
    3933        return this
    3934
    3935    def _parse_version(self) -> t.Optional[exp.Version]:
    3936        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    3937            this = "TIMESTAMP"
    3938        elif self._match(TokenType.VERSION_SNAPSHOT):
    3939            this = "VERSION"
    3940        else:
    3941            return None
    3942
    3943        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    3944            kind = self._prev.text.upper()
    3945            start = self._parse_bitwise()
    3946            self._match_texts(("TO", "AND"))
    3947            end = self._parse_bitwise()
    3948            expression: t.Optional[exp.Expression] = self.expression(
    3949                exp.Tuple, expressions=[start, end]
    3950            )
    3951        elif self._match_text_seq("CONTAINED", "IN"):
    3952            kind = "CONTAINED IN"
    3953            expression = self.expression(
    3954                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    3955            )
    3956        elif self._match(TokenType.ALL):
    3957            kind = "ALL"
    3958            expression = None
    3959        else:
    3960            self._match_text_seq("AS", "OF")
    3961            kind = "AS OF"
    3962            expression = self._parse_type()
    3963
    3964        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    3965
    3966    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
    3967        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
    3968        index = self._index
    3969        historical_data = None
    3970        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
    3971            this = self._prev.text.upper()
    3972            kind = (
    3973                self._match(TokenType.L_PAREN)
    3974                and self._match_texts(self.HISTORICAL_DATA_KIND)
    3975                and self._prev.text.upper()
    3976            )
    3977            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    3978
    3979            if expression:
    3980                self._match_r_paren()
    3981                historical_data = self.expression(
    3982                    exp.HistoricalData, this=this, kind=kind, expression=expression
    3983                )
    3984            else:
    3985                self._retreat(index)
    3986
    3987        return historical_data
    3988
    3989    def _parse_changes(self) -> t.Optional[exp.Changes]:
    3990        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
    3991            return None
    3992
    3993        information = self._parse_var(any_token=True)
    3994        self._match_r_paren()
    3995
    3996        return self.expression(
    3997            exp.Changes,
    3998            information=information,
    3999            at_before=self._parse_historical_data(),
    4000            end=self._parse_historical_data(),
    4001        )
    4002
    4003    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    4004        if not self._match(TokenType.UNNEST):
    4005            return None
    4006
    4007        expressions = self._parse_wrapped_csv(self._parse_equality)
    4008        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    4009
    4010        alias = self._parse_table_alias() if with_alias else None
    4011
    4012        if alias:
    4013            if self.dialect.UNNEST_COLUMN_ONLY:
    4014                if alias.args.get("columns"):
    4015                    self.raise_error("Unexpected extra column alias in unnest.")
    4016
    4017                alias.set("columns", [alias.this])
    4018                alias.set("this", None)
    4019
    4020            columns = alias.args.get("columns") or []
    4021            if offset and len(expressions) < len(columns):
    4022                offset = columns.pop()
    4023
    4024        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    4025            self._match(TokenType.ALIAS)
    4026            offset = self._parse_id_var(
    4027                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    4028            ) or exp.to_identifier("offset")
    4029
    4030        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    4031
    4032    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    4033        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    4034        if not is_derived and not (
    4035            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
    4036            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
    4037        ):
    4038            return None
    4039
    4040        expressions = self._parse_csv(self._parse_value)
    4041        alias = self._parse_table_alias()
    4042
    4043        if is_derived:
    4044            self._match_r_paren()
    4045
    4046        return self.expression(
    4047            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    4048        )
    4049
    4050    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    4051        if not self._match(TokenType.TABLE_SAMPLE) and not (
    4052            as_modifier and self._match_text_seq("USING", "SAMPLE")
    4053        ):
    4054            return None
    4055
    4056        bucket_numerator = None
    4057        bucket_denominator = None
    4058        bucket_field = None
    4059        percent = None
    4060        size = None
    4061        seed = None
    4062
    4063        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    4064        matched_l_paren = self._match(TokenType.L_PAREN)
    4065
    4066        if self.TABLESAMPLE_CSV:
    4067            num = None
    4068            expressions = self._parse_csv(self._parse_primary)
    4069        else:
    4070            expressions = None
    4071            num = (
    4072                self._parse_factor()
    4073                if self._match(TokenType.NUMBER, advance=False)
    4074                else self._parse_primary() or self._parse_placeholder()
    4075            )
    4076
    4077        if self._match_text_seq("BUCKET"):
    4078            bucket_numerator = self._parse_number()
    4079            self._match_text_seq("OUT", "OF")
    4080            bucket_denominator = bucket_denominator = self._parse_number()
    4081            self._match(TokenType.ON)
    4082            bucket_field = self._parse_field()
    4083        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    4084            percent = num
    4085        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    4086            size = num
    4087        else:
    4088            percent = num
    4089
    4090        if matched_l_paren:
    4091            self._match_r_paren()
    4092
    4093        if self._match(TokenType.L_PAREN):
    4094            method = self._parse_var(upper=True)
    4095            seed = self._match(TokenType.COMMA) and self._parse_number()
    4096            self._match_r_paren()
    4097        elif self._match_texts(("SEED", "REPEATABLE")):
    4098            seed = self._parse_wrapped(self._parse_number)
    4099
    4100        if not method and self.DEFAULT_SAMPLING_METHOD:
    4101            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    4102
    4103        return self.expression(
    4104            exp.TableSample,
    4105            expressions=expressions,
    4106            method=method,
    4107            bucket_numerator=bucket_numerator,
    4108            bucket_denominator=bucket_denominator,
    4109            bucket_field=bucket_field,
    4110            percent=percent,
    4111            size=size,
    4112            seed=seed,
    4113        )
    4114
    4115    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    4116        return list(iter(self._parse_pivot, None)) or None
    4117
    4118    def _parse_joins(self) -> t.Iterator[exp.Join]:
    4119        return iter(self._parse_join, None)
    4120
    4121    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
    4122        if not self._match(TokenType.INTO):
    4123            return None
    4124
    4125        return self.expression(
    4126            exp.UnpivotColumns,
    4127            this=self._match_text_seq("NAME") and self._parse_column(),
    4128            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
    4129        )
    4130
    4131    # https://duckdb.org/docs/sql/statements/pivot
    4132    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
    4133        def _parse_on() -> t.Optional[exp.Expression]:
    4134            this = self._parse_bitwise()
    4135
    4136            if self._match(TokenType.IN):
    4137                # PIVOT ... ON col IN (row_val1, row_val2)
    4138                return self._parse_in(this)
    4139            if self._match(TokenType.ALIAS, advance=False):
    4140                # UNPIVOT ... ON (col1, col2, col3) AS row_val
    4141                return self._parse_alias(this)
    4142
    4143            return this
    4144
    4145        this = self._parse_table()
    4146        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    4147        into = self._parse_unpivot_columns()
    4148        using = self._match(TokenType.USING) and self._parse_csv(
    4149            lambda: self._parse_alias(self._parse_function())
    4150        )
    4151        group = self._parse_group()
    4152
    4153        return self.expression(
    4154            exp.Pivot,
    4155            this=this,
    4156            expressions=expressions,
    4157            using=using,
    4158            group=group,
    4159            unpivot=is_unpivot,
    4160            into=into,
    4161        )
    4162
    4163    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
    4164        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    4165            this = self._parse_select_or_expression()
    4166
    4167            self._match(TokenType.ALIAS)
    4168            alias = self._parse_bitwise()
    4169            if alias:
    4170                if isinstance(alias, exp.Column) and not alias.db:
    4171                    alias = alias.this
    4172                return self.expression(exp.PivotAlias, this=this, alias=alias)
    4173
    4174            return this
    4175
    4176        value = self._parse_column()
    4177
    4178        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    4179            self.raise_error("Expecting IN (")
    4180
    4181        if self._match(TokenType.ANY):
    4182            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
    4183        else:
    4184            exprs = self._parse_csv(_parse_aliased_expression)
    4185
    4186        self._match_r_paren()
    4187        return self.expression(exp.In, this=value, expressions=exprs)
    4188
    4189    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    4190        index = self._index
    4191        include_nulls = None
    4192
    4193        if self._match(TokenType.PIVOT):
    4194            unpivot = False
    4195        elif self._match(TokenType.UNPIVOT):
    4196            unpivot = True
    4197
    4198            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    4199            if self._match_text_seq("INCLUDE", "NULLS"):
    4200                include_nulls = True
    4201            elif self._match_text_seq("EXCLUDE", "NULLS"):
    4202                include_nulls = False
    4203        else:
    4204            return None
    4205
    4206        expressions = []
    4207
    4208        if not self._match(TokenType.L_PAREN):
    4209            self._retreat(index)
    4210            return None
    4211
    4212        if unpivot:
    4213            expressions = self._parse_csv(self._parse_column)
    4214        else:
    4215            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    4216
    4217        if not expressions:
    4218            self.raise_error("Failed to parse PIVOT's aggregation list")
    4219
    4220        if not self._match(TokenType.FOR):
    4221            self.raise_error("Expecting FOR")
    4222
    4223        field = self._parse_pivot_in()
    4224        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
    4225            self._parse_bitwise
    4226        )
    4227
    4228        self._match_r_paren()
    4229
    4230        pivot = self.expression(
    4231            exp.Pivot,
    4232            expressions=expressions,
    4233            field=field,
    4234            unpivot=unpivot,
    4235            include_nulls=include_nulls,
    4236            default_on_null=default_on_null,
    4237        )
    4238
    4239        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    4240            pivot.set("alias", self._parse_table_alias())
    4241
    4242        if not unpivot:
    4243            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    4244
    4245            columns: t.List[exp.Expression] = []
    4246            pivot_field_expressions = pivot.args["field"].expressions
    4247
    4248            # The `PivotAny` expression corresponds to `ANY ORDER BY <column>`; we can't infer in this case.
    4249            if not isinstance(seq_get(pivot_field_expressions, 0), exp.PivotAny):
    4250                for fld in pivot_field_expressions:
    4251                    field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    4252                    for name in names:
    4253                        if self.PREFIXED_PIVOT_COLUMNS:
    4254                            name = f"{name}_{field_name}" if name else field_name
    4255                        else:
    4256                            name = f"{field_name}_{name}" if name else field_name
    4257
    4258                        columns.append(exp.to_identifier(name))
    4259
    4260            pivot.set("columns", columns)
    4261
    4262        return pivot
    4263
    4264    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    4265        return [agg.alias for agg in aggregations]
    4266
    4267    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    4268        if not skip_where_token and not self._match(TokenType.PREWHERE):
    4269            return None
    4270
    4271        return self.expression(
    4272            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    4273        )
    4274
    4275    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    4276        if not skip_where_token and not self._match(TokenType.WHERE):
    4277            return None
    4278
    4279        return self.expression(
    4280            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    4281        )
    4282
    4283    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    4284        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    4285            return None
    4286
    4287        elements: t.Dict[str, t.Any] = defaultdict(list)
    4288
    4289        if self._match(TokenType.ALL):
    4290            elements["all"] = True
    4291        elif self._match(TokenType.DISTINCT):
    4292            elements["all"] = False
    4293
    4294        while True:
    4295            index = self._index
    4296
    4297            elements["expressions"].extend(
    4298                self._parse_csv(
    4299                    lambda: None
    4300                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
    4301                    else self._parse_assignment()
    4302                )
    4303            )
    4304
    4305            before_with_index = self._index
    4306            with_prefix = self._match(TokenType.WITH)
    4307
    4308            if self._match(TokenType.ROLLUP):
    4309                elements["rollup"].append(
    4310                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
    4311                )
    4312            elif self._match(TokenType.CUBE):
    4313                elements["cube"].append(
    4314                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
    4315                )
    4316            elif self._match(TokenType.GROUPING_SETS):
    4317                elements["grouping_sets"].append(
    4318                    self.expression(
    4319                        exp.GroupingSets,
    4320                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
    4321                    )
    4322                )
    4323            elif self._match_text_seq("TOTALS"):
    4324                elements["totals"] = True  # type: ignore
    4325
    4326            if before_with_index <= self._index <= before_with_index + 1:
    4327                self._retreat(before_with_index)
    4328                break
    4329
    4330            if index == self._index:
    4331                break
    4332
    4333        return self.expression(exp.Group, **elements)  # type: ignore
    4334
    4335    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
    4336        return self.expression(
    4337            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
    4338        )
    4339
    4340    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    4341        if self._match(TokenType.L_PAREN):
    4342            grouping_set = self._parse_csv(self._parse_column)
    4343            self._match_r_paren()
    4344            return self.expression(exp.Tuple, expressions=grouping_set)
    4345
    4346        return self._parse_column()
    4347
    4348    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    4349        if not skip_having_token and not self._match(TokenType.HAVING):
    4350            return None
    4351        return self.expression(exp.Having, this=self._parse_assignment())
    4352
    4353    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    4354        if not self._match(TokenType.QUALIFY):
    4355            return None
    4356        return self.expression(exp.Qualify, this=self._parse_assignment())
    4357
    4358    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    4359        if skip_start_token:
    4360            start = None
    4361        elif self._match(TokenType.START_WITH):
    4362            start = self._parse_assignment()
    4363        else:
    4364            return None
    4365
    4366        self._match(TokenType.CONNECT_BY)
    4367        nocycle = self._match_text_seq("NOCYCLE")
    4368        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    4369            exp.Prior, this=self._parse_bitwise()
    4370        )
    4371        connect = self._parse_assignment()
    4372        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    4373
    4374        if not start and self._match(TokenType.START_WITH):
    4375            start = self._parse_assignment()
    4376
    4377        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    4378
    4379    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
    4380        this = self._parse_id_var(any_token=True)
    4381        if self._match(TokenType.ALIAS):
    4382            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
    4383        return this
    4384
    4385    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    4386        if self._match_text_seq("INTERPOLATE"):
    4387            return self._parse_wrapped_csv(self._parse_name_as_expression)
    4388        return None
    4389
    4390    def _parse_order(
    4391        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    4392    ) -> t.Optional[exp.Expression]:
    4393        siblings = None
    4394        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    4395            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    4396                return this
    4397
    4398            siblings = True
    4399
    4400        return self.expression(
    4401            exp.Order,
    4402            this=this,
    4403            expressions=self._parse_csv(self._parse_ordered),
    4404            siblings=siblings,
    4405        )
    4406
    4407    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    4408        if not self._match(token):
    4409            return None
    4410        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    4411
    4412    def _parse_ordered(
    4413        self, parse_method: t.Optional[t.Callable] = None
    4414    ) -> t.Optional[exp.Ordered]:
    4415        this = parse_method() if parse_method else self._parse_assignment()
    4416        if not this:
    4417            return None
    4418
    4419        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
    4420            this = exp.var("ALL")
    4421
    4422        asc = self._match(TokenType.ASC)
    4423        desc = self._match(TokenType.DESC) or (asc and False)
    4424
    4425        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    4426        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    4427
    4428        nulls_first = is_nulls_first or False
    4429        explicitly_null_ordered = is_nulls_first or is_nulls_last
    4430
    4431        if (
    4432            not explicitly_null_ordered
    4433            and (
    4434                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    4435                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    4436            )
    4437            and self.dialect.NULL_ORDERING != "nulls_are_last"
    4438        ):
    4439            nulls_first = True
    4440
    4441        if self._match_text_seq("WITH", "FILL"):
    4442            with_fill = self.expression(
    4443                exp.WithFill,
    4444                **{  # type: ignore
    4445                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    4446                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    4447                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    4448                    "interpolate": self._parse_interpolate(),
    4449                },
    4450            )
    4451        else:
    4452            with_fill = None
    4453
    4454        return self.expression(
    4455            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    4456        )
    4457
    4458    def _parse_limit_options(self) -> exp.LimitOptions:
    4459        percent = self._match(TokenType.PERCENT)
    4460        rows = self._match_set((TokenType.ROW, TokenType.ROWS))
    4461        self._match_text_seq("ONLY")
    4462        with_ties = self._match_text_seq("WITH", "TIES")
    4463        return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
    4464
    4465    def _parse_limit(
    4466        self,
    4467        this: t.Optional[exp.Expression] = None,
    4468        top: bool = False,
    4469        skip_limit_token: bool = False,
    4470    ) -> t.Optional[exp.Expression]:
    4471        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    4472            comments = self._prev_comments
    4473            if top:
    4474                limit_paren = self._match(TokenType.L_PAREN)
    4475                expression = self._parse_term() if limit_paren else self._parse_number()
    4476
    4477                if limit_paren:
    4478                    self._match_r_paren()
    4479
    4480                limit_options = self._parse_limit_options()
    4481            else:
    4482                limit_options = None
    4483                expression = self._parse_term()
    4484
    4485            if self._match(TokenType.COMMA):
    4486                offset = expression
    4487                expression = self._parse_term()
    4488            else:
    4489                offset = None
    4490
    4491            limit_exp = self.expression(
    4492                exp.Limit,
    4493                this=this,
    4494                expression=expression,
    4495                offset=offset,
    4496                comments=comments,
    4497                limit_options=limit_options,
    4498                expressions=self._parse_limit_by(),
    4499            )
    4500
    4501            return limit_exp
    4502
    4503        if self._match(TokenType.FETCH):
    4504            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    4505            direction = self._prev.text.upper() if direction else "FIRST"
    4506
    4507            count = self._parse_field(tokens=self.FETCH_TOKENS)
    4508
    4509            return self.expression(
    4510                exp.Fetch,
    4511                direction=direction,
    4512                count=count,
    4513                limit_options=self._parse_limit_options(),
    4514            )
    4515
    4516        return this
    4517
    4518    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4519        if not self._match(TokenType.OFFSET):
    4520            return this
    4521
    4522        count = self._parse_term()
    4523        self._match_set((TokenType.ROW, TokenType.ROWS))
    4524
    4525        return self.expression(
    4526            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    4527        )
    4528
    4529    def _can_parse_limit_or_offset(self) -> bool:
    4530        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
    4531            return False
    4532
    4533        index = self._index
    4534        result = bool(
    4535            self._try_parse(self._parse_limit, retreat=True)
    4536            or self._try_parse(self._parse_offset, retreat=True)
    4537        )
    4538        self._retreat(index)
    4539        return result
    4540
    4541    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    4542        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    4543
    4544    def _parse_locks(self) -> t.List[exp.Lock]:
    4545        locks = []
    4546        while True:
    4547            if self._match_text_seq("FOR", "UPDATE"):
    4548                update = True
    4549            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    4550                "LOCK", "IN", "SHARE", "MODE"
    4551            ):
    4552                update = False
    4553            else:
    4554                break
    4555
    4556            expressions = None
    4557            if self._match_text_seq("OF"):
    4558                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    4559
    4560            wait: t.Optional[bool | exp.Expression] = None
    4561            if self._match_text_seq("NOWAIT"):
    4562                wait = True
    4563            elif self._match_text_seq("WAIT"):
    4564                wait = self._parse_primary()
    4565            elif self._match_text_seq("SKIP", "LOCKED"):
    4566                wait = False
    4567
    4568            locks.append(
    4569                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    4570            )
    4571
    4572        return locks
    4573
    4574    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4575        while this and self._match_set(self.SET_OPERATIONS):
    4576            token_type = self._prev.token_type
    4577
    4578            if token_type == TokenType.UNION:
    4579                operation: t.Type[exp.SetOperation] = exp.Union
    4580            elif token_type == TokenType.EXCEPT:
    4581                operation = exp.Except
    4582            else:
    4583                operation = exp.Intersect
    4584
    4585            comments = self._prev.comments
    4586
    4587            if self._match(TokenType.DISTINCT):
    4588                distinct: t.Optional[bool] = True
    4589            elif self._match(TokenType.ALL):
    4590                distinct = False
    4591            else:
    4592                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4593                if distinct is None:
    4594                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4595
    4596            by_name = self._match_text_seq("BY", "NAME")
    4597            expression = self._parse_select(nested=True, parse_set_operation=False)
    4598
    4599            this = self.expression(
    4600                operation,
    4601                comments=comments,
    4602                this=this,
    4603                distinct=distinct,
    4604                by_name=by_name,
    4605                expression=expression,
    4606            )
    4607
    4608        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
    4609            expression = this.expression
    4610
    4611            if expression:
    4612                for arg in self.SET_OP_MODIFIERS:
    4613                    expr = expression.args.get(arg)
    4614                    if expr:
    4615                        this.set(arg, expr.pop())
    4616
    4617        return this
    4618
    4619    def _parse_expression(self) -> t.Optional[exp.Expression]:
    4620        return self._parse_alias(self._parse_assignment())
    4621
    4622    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    4623        this = self._parse_disjunction()
    4624        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
    4625            # This allows us to parse <non-identifier token> := <expr>
    4626            this = exp.column(
    4627                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
    4628            )
    4629
    4630        while self._match_set(self.ASSIGNMENT):
    4631            if isinstance(this, exp.Column) and len(this.parts) == 1:
    4632                this = this.this
    4633
    4634            this = self.expression(
    4635                self.ASSIGNMENT[self._prev.token_type],
    4636                this=this,
    4637                comments=self._prev_comments,
    4638                expression=self._parse_assignment(),
    4639            )
    4640
    4641        return this
    4642
    4643    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4644        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4645
    4646    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4647        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4648
    4649    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4650        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4651
    4652    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4653        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4654
    4655    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4656        this = this or self._parse_bitwise()
    4657        negate = self._match(TokenType.NOT)
    4658
    4659        if self._match_set(self.RANGE_PARSERS):
    4660            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4661            if not expression:
    4662                return this
    4663
    4664            this = expression
    4665        elif self._match(TokenType.ISNULL):
    4666            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4667
    4668        # Postgres supports ISNULL and NOTNULL for conditions.
    4669        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4670        if self._match(TokenType.NOTNULL):
    4671            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4672            this = self.expression(exp.Not, this=this)
    4673
    4674        if negate:
    4675            this = self._negate_range(this)
    4676
    4677        if self._match(TokenType.IS):
    4678            this = self._parse_is(this)
    4679
    4680        return this
    4681
    4682    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4683        if not this:
    4684            return this
    4685
    4686        return self.expression(exp.Not, this=this)
    4687
    4688    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4689        index = self._index - 1
    4690        negate = self._match(TokenType.NOT)
    4691
    4692        if self._match_text_seq("DISTINCT", "FROM"):
    4693            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4694            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4695
    4696        if self._match(TokenType.JSON):
    4697            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
    4698
    4699            if self._match_text_seq("WITH"):
    4700                _with = True
    4701            elif self._match_text_seq("WITHOUT"):
    4702                _with = False
    4703            else:
    4704                _with = None
    4705
    4706            unique = self._match(TokenType.UNIQUE)
    4707            self._match_text_seq("KEYS")
    4708            expression: t.Optional[exp.Expression] = self.expression(
    4709                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
    4710            )
    4711        else:
    4712            expression = self._parse_primary() or self._parse_null()
    4713            if not expression:
    4714                self._retreat(index)
    4715                return None
    4716
    4717        this = self.expression(exp.Is, this=this, expression=expression)
    4718        return self.expression(exp.Not, this=this) if negate else this
    4719
    4720    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4721        unnest = self._parse_unnest(with_alias=False)
    4722        if unnest:
    4723            this = self.expression(exp.In, this=this, unnest=unnest)
    4724        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4725            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4726            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4727
    4728            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4729                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4730            else:
    4731                this = self.expression(exp.In, this=this, expressions=expressions)
    4732
    4733            if matched_l_paren:
    4734                self._match_r_paren(this)
    4735            elif not self._match(TokenType.R_BRACKET, expression=this):
    4736                self.raise_error("Expecting ]")
    4737        else:
    4738            this = self.expression(exp.In, this=this, field=self._parse_column())
    4739
    4740        return this
    4741
    4742    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4743        low = self._parse_bitwise()
    4744        self._match(TokenType.AND)
    4745        high = self._parse_bitwise()
    4746        return self.expression(exp.Between, this=this, low=low, high=high)
    4747
    4748    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4749        if not self._match(TokenType.ESCAPE):
    4750            return this
    4751        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4752
    4753    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4754        index = self._index
    4755
    4756        if not self._match(TokenType.INTERVAL) and match_interval:
    4757            return None
    4758
    4759        if self._match(TokenType.STRING, advance=False):
    4760            this = self._parse_primary()
    4761        else:
    4762            this = self._parse_term()
    4763
    4764        if not this or (
    4765            isinstance(this, exp.Column)
    4766            and not this.table
    4767            and not this.this.quoted
    4768            and this.name.upper() == "IS"
    4769        ):
    4770            self._retreat(index)
    4771            return None
    4772
    4773        unit = self._parse_function() or (
    4774            not self._match(TokenType.ALIAS, advance=False)
    4775            and self._parse_var(any_token=True, upper=True)
    4776        )
    4777
    4778        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4779        # each INTERVAL expression into this canonical form so it's easy to transpile
    4780        if this and this.is_number:
    4781            this = exp.Literal.string(this.to_py())
    4782        elif this and this.is_string:
    4783            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4784            if parts and unit:
    4785                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4786                unit = None
    4787                self._retreat(self._index - 1)
    4788
    4789            if len(parts) == 1:
    4790                this = exp.Literal.string(parts[0][0])
    4791                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4792        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4793            unit = self.expression(
    4794                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4795            )
    4796
    4797        interval = self.expression(exp.Interval, this=this, unit=unit)
    4798
    4799        index = self._index
    4800        self._match(TokenType.PLUS)
    4801
    4802        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4803        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4804            return self.expression(
    4805                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4806            )
    4807
    4808        self._retreat(index)
    4809        return interval
    4810
    4811    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4812        this = self._parse_term()
    4813
    4814        while True:
    4815            if self._match_set(self.BITWISE):
    4816                this = self.expression(
    4817                    self.BITWISE[self._prev.token_type],
    4818                    this=this,
    4819                    expression=self._parse_term(),
    4820                )
    4821            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4822                this = self.expression(
    4823                    exp.DPipe,
    4824                    this=this,
    4825                    expression=self._parse_term(),
    4826                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4827                )
    4828            elif self._match(TokenType.DQMARK):
    4829                this = self.expression(
    4830                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
    4831                )
    4832            elif self._match_pair(TokenType.LT, TokenType.LT):
    4833                this = self.expression(
    4834                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4835                )
    4836            elif self._match_pair(TokenType.GT, TokenType.GT):
    4837                this = self.expression(
    4838                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4839                )
    4840            else:
    4841                break
    4842
    4843        return this
    4844
    4845    def _parse_term(self) -> t.Optional[exp.Expression]:
    4846        this = self._parse_factor()
    4847
    4848        while self._match_set(self.TERM):
    4849            klass = self.TERM[self._prev.token_type]
    4850            comments = self._prev_comments
    4851            expression = self._parse_factor()
    4852
    4853            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4854
    4855            if isinstance(this, exp.Collate):
    4856                expr = this.expression
    4857
    4858                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
    4859                # fallback to Identifier / Var
    4860                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
    4861                    ident = expr.this
    4862                    if isinstance(ident, exp.Identifier):
    4863                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
    4864
    4865        return this
    4866
    4867    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4868        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4869        this = parse_method()
    4870
    4871        while self._match_set(self.FACTOR):
    4872            klass = self.FACTOR[self._prev.token_type]
    4873            comments = self._prev_comments
    4874            expression = parse_method()
    4875
    4876            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4877                self._retreat(self._index - 1)
    4878                return this
    4879
    4880            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4881
    4882            if isinstance(this, exp.Div):
    4883                this.args["typed"] = self.dialect.TYPED_DIVISION
    4884                this.args["safe"] = self.dialect.SAFE_DIVISION
    4885
    4886        return this
    4887
    4888    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    4889        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    4890
    4891    def _parse_unary(self) -> t.Optional[exp.Expression]:
    4892        if self._match_set(self.UNARY_PARSERS):
    4893            return self.UNARY_PARSERS[self._prev.token_type](self)
    4894        return self._parse_at_time_zone(self._parse_type())
    4895
    4896    def _parse_type(
    4897        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    4898    ) -> t.Optional[exp.Expression]:
    4899        interval = parse_interval and self._parse_interval()
    4900        if interval:
    4901            return interval
    4902
    4903        index = self._index
    4904        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    4905
    4906        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
    4907        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
    4908        if isinstance(data_type, exp.Cast):
    4909            # This constructor can contain ops directly after it, for instance struct unnesting:
    4910            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
    4911            return self._parse_column_ops(data_type)
    4912
    4913        if data_type:
    4914            index2 = self._index
    4915            this = self._parse_primary()
    4916
    4917            if isinstance(this, exp.Literal):
    4918                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    4919                if parser:
    4920                    return parser(self, this, data_type)
    4921
    4922                return self.expression(exp.Cast, this=this, to=data_type)
    4923
    4924            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    4925            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    4926            #
    4927            # If the index difference here is greater than 1, that means the parser itself must have
    4928            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    4929            #
    4930            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    4931            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    4932            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    4933            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    4934            #
    4935            # In these cases, we don't really want to return the converted type, but instead retreat
    4936            # and try to parse a Column or Identifier in the section below.
    4937            if data_type.expressions and index2 - index > 1:
    4938                self._retreat(index2)
    4939                return self._parse_column_ops(data_type)
    4940
    4941            self._retreat(index)
    4942
    4943        if fallback_to_identifier:
    4944            return self._parse_id_var()
    4945
    4946        this = self._parse_column()
    4947        return this and self._parse_column_ops(this)
    4948
    4949    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    4950        this = self._parse_type()
    4951        if not this:
    4952            return None
    4953
    4954        if isinstance(this, exp.Column) and not this.table:
    4955            this = exp.var(this.name.upper())
    4956
    4957        return self.expression(
    4958            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    4959        )
    4960
    4961    def _parse_types(
    4962        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    4963    ) -> t.Optional[exp.Expression]:
    4964        index = self._index
    4965
    4966        this: t.Optional[exp.Expression] = None
    4967        prefix = self._match_text_seq("SYSUDTLIB", ".")
    4968
    4969        if not self._match_set(self.TYPE_TOKENS):
    4970            identifier = allow_identifiers and self._parse_id_var(
    4971                any_token=False, tokens=(TokenType.VAR,)
    4972            )
    4973            if isinstance(identifier, exp.Identifier):
    4974                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
    4975
    4976                if len(tokens) != 1:
    4977                    self.raise_error("Unexpected identifier", self._prev)
    4978
    4979                if tokens[0].token_type in self.TYPE_TOKENS:
    4980                    self._prev = tokens[0]
    4981                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    4982                    type_name = identifier.name
    4983
    4984                    while self._match(TokenType.DOT):
    4985                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    4986
    4987                    this = exp.DataType.build(type_name, udt=True)
    4988                else:
    4989                    self._retreat(self._index - 1)
    4990                    return None
    4991            else:
    4992                return None
    4993
    4994        type_token = self._prev.token_type
    4995
    4996        if type_token == TokenType.PSEUDO_TYPE:
    4997            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    4998
    4999        if type_token == TokenType.OBJECT_IDENTIFIER:
    5000            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    5001
    5002        # https://materialize.com/docs/sql/types/map/
    5003        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    5004            key_type = self._parse_types(
    5005                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5006            )
    5007            if not self._match(TokenType.FARROW):
    5008                self._retreat(index)
    5009                return None
    5010
    5011            value_type = self._parse_types(
    5012                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5013            )
    5014            if not self._match(TokenType.R_BRACKET):
    5015                self._retreat(index)
    5016                return None
    5017
    5018            return exp.DataType(
    5019                this=exp.DataType.Type.MAP,
    5020                expressions=[key_type, value_type],
    5021                nested=True,
    5022                prefix=prefix,
    5023            )
    5024
    5025        nested = type_token in self.NESTED_TYPE_TOKENS
    5026        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    5027        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    5028        expressions = None
    5029        maybe_func = False
    5030
    5031        if self._match(TokenType.L_PAREN):
    5032            if is_struct:
    5033                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5034            elif nested:
    5035                expressions = self._parse_csv(
    5036                    lambda: self._parse_types(
    5037                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5038                    )
    5039                )
    5040                if type_token == TokenType.NULLABLE and len(expressions) == 1:
    5041                    this = expressions[0]
    5042                    this.set("nullable", True)
    5043                    self._match_r_paren()
    5044                    return this
    5045            elif type_token in self.ENUM_TYPE_TOKENS:
    5046                expressions = self._parse_csv(self._parse_equality)
    5047            elif is_aggregate:
    5048                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    5049                    any_token=False, tokens=(TokenType.VAR, TokenType.ANY)
    5050                )
    5051                if not func_or_ident:
    5052                    return None
    5053                expressions = [func_or_ident]
    5054                if self._match(TokenType.COMMA):
    5055                    expressions.extend(
    5056                        self._parse_csv(
    5057                            lambda: self._parse_types(
    5058                                check_func=check_func,
    5059                                schema=schema,
    5060                                allow_identifiers=allow_identifiers,
    5061                            )
    5062                        )
    5063                    )
    5064            else:
    5065                expressions = self._parse_csv(self._parse_type_size)
    5066
    5067                # https://docs.snowflake.com/en/sql-reference/data-types-vector
    5068                if type_token == TokenType.VECTOR and len(expressions) == 2:
    5069                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
    5070
    5071            if not expressions or not self._match(TokenType.R_PAREN):
    5072                self._retreat(index)
    5073                return None
    5074
    5075            maybe_func = True
    5076
    5077        values: t.Optional[t.List[exp.Expression]] = None
    5078
    5079        if nested and self._match(TokenType.LT):
    5080            if is_struct:
    5081                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5082            else:
    5083                expressions = self._parse_csv(
    5084                    lambda: self._parse_types(
    5085                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5086                    )
    5087                )
    5088
    5089            if not self._match(TokenType.GT):
    5090                self.raise_error("Expecting >")
    5091
    5092            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    5093                values = self._parse_csv(self._parse_assignment)
    5094                if not values and is_struct:
    5095                    values = None
    5096                    self._retreat(self._index - 1)
    5097                else:
    5098                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    5099
    5100        if type_token in self.TIMESTAMPS:
    5101            if self._match_text_seq("WITH", "TIME", "ZONE"):
    5102                maybe_func = False
    5103                tz_type = (
    5104                    exp.DataType.Type.TIMETZ
    5105                    if type_token in self.TIMES
    5106                    else exp.DataType.Type.TIMESTAMPTZ
    5107                )
    5108                this = exp.DataType(this=tz_type, expressions=expressions)
    5109            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    5110                maybe_func = False
    5111                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    5112            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    5113                maybe_func = False
    5114        elif type_token == TokenType.INTERVAL:
    5115            unit = self._parse_var(upper=True)
    5116            if unit:
    5117                if self._match_text_seq("TO"):
    5118                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    5119
    5120                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    5121            else:
    5122                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    5123
    5124        if maybe_func and check_func:
    5125            index2 = self._index
    5126            peek = self._parse_string()
    5127
    5128            if not peek:
    5129                self._retreat(index)
    5130                return None
    5131
    5132            self._retreat(index2)
    5133
    5134        if not this:
    5135            if self._match_text_seq("UNSIGNED"):
    5136                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    5137                if not unsigned_type_token:
    5138                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    5139
    5140                type_token = unsigned_type_token or type_token
    5141
    5142            this = exp.DataType(
    5143                this=exp.DataType.Type[type_token.value],
    5144                expressions=expressions,
    5145                nested=nested,
    5146                prefix=prefix,
    5147            )
    5148
    5149            # Empty arrays/structs are allowed
    5150            if values is not None:
    5151                cls = exp.Struct if is_struct else exp.Array
    5152                this = exp.cast(cls(expressions=values), this, copy=False)
    5153
    5154        elif expressions:
    5155            this.set("expressions", expressions)
    5156
    5157        # https://materialize.com/docs/sql/types/list/#type-name
    5158        while self._match(TokenType.LIST):
    5159            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    5160
    5161        index = self._index
    5162
    5163        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    5164        matched_array = self._match(TokenType.ARRAY)
    5165
    5166        while self._curr:
    5167            datatype_token = self._prev.token_type
    5168            matched_l_bracket = self._match(TokenType.L_BRACKET)
    5169
    5170            if (not matched_l_bracket and not matched_array) or (
    5171                datatype_token == TokenType.ARRAY and self._match(TokenType.R_BRACKET)
    5172            ):
    5173                # Postgres allows casting empty arrays such as ARRAY[]::INT[],
    5174                # not to be confused with the fixed size array parsing
    5175                break
    5176
    5177            matched_array = False
    5178            values = self._parse_csv(self._parse_assignment) or None
    5179            if (
    5180                values
    5181                and not schema
    5182                and (
    5183                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
    5184                )
    5185            ):
    5186                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
    5187                # ARRAY[1] should retreat and instead be parsed into exp.Array in contrast to INT[x][y] which denotes a fixed-size array data type
    5188                self._retreat(index)
    5189                break
    5190
    5191            this = exp.DataType(
    5192                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    5193            )
    5194            self._match(TokenType.R_BRACKET)
    5195
    5196        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
    5197            converter = self.TYPE_CONVERTERS.get(this.this)
    5198            if converter:
    5199                this = converter(t.cast(exp.DataType, this))
    5200
    5201        return this
    5202
    5203    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    5204        index = self._index
    5205
    5206        if (
    5207            self._curr
    5208            and self._next
    5209            and self._curr.token_type in self.TYPE_TOKENS
    5210            and self._next.token_type in self.TYPE_TOKENS
    5211        ):
    5212            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
    5213            # type token. Without this, the list will be parsed as a type and we'll eventually crash
    5214            this = self._parse_id_var()
    5215        else:
    5216            this = (
    5217                self._parse_type(parse_interval=False, fallback_to_identifier=True)
    5218                or self._parse_id_var()
    5219            )
    5220
    5221        self._match(TokenType.COLON)
    5222
    5223        if (
    5224            type_required
    5225            and not isinstance(this, exp.DataType)
    5226            and not self._match_set(self.TYPE_TOKENS, advance=False)
    5227        ):
    5228            self._retreat(index)
    5229            return self._parse_types()
    5230
    5231        return self._parse_column_def(this)
    5232
    5233    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5234        if not self._match_text_seq("AT", "TIME", "ZONE"):
    5235            return this
    5236        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    5237
    5238    def _parse_column(self) -> t.Optional[exp.Expression]:
    5239        this = self._parse_column_reference()
    5240        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
    5241
    5242        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
    5243            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
    5244
    5245        return column
    5246
    5247    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    5248        this = self._parse_field()
    5249        if (
    5250            not this
    5251            and self._match(TokenType.VALUES, advance=False)
    5252            and self.VALUES_FOLLOWED_BY_PAREN
    5253            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    5254        ):
    5255            this = self._parse_id_var()
    5256
    5257        if isinstance(this, exp.Identifier):
    5258            # We bubble up comments from the Identifier to the Column
    5259            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    5260
    5261        return this
    5262
    5263    def _parse_colon_as_variant_extract(
    5264        self, this: t.Optional[exp.Expression]
    5265    ) -> t.Optional[exp.Expression]:
    5266        casts = []
    5267        json_path = []
    5268        escape = None
    5269
    5270        while self._match(TokenType.COLON):
    5271            start_index = self._index
    5272
    5273            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
    5274            path = self._parse_column_ops(
    5275                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
    5276            )
    5277
    5278            # The cast :: operator has a lower precedence than the extraction operator :, so
    5279            # we rearrange the AST appropriately to avoid casting the JSON path
    5280            while isinstance(path, exp.Cast):
    5281                casts.append(path.to)
    5282                path = path.this
    5283
    5284            if casts:
    5285                dcolon_offset = next(
    5286                    i
    5287                    for i, t in enumerate(self._tokens[start_index:])
    5288                    if t.token_type == TokenType.DCOLON
    5289                )
    5290                end_token = self._tokens[start_index + dcolon_offset - 1]
    5291            else:
    5292                end_token = self._prev
    5293
    5294            if path:
    5295                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
    5296                # it'll roundtrip to a string literal in GET_PATH
    5297                if isinstance(path, exp.Identifier) and path.quoted:
    5298                    escape = True
    5299
    5300                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    5301
    5302        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
    5303        # Databricks transforms it back to the colon/dot notation
    5304        if json_path:
    5305            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
    5306
    5307            if json_path_expr:
    5308                json_path_expr.set("escape", escape)
    5309
    5310            this = self.expression(
    5311                exp.JSONExtract,
    5312                this=this,
    5313                expression=json_path_expr,
    5314                variant_extract=True,
    5315            )
    5316
    5317            while casts:
    5318                this = self.expression(exp.Cast, this=this, to=casts.pop())
    5319
    5320        return this
    5321
    5322    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
    5323        return self._parse_types()
    5324
    5325    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5326        this = self._parse_bracket(this)
    5327
    5328        while self._match_set(self.COLUMN_OPERATORS):
    5329            op_token = self._prev.token_type
    5330            op = self.COLUMN_OPERATORS.get(op_token)
    5331
    5332            if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
    5333                field = self._parse_dcolon()
    5334                if not field:
    5335                    self.raise_error("Expected type")
    5336            elif op and self._curr:
    5337                field = self._parse_column_reference() or self._parse_bracket()
    5338            else:
    5339                field = self._parse_field(any_token=True, anonymous_func=True)
    5340
    5341            if isinstance(field, (exp.Func, exp.Window)) and this:
    5342                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
    5343                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    5344                this = exp.replace_tree(
    5345                    this,
    5346                    lambda n: (
    5347                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    5348                        if n.table
    5349                        else n.this
    5350                    )
    5351                    if isinstance(n, exp.Column)
    5352                    else n,
    5353                )
    5354
    5355            if op:
    5356                this = op(self, this, field)
    5357            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    5358                this = self.expression(
    5359                    exp.Column,
    5360                    comments=this.comments,
    5361                    this=field,
    5362                    table=this.this,
    5363                    db=this.args.get("table"),
    5364                    catalog=this.args.get("db"),
    5365                )
    5366            elif isinstance(field, exp.Window):
    5367                # Move the exp.Dot's to the window's function
    5368                window_func = self.expression(exp.Dot, this=this, expression=field.this)
    5369                field.set("this", window_func)
    5370                this = field
    5371            else:
    5372                this = self.expression(exp.Dot, this=this, expression=field)
    5373
    5374            if field and field.comments:
    5375                t.cast(exp.Expression, this).add_comments(field.pop_comments())
    5376
    5377            this = self._parse_bracket(this)
    5378
    5379        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
    5380
    5381    def _parse_primary(self) -> t.Optional[exp.Expression]:
    5382        if self._match_set(self.PRIMARY_PARSERS):
    5383            token_type = self._prev.token_type
    5384            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    5385
    5386            if token_type == TokenType.STRING:
    5387                expressions = [primary]
    5388                while self._match(TokenType.STRING):
    5389                    expressions.append(exp.Literal.string(self._prev.text))
    5390
    5391                if len(expressions) > 1:
    5392                    return self.expression(exp.Concat, expressions=expressions)
    5393
    5394            return primary
    5395
    5396        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    5397            return exp.Literal.number(f"0.{self._prev.text}")
    5398
    5399        if self._match(TokenType.L_PAREN):
    5400            comments = self._prev_comments
    5401            query = self._parse_select()
    5402
    5403            if query:
    5404                expressions = [query]
    5405            else:
    5406                expressions = self._parse_expressions()
    5407
    5408            this = self._parse_query_modifiers(seq_get(expressions, 0))
    5409
    5410            if not this and self._match(TokenType.R_PAREN, advance=False):
    5411                this = self.expression(exp.Tuple)
    5412            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    5413                this = self._parse_subquery(this=this, parse_alias=False)
    5414            elif isinstance(this, exp.Subquery):
    5415                this = self._parse_subquery(
    5416                    this=self._parse_set_operations(this), parse_alias=False
    5417                )
    5418            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    5419                this = self.expression(exp.Tuple, expressions=expressions)
    5420            else:
    5421                this = self.expression(exp.Paren, this=this)
    5422
    5423            if this:
    5424                this.add_comments(comments)
    5425
    5426            self._match_r_paren(expression=this)
    5427            return this
    5428
    5429        return None
    5430
    5431    def _parse_field(
    5432        self,
    5433        any_token: bool = False,
    5434        tokens: t.Optional[t.Collection[TokenType]] = None,
    5435        anonymous_func: bool = False,
    5436    ) -> t.Optional[exp.Expression]:
    5437        if anonymous_func:
    5438            field = (
    5439                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    5440                or self._parse_primary()
    5441            )
    5442        else:
    5443            field = self._parse_primary() or self._parse_function(
    5444                anonymous=anonymous_func, any_token=any_token
    5445            )
    5446        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    5447
    5448    def _parse_function(
    5449        self,
    5450        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5451        anonymous: bool = False,
    5452        optional_parens: bool = True,
    5453        any_token: bool = False,
    5454    ) -> t.Optional[exp.Expression]:
    5455        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    5456        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    5457        fn_syntax = False
    5458        if (
    5459            self._match(TokenType.L_BRACE, advance=False)
    5460            and self._next
    5461            and self._next.text.upper() == "FN"
    5462        ):
    5463            self._advance(2)
    5464            fn_syntax = True
    5465
    5466        func = self._parse_function_call(
    5467            functions=functions,
    5468            anonymous=anonymous,
    5469            optional_parens=optional_parens,
    5470            any_token=any_token,
    5471        )
    5472
    5473        if fn_syntax:
    5474            self._match(TokenType.R_BRACE)
    5475
    5476        return func
    5477
    5478    def _parse_function_call(
    5479        self,
    5480        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5481        anonymous: bool = False,
    5482        optional_parens: bool = True,
    5483        any_token: bool = False,
    5484    ) -> t.Optional[exp.Expression]:
    5485        if not self._curr:
    5486            return None
    5487
    5488        comments = self._curr.comments
    5489        token_type = self._curr.token_type
    5490        this = self._curr.text
    5491        upper = this.upper()
    5492
    5493        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    5494        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    5495            self._advance()
    5496            return self._parse_window(parser(self))
    5497
    5498        if not self._next or self._next.token_type != TokenType.L_PAREN:
    5499            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    5500                self._advance()
    5501                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    5502
    5503            return None
    5504
    5505        if any_token:
    5506            if token_type in self.RESERVED_TOKENS:
    5507                return None
    5508        elif token_type not in self.FUNC_TOKENS:
    5509            return None
    5510
    5511        self._advance(2)
    5512
    5513        parser = self.FUNCTION_PARSERS.get(upper)
    5514        if parser and not anonymous:
    5515            this = parser(self)
    5516        else:
    5517            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    5518
    5519            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    5520                this = self.expression(
    5521                    subquery_predicate, comments=comments, this=self._parse_select()
    5522                )
    5523                self._match_r_paren()
    5524                return this
    5525
    5526            if functions is None:
    5527                functions = self.FUNCTIONS
    5528
    5529            function = functions.get(upper)
    5530            known_function = function and not anonymous
    5531
    5532            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    5533            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    5534
    5535            post_func_comments = self._curr and self._curr.comments
    5536            if known_function and post_func_comments:
    5537                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
    5538                # call we'll construct it as exp.Anonymous, even if it's "known"
    5539                if any(
    5540                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
    5541                    for comment in post_func_comments
    5542                ):
    5543                    known_function = False
    5544
    5545            if alias and known_function:
    5546                args = self._kv_to_prop_eq(args)
    5547
    5548            if known_function:
    5549                func_builder = t.cast(t.Callable, function)
    5550
    5551                if "dialect" in func_builder.__code__.co_varnames:
    5552                    func = func_builder(args, dialect=self.dialect)
    5553                else:
    5554                    func = func_builder(args)
    5555
    5556                func = self.validate_expression(func, args)
    5557                if self.dialect.PRESERVE_ORIGINAL_NAMES:
    5558                    func.meta["name"] = this
    5559
    5560                this = func
    5561            else:
    5562                if token_type == TokenType.IDENTIFIER:
    5563                    this = exp.Identifier(this=this, quoted=True)
    5564                this = self.expression(exp.Anonymous, this=this, expressions=args)
    5565
    5566        if isinstance(this, exp.Expression):
    5567            this.add_comments(comments)
    5568
    5569        self._match_r_paren(this)
    5570        return self._parse_window(this)
    5571
    5572    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
    5573        return expression
    5574
    5575    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    5576        transformed = []
    5577
    5578        for index, e in enumerate(expressions):
    5579            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    5580                if isinstance(e, exp.Alias):
    5581                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    5582
    5583                if not isinstance(e, exp.PropertyEQ):
    5584                    e = self.expression(
    5585                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    5586                    )
    5587
    5588                if isinstance(e.this, exp.Column):
    5589                    e.this.replace(e.this.this)
    5590            else:
    5591                e = self._to_prop_eq(e, index)
    5592
    5593            transformed.append(e)
    5594
    5595        return transformed
    5596
    5597    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
    5598        return self._parse_statement()
    5599
    5600    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    5601        return self._parse_column_def(this=self._parse_id_var(), computed_column=False)
    5602
    5603    def _parse_user_defined_function(
    5604        self, kind: t.Optional[TokenType] = None
    5605    ) -> t.Optional[exp.Expression]:
    5606        this = self._parse_id_var()
    5607
    5608        while self._match(TokenType.DOT):
    5609            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    5610
    5611        if not self._match(TokenType.L_PAREN):
    5612            return this
    5613
    5614        expressions = self._parse_csv(self._parse_function_parameter)
    5615        self._match_r_paren()
    5616        return self.expression(
    5617            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    5618        )
    5619
    5620    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    5621        literal = self._parse_primary()
    5622        if literal:
    5623            return self.expression(exp.Introducer, this=token.text, expression=literal)
    5624
    5625        return self.expression(exp.Identifier, this=token.text)
    5626
    5627    def _parse_session_parameter(self) -> exp.SessionParameter:
    5628        kind = None
    5629        this = self._parse_id_var() or self._parse_primary()
    5630
    5631        if this and self._match(TokenType.DOT):
    5632            kind = this.name
    5633            this = self._parse_var() or self._parse_primary()
    5634
    5635        return self.expression(exp.SessionParameter, this=this, kind=kind)
    5636
    5637    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    5638        return self._parse_id_var()
    5639
    5640    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5641        index = self._index
    5642
    5643        if self._match(TokenType.L_PAREN):
    5644            expressions = t.cast(
    5645                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    5646            )
    5647
    5648            if not self._match(TokenType.R_PAREN):
    5649                self._retreat(index)
    5650        else:
    5651            expressions = [self._parse_lambda_arg()]
    5652
    5653        if self._match_set(self.LAMBDAS):
    5654            return self.LAMBDAS[self._prev.token_type](self, expressions)
    5655
    5656        self._retreat(index)
    5657
    5658        this: t.Optional[exp.Expression]
    5659
    5660        if self._match(TokenType.DISTINCT):
    5661            this = self.expression(
    5662                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    5663            )
    5664        else:
    5665            this = self._parse_select_or_expression(alias=alias)
    5666
    5667        return self._parse_limit(
    5668            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    5669        )
    5670
    5671    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5672        index = self._index
    5673        if not self._match(TokenType.L_PAREN):
    5674            return this
    5675
    5676        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    5677        # expr can be of both types
    5678        if self._match_set(self.SELECT_START_TOKENS):
    5679            self._retreat(index)
    5680            return this
    5681        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    5682        self._match_r_paren()
    5683        return self.expression(exp.Schema, this=this, expressions=args)
    5684
    5685    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    5686        return self._parse_column_def(self._parse_field(any_token=True))
    5687
    5688    def _parse_column_def(
    5689        self, this: t.Optional[exp.Expression], computed_column: bool = True
    5690    ) -> t.Optional[exp.Expression]:
    5691        # column defs are not really columns, they're identifiers
    5692        if isinstance(this, exp.Column):
    5693            this = this.this
    5694
    5695        if not computed_column:
    5696            self._match(TokenType.ALIAS)
    5697
    5698        kind = self._parse_types(schema=True)
    5699
    5700        if self._match_text_seq("FOR", "ORDINALITY"):
    5701            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    5702
    5703        constraints: t.List[exp.Expression] = []
    5704
    5705        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    5706            ("ALIAS", "MATERIALIZED")
    5707        ):
    5708            persisted = self._prev.text.upper() == "MATERIALIZED"
    5709            constraint_kind = exp.ComputedColumnConstraint(
    5710                this=self._parse_assignment(),
    5711                persisted=persisted or self._match_text_seq("PERSISTED"),
    5712                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    5713            )
    5714            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
    5715        elif (
    5716            kind
    5717            and self._match(TokenType.ALIAS, advance=False)
    5718            and (
    5719                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
    5720                or (self._next and self._next.token_type == TokenType.L_PAREN)
    5721            )
    5722        ):
    5723            self._advance()
    5724            constraints.append(
    5725                self.expression(
    5726                    exp.ColumnConstraint,
    5727                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
    5728                )
    5729            )
    5730
    5731        while True:
    5732            constraint = self._parse_column_constraint()
    5733            if not constraint:
    5734                break
    5735            constraints.append(constraint)
    5736
    5737        if not kind and not constraints:
    5738            return this
    5739
    5740        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    5741
    5742    def _parse_auto_increment(
    5743        self,
    5744    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    5745        start = None
    5746        increment = None
    5747
    5748        if self._match(TokenType.L_PAREN, advance=False):
    5749            args = self._parse_wrapped_csv(self._parse_bitwise)
    5750            start = seq_get(args, 0)
    5751            increment = seq_get(args, 1)
    5752        elif self._match_text_seq("START"):
    5753            start = self._parse_bitwise()
    5754            self._match_text_seq("INCREMENT")
    5755            increment = self._parse_bitwise()
    5756
    5757        if start and increment:
    5758            return exp.GeneratedAsIdentityColumnConstraint(
    5759                start=start, increment=increment, this=False
    5760            )
    5761
    5762        return exp.AutoIncrementColumnConstraint()
    5763
    5764    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    5765        if not self._match_text_seq("REFRESH"):
    5766            self._retreat(self._index - 1)
    5767            return None
    5768        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    5769
    5770    def _parse_compress(self) -> exp.CompressColumnConstraint:
    5771        if self._match(TokenType.L_PAREN, advance=False):
    5772            return self.expression(
    5773                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    5774            )
    5775
    5776        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    5777
    5778    def _parse_generated_as_identity(
    5779        self,
    5780    ) -> (
    5781        exp.GeneratedAsIdentityColumnConstraint
    5782        | exp.ComputedColumnConstraint
    5783        | exp.GeneratedAsRowColumnConstraint
    5784    ):
    5785        if self._match_text_seq("BY", "DEFAULT"):
    5786            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    5787            this = self.expression(
    5788                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    5789            )
    5790        else:
    5791            self._match_text_seq("ALWAYS")
    5792            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    5793
    5794        self._match(TokenType.ALIAS)
    5795
    5796        if self._match_text_seq("ROW"):
    5797            start = self._match_text_seq("START")
    5798            if not start:
    5799                self._match(TokenType.END)
    5800            hidden = self._match_text_seq("HIDDEN")
    5801            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    5802
    5803        identity = self._match_text_seq("IDENTITY")
    5804
    5805        if self._match(TokenType.L_PAREN):
    5806            if self._match(TokenType.START_WITH):
    5807                this.set("start", self._parse_bitwise())
    5808            if self._match_text_seq("INCREMENT", "BY"):
    5809                this.set("increment", self._parse_bitwise())
    5810            if self._match_text_seq("MINVALUE"):
    5811                this.set("minvalue", self._parse_bitwise())
    5812            if self._match_text_seq("MAXVALUE"):
    5813                this.set("maxvalue", self._parse_bitwise())
    5814
    5815            if self._match_text_seq("CYCLE"):
    5816                this.set("cycle", True)
    5817            elif self._match_text_seq("NO", "CYCLE"):
    5818                this.set("cycle", False)
    5819
    5820            if not identity:
    5821                this.set("expression", self._parse_range())
    5822            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5823                args = self._parse_csv(self._parse_bitwise)
    5824                this.set("start", seq_get(args, 0))
    5825                this.set("increment", seq_get(args, 1))
    5826
    5827            self._match_r_paren()
    5828
    5829        return this
    5830
    5831    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5832        self._match_text_seq("LENGTH")
    5833        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5834
    5835    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5836        if self._match_text_seq("NULL"):
    5837            return self.expression(exp.NotNullColumnConstraint)
    5838        if self._match_text_seq("CASESPECIFIC"):
    5839            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5840        if self._match_text_seq("FOR", "REPLICATION"):
    5841            return self.expression(exp.NotForReplicationColumnConstraint)
    5842
    5843        # Unconsume the `NOT` token
    5844        self._retreat(self._index - 1)
    5845        return None
    5846
    5847    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5848        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
    5849
    5850        procedure_option_follows = (
    5851            self._match(TokenType.WITH, advance=False)
    5852            and self._next
    5853            and self._next.text.upper() in self.PROCEDURE_OPTIONS
    5854        )
    5855
    5856        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
    5857            return self.expression(
    5858                exp.ColumnConstraint,
    5859                this=this,
    5860                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5861            )
    5862
    5863        return this
    5864
    5865    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5866        if not self._match(TokenType.CONSTRAINT):
    5867            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5868
    5869        return self.expression(
    5870            exp.Constraint,
    5871            this=self._parse_id_var(),
    5872            expressions=self._parse_unnamed_constraints(),
    5873        )
    5874
    5875    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5876        constraints = []
    5877        while True:
    5878            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5879            if not constraint:
    5880                break
    5881            constraints.append(constraint)
    5882
    5883        return constraints
    5884
    5885    def _parse_unnamed_constraint(
    5886        self, constraints: t.Optional[t.Collection[str]] = None
    5887    ) -> t.Optional[exp.Expression]:
    5888        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    5889            constraints or self.CONSTRAINT_PARSERS
    5890        ):
    5891            return None
    5892
    5893        constraint = self._prev.text.upper()
    5894        if constraint not in self.CONSTRAINT_PARSERS:
    5895            self.raise_error(f"No parser found for schema constraint {constraint}.")
    5896
    5897        return self.CONSTRAINT_PARSERS[constraint](self)
    5898
    5899    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
    5900        return self._parse_id_var(any_token=False)
    5901
    5902    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    5903        self._match_text_seq("KEY")
    5904        return self.expression(
    5905            exp.UniqueColumnConstraint,
    5906            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
    5907            this=self._parse_schema(self._parse_unique_key()),
    5908            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    5909            on_conflict=self._parse_on_conflict(),
    5910        )
    5911
    5912    def _parse_key_constraint_options(self) -> t.List[str]:
    5913        options = []
    5914        while True:
    5915            if not self._curr:
    5916                break
    5917
    5918            if self._match(TokenType.ON):
    5919                action = None
    5920                on = self._advance_any() and self._prev.text
    5921
    5922                if self._match_text_seq("NO", "ACTION"):
    5923                    action = "NO ACTION"
    5924                elif self._match_text_seq("CASCADE"):
    5925                    action = "CASCADE"
    5926                elif self._match_text_seq("RESTRICT"):
    5927                    action = "RESTRICT"
    5928                elif self._match_pair(TokenType.SET, TokenType.NULL):
    5929                    action = "SET NULL"
    5930                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5931                    action = "SET DEFAULT"
    5932                else:
    5933                    self.raise_error("Invalid key constraint")
    5934
    5935                options.append(f"ON {on} {action}")
    5936            else:
    5937                var = self._parse_var_from_options(
    5938                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
    5939                )
    5940                if not var:
    5941                    break
    5942                options.append(var.name)
    5943
    5944        return options
    5945
    5946    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    5947        if match and not self._match(TokenType.REFERENCES):
    5948            return None
    5949
    5950        expressions = None
    5951        this = self._parse_table(schema=True)
    5952        options = self._parse_key_constraint_options()
    5953        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    5954
    5955    def _parse_foreign_key(self) -> exp.ForeignKey:
    5956        expressions = self._parse_wrapped_id_vars()
    5957        reference = self._parse_references()
    5958        options = {}
    5959
    5960        while self._match(TokenType.ON):
    5961            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    5962                self.raise_error("Expected DELETE or UPDATE")
    5963
    5964            kind = self._prev.text.lower()
    5965
    5966            if self._match_text_seq("NO", "ACTION"):
    5967                action = "NO ACTION"
    5968            elif self._match(TokenType.SET):
    5969                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    5970                action = "SET " + self._prev.text.upper()
    5971            else:
    5972                self._advance()
    5973                action = self._prev.text.upper()
    5974
    5975            options[kind] = action
    5976
    5977        return self.expression(
    5978            exp.ForeignKey,
    5979            expressions=expressions,
    5980            reference=reference,
    5981            **options,  # type: ignore
    5982        )
    5983
    5984    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    5985        return self._parse_ordered() or self._parse_field()
    5986
    5987    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    5988        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    5989            self._retreat(self._index - 1)
    5990            return None
    5991
    5992        id_vars = self._parse_wrapped_id_vars()
    5993        return self.expression(
    5994            exp.PeriodForSystemTimeConstraint,
    5995            this=seq_get(id_vars, 0),
    5996            expression=seq_get(id_vars, 1),
    5997        )
    5998
    5999    def _parse_primary_key(
    6000        self, wrapped_optional: bool = False, in_props: bool = False
    6001    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    6002        desc = (
    6003            self._match_set((TokenType.ASC, TokenType.DESC))
    6004            and self._prev.token_type == TokenType.DESC
    6005        )
    6006
    6007        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    6008            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    6009
    6010        expressions = self._parse_wrapped_csv(
    6011            self._parse_primary_key_part, optional=wrapped_optional
    6012        )
    6013        options = self._parse_key_constraint_options()
    6014        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    6015
    6016    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    6017        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    6018
    6019    def _parse_odbc_datetime_literal(self) -> exp.Expression:
    6020        """
    6021        Parses a datetime column in ODBC format. We parse the column into the corresponding
    6022        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
    6023        same as we did for `DATE('yyyy-mm-dd')`.
    6024
    6025        Reference:
    6026        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
    6027        """
    6028        self._match(TokenType.VAR)
    6029        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
    6030        expression = self.expression(exp_class=exp_class, this=self._parse_string())
    6031        if not self._match(TokenType.R_BRACE):
    6032            self.raise_error("Expected }")
    6033        return expression
    6034
    6035    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    6036        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    6037            return this
    6038
    6039        bracket_kind = self._prev.token_type
    6040        if (
    6041            bracket_kind == TokenType.L_BRACE
    6042            and self._curr
    6043            and self._curr.token_type == TokenType.VAR
    6044            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
    6045        ):
    6046            return self._parse_odbc_datetime_literal()
    6047
    6048        expressions = self._parse_csv(
    6049            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    6050        )
    6051
    6052        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    6053            self.raise_error("Expected ]")
    6054        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    6055            self.raise_error("Expected }")
    6056
    6057        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    6058        if bracket_kind == TokenType.L_BRACE:
    6059            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    6060        elif not this:
    6061            this = build_array_constructor(
    6062                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
    6063            )
    6064        else:
    6065            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    6066            if constructor_type:
    6067                return build_array_constructor(
    6068                    constructor_type,
    6069                    args=expressions,
    6070                    bracket_kind=bracket_kind,
    6071                    dialect=self.dialect,
    6072                )
    6073
    6074            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    6075            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    6076
    6077        self._add_comments(this)
    6078        return self._parse_bracket(this)
    6079
    6080    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6081        if self._match(TokenType.COLON):
    6082            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    6083        return this
    6084
    6085    def _parse_case(self) -> t.Optional[exp.Expression]:
    6086        ifs = []
    6087        default = None
    6088
    6089        comments = self._prev_comments
    6090        expression = self._parse_assignment()
    6091
    6092        while self._match(TokenType.WHEN):
    6093            this = self._parse_assignment()
    6094            self._match(TokenType.THEN)
    6095            then = self._parse_assignment()
    6096            ifs.append(self.expression(exp.If, this=this, true=then))
    6097
    6098        if self._match(TokenType.ELSE):
    6099            default = self._parse_assignment()
    6100
    6101        if not self._match(TokenType.END):
    6102            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    6103                default = exp.column("interval")
    6104            else:
    6105                self.raise_error("Expected END after CASE", self._prev)
    6106
    6107        return self.expression(
    6108            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    6109        )
    6110
    6111    def _parse_if(self) -> t.Optional[exp.Expression]:
    6112        if self._match(TokenType.L_PAREN):
    6113            args = self._parse_csv(self._parse_assignment)
    6114            this = self.validate_expression(exp.If.from_arg_list(args), args)
    6115            self._match_r_paren()
    6116        else:
    6117            index = self._index - 1
    6118
    6119            if self.NO_PAREN_IF_COMMANDS and index == 0:
    6120                return self._parse_as_command(self._prev)
    6121
    6122            condition = self._parse_assignment()
    6123
    6124            if not condition:
    6125                self._retreat(index)
    6126                return None
    6127
    6128            self._match(TokenType.THEN)
    6129            true = self._parse_assignment()
    6130            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    6131            self._match(TokenType.END)
    6132            this = self.expression(exp.If, this=condition, true=true, false=false)
    6133
    6134        return this
    6135
    6136    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    6137        if not self._match_text_seq("VALUE", "FOR"):
    6138            self._retreat(self._index - 1)
    6139            return None
    6140
    6141        return self.expression(
    6142            exp.NextValueFor,
    6143            this=self._parse_column(),
    6144            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    6145        )
    6146
    6147    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
    6148        this = self._parse_function() or self._parse_var_or_string(upper=True)
    6149
    6150        if self._match(TokenType.FROM):
    6151            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6152
    6153        if not self._match(TokenType.COMMA):
    6154            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    6155
    6156        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6157
    6158    def _parse_gap_fill(self) -> exp.GapFill:
    6159        self._match(TokenType.TABLE)
    6160        this = self._parse_table()
    6161
    6162        self._match(TokenType.COMMA)
    6163        args = [this, *self._parse_csv(self._parse_lambda)]
    6164
    6165        gap_fill = exp.GapFill.from_arg_list(args)
    6166        return self.validate_expression(gap_fill, args)
    6167
    6168    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    6169        this = self._parse_assignment()
    6170
    6171        if not self._match(TokenType.ALIAS):
    6172            if self._match(TokenType.COMMA):
    6173                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    6174
    6175            self.raise_error("Expected AS after CAST")
    6176
    6177        fmt = None
    6178        to = self._parse_types()
    6179
    6180        default = self._match(TokenType.DEFAULT)
    6181        if default:
    6182            default = self._parse_bitwise()
    6183            self._match_text_seq("ON", "CONVERSION", "ERROR")
    6184
    6185        if self._match_set((TokenType.FORMAT, TokenType.COMMA)):
    6186            fmt_string = self._parse_string()
    6187            fmt = self._parse_at_time_zone(fmt_string)
    6188
    6189            if not to:
    6190                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    6191            if to.this in exp.DataType.TEMPORAL_TYPES:
    6192                this = self.expression(
    6193                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    6194                    this=this,
    6195                    format=exp.Literal.string(
    6196                        format_time(
    6197                            fmt_string.this if fmt_string else "",
    6198                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    6199                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    6200                        )
    6201                    ),
    6202                    safe=safe,
    6203                )
    6204
    6205                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    6206                    this.set("zone", fmt.args["zone"])
    6207                return this
    6208        elif not to:
    6209            self.raise_error("Expected TYPE after CAST")
    6210        elif isinstance(to, exp.Identifier):
    6211            to = exp.DataType.build(to.name, udt=True)
    6212        elif to.this == exp.DataType.Type.CHAR:
    6213            if self._match(TokenType.CHARACTER_SET):
    6214                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    6215
    6216        return self.expression(
    6217            exp.Cast if strict else exp.TryCast,
    6218            this=this,
    6219            to=to,
    6220            format=fmt,
    6221            safe=safe,
    6222            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    6223            default=default,
    6224        )
    6225
    6226    def _parse_string_agg(self) -> exp.GroupConcat:
    6227        if self._match(TokenType.DISTINCT):
    6228            args: t.List[t.Optional[exp.Expression]] = [
    6229                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    6230            ]
    6231            if self._match(TokenType.COMMA):
    6232                args.extend(self._parse_csv(self._parse_assignment))
    6233        else:
    6234            args = self._parse_csv(self._parse_assignment)  # type: ignore
    6235
    6236        if self._match_text_seq("ON", "OVERFLOW"):
    6237            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
    6238            if self._match_text_seq("ERROR"):
    6239                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
    6240            else:
    6241                self._match_text_seq("TRUNCATE")
    6242                on_overflow = self.expression(
    6243                    exp.OverflowTruncateBehavior,
    6244                    this=self._parse_string(),
    6245                    with_count=(
    6246                        self._match_text_seq("WITH", "COUNT")
    6247                        or not self._match_text_seq("WITHOUT", "COUNT")
    6248                    ),
    6249                )
    6250        else:
    6251            on_overflow = None
    6252
    6253        index = self._index
    6254        if not self._match(TokenType.R_PAREN) and args:
    6255            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    6256            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    6257            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    6258            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    6259
    6260        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    6261        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    6262        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    6263        if not self._match_text_seq("WITHIN", "GROUP"):
    6264            self._retreat(index)
    6265            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    6266
    6267        # The corresponding match_r_paren will be called in parse_function (caller)
    6268        self._match_l_paren()
    6269
    6270        return self.expression(
    6271            exp.GroupConcat,
    6272            this=self._parse_order(this=seq_get(args, 0)),
    6273            separator=seq_get(args, 1),
    6274            on_overflow=on_overflow,
    6275        )
    6276
    6277    def _parse_convert(
    6278        self, strict: bool, safe: t.Optional[bool] = None
    6279    ) -> t.Optional[exp.Expression]:
    6280        this = self._parse_bitwise()
    6281
    6282        if self._match(TokenType.USING):
    6283            to: t.Optional[exp.Expression] = self.expression(
    6284                exp.CharacterSet, this=self._parse_var()
    6285            )
    6286        elif self._match(TokenType.COMMA):
    6287            to = self._parse_types()
    6288        else:
    6289            to = None
    6290
    6291        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    6292
    6293    def _parse_xml_table(self) -> exp.XMLTable:
    6294        namespaces = None
    6295        passing = None
    6296        columns = None
    6297
    6298        if self._match_text_seq("XMLNAMESPACES", "("):
    6299            namespaces = self._parse_xml_namespace()
    6300            self._match_text_seq(")", ",")
    6301
    6302        this = self._parse_string()
    6303
    6304        if self._match_text_seq("PASSING"):
    6305            # The BY VALUE keywords are optional and are provided for semantic clarity
    6306            self._match_text_seq("BY", "VALUE")
    6307            passing = self._parse_csv(self._parse_column)
    6308
    6309        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
    6310
    6311        if self._match_text_seq("COLUMNS"):
    6312            columns = self._parse_csv(self._parse_field_def)
    6313
    6314        return self.expression(
    6315            exp.XMLTable,
    6316            this=this,
    6317            namespaces=namespaces,
    6318            passing=passing,
    6319            columns=columns,
    6320            by_ref=by_ref,
    6321        )
    6322
    6323    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
    6324        namespaces = []
    6325
    6326        while True:
    6327            if self._match(TokenType.DEFAULT):
    6328                uri = self._parse_string()
    6329            else:
    6330                uri = self._parse_alias(self._parse_string())
    6331            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
    6332            if not self._match(TokenType.COMMA):
    6333                break
    6334
    6335        return namespaces
    6336
    6337    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    6338        """
    6339        There are generally two variants of the DECODE function:
    6340
    6341        - DECODE(bin, charset)
    6342        - DECODE(expression, search, result [, search, result] ... [, default])
    6343
    6344        The second variant will always be parsed into a CASE expression. Note that NULL
    6345        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    6346        instead of relying on pattern matching.
    6347        """
    6348        args = self._parse_csv(self._parse_assignment)
    6349
    6350        if len(args) < 3:
    6351            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    6352
    6353        expression, *expressions = args
    6354        if not expression:
    6355            return None
    6356
    6357        ifs = []
    6358        for search, result in zip(expressions[::2], expressions[1::2]):
    6359            if not search or not result:
    6360                return None
    6361
    6362            if isinstance(search, exp.Literal):
    6363                ifs.append(
    6364                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    6365                )
    6366            elif isinstance(search, exp.Null):
    6367                ifs.append(
    6368                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    6369                )
    6370            else:
    6371                cond = exp.or_(
    6372                    exp.EQ(this=expression.copy(), expression=search),
    6373                    exp.and_(
    6374                        exp.Is(this=expression.copy(), expression=exp.Null()),
    6375                        exp.Is(this=search.copy(), expression=exp.Null()),
    6376                        copy=False,
    6377                    ),
    6378                    copy=False,
    6379                )
    6380                ifs.append(exp.If(this=cond, true=result))
    6381
    6382        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    6383
    6384    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    6385        self._match_text_seq("KEY")
    6386        key = self._parse_column()
    6387        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    6388        self._match_text_seq("VALUE")
    6389        value = self._parse_bitwise()
    6390
    6391        if not key and not value:
    6392            return None
    6393        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    6394
    6395    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6396        if not this or not self._match_text_seq("FORMAT", "JSON"):
    6397            return this
    6398
    6399        return self.expression(exp.FormatJson, this=this)
    6400
    6401    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
    6402        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
    6403        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
    6404            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6405            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6406        else:
    6407            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6408            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6409
    6410        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
    6411
    6412        if not empty and not error and not null:
    6413            return None
    6414
    6415        return self.expression(
    6416            exp.OnCondition,
    6417            empty=empty,
    6418            error=error,
    6419            null=null,
    6420        )
    6421
    6422    def _parse_on_handling(
    6423        self, on: str, *values: str
    6424    ) -> t.Optional[str] | t.Optional[exp.Expression]:
    6425        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
    6426        for value in values:
    6427            if self._match_text_seq(value, "ON", on):
    6428                return f"{value} ON {on}"
    6429
    6430        index = self._index
    6431        if self._match(TokenType.DEFAULT):
    6432            default_value = self._parse_bitwise()
    6433            if self._match_text_seq("ON", on):
    6434                return default_value
    6435
    6436            self._retreat(index)
    6437
    6438        return None
    6439
    6440    @t.overload
    6441    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    6442
    6443    @t.overload
    6444    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    6445
    6446    def _parse_json_object(self, agg=False):
    6447        star = self._parse_star()
    6448        expressions = (
    6449            [star]
    6450            if star
    6451            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    6452        )
    6453        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    6454
    6455        unique_keys = None
    6456        if self._match_text_seq("WITH", "UNIQUE"):
    6457            unique_keys = True
    6458        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    6459            unique_keys = False
    6460
    6461        self._match_text_seq("KEYS")
    6462
    6463        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    6464            self._parse_type()
    6465        )
    6466        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    6467
    6468        return self.expression(
    6469            exp.JSONObjectAgg if agg else exp.JSONObject,
    6470            expressions=expressions,
    6471            null_handling=null_handling,
    6472            unique_keys=unique_keys,
    6473            return_type=return_type,
    6474            encoding=encoding,
    6475        )
    6476
    6477    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    6478    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    6479        if not self._match_text_seq("NESTED"):
    6480            this = self._parse_id_var()
    6481            kind = self._parse_types(allow_identifiers=False)
    6482            nested = None
    6483        else:
    6484            this = None
    6485            kind = None
    6486            nested = True
    6487
    6488        path = self._match_text_seq("PATH") and self._parse_string()
    6489        nested_schema = nested and self._parse_json_schema()
    6490
    6491        return self.expression(
    6492            exp.JSONColumnDef,
    6493            this=this,
    6494            kind=kind,
    6495            path=path,
    6496            nested_schema=nested_schema,
    6497        )
    6498
    6499    def _parse_json_schema(self) -> exp.JSONSchema:
    6500        self._match_text_seq("COLUMNS")
    6501        return self.expression(
    6502            exp.JSONSchema,
    6503            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    6504        )
    6505
    6506    def _parse_json_table(self) -> exp.JSONTable:
    6507        this = self._parse_format_json(self._parse_bitwise())
    6508        path = self._match(TokenType.COMMA) and self._parse_string()
    6509        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    6510        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    6511        schema = self._parse_json_schema()
    6512
    6513        return exp.JSONTable(
    6514            this=this,
    6515            schema=schema,
    6516            path=path,
    6517            error_handling=error_handling,
    6518            empty_handling=empty_handling,
    6519        )
    6520
    6521    def _parse_match_against(self) -> exp.MatchAgainst:
    6522        expressions = self._parse_csv(self._parse_column)
    6523
    6524        self._match_text_seq(")", "AGAINST", "(")
    6525
    6526        this = self._parse_string()
    6527
    6528        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    6529            modifier = "IN NATURAL LANGUAGE MODE"
    6530            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6531                modifier = f"{modifier} WITH QUERY EXPANSION"
    6532        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    6533            modifier = "IN BOOLEAN MODE"
    6534        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6535            modifier = "WITH QUERY EXPANSION"
    6536        else:
    6537            modifier = None
    6538
    6539        return self.expression(
    6540            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    6541        )
    6542
    6543    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    6544    def _parse_open_json(self) -> exp.OpenJSON:
    6545        this = self._parse_bitwise()
    6546        path = self._match(TokenType.COMMA) and self._parse_string()
    6547
    6548        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    6549            this = self._parse_field(any_token=True)
    6550            kind = self._parse_types()
    6551            path = self._parse_string()
    6552            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    6553
    6554            return self.expression(
    6555                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    6556            )
    6557
    6558        expressions = None
    6559        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    6560            self._match_l_paren()
    6561            expressions = self._parse_csv(_parse_open_json_column_def)
    6562
    6563        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    6564
    6565    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    6566        args = self._parse_csv(self._parse_bitwise)
    6567
    6568        if self._match(TokenType.IN):
    6569            return self.expression(
    6570                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    6571            )
    6572
    6573        if haystack_first:
    6574            haystack = seq_get(args, 0)
    6575            needle = seq_get(args, 1)
    6576        else:
    6577            haystack = seq_get(args, 1)
    6578            needle = seq_get(args, 0)
    6579
    6580        return self.expression(
    6581            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    6582        )
    6583
    6584    def _parse_predict(self) -> exp.Predict:
    6585        self._match_text_seq("MODEL")
    6586        this = self._parse_table()
    6587
    6588        self._match(TokenType.COMMA)
    6589        self._match_text_seq("TABLE")
    6590
    6591        return self.expression(
    6592            exp.Predict,
    6593            this=this,
    6594            expression=self._parse_table(),
    6595            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    6596        )
    6597
    6598    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    6599        args = self._parse_csv(self._parse_table)
    6600        return exp.JoinHint(this=func_name.upper(), expressions=args)
    6601
    6602    def _parse_substring(self) -> exp.Substring:
    6603        # Postgres supports the form: substring(string [from int] [for int])
    6604        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    6605
    6606        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    6607
    6608        if self._match(TokenType.FROM):
    6609            args.append(self._parse_bitwise())
    6610        if self._match(TokenType.FOR):
    6611            if len(args) == 1:
    6612                args.append(exp.Literal.number(1))
    6613            args.append(self._parse_bitwise())
    6614
    6615        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    6616
    6617    def _parse_trim(self) -> exp.Trim:
    6618        # https://www.w3resource.com/sql/character-functions/trim.php
    6619        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    6620
    6621        position = None
    6622        collation = None
    6623        expression = None
    6624
    6625        if self._match_texts(self.TRIM_TYPES):
    6626            position = self._prev.text.upper()
    6627
    6628        this = self._parse_bitwise()
    6629        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    6630            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    6631            expression = self._parse_bitwise()
    6632
    6633            if invert_order:
    6634                this, expression = expression, this
    6635
    6636        if self._match(TokenType.COLLATE):
    6637            collation = self._parse_bitwise()
    6638
    6639        return self.expression(
    6640            exp.Trim, this=this, position=position, expression=expression, collation=collation
    6641        )
    6642
    6643    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    6644        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    6645
    6646    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    6647        return self._parse_window(self._parse_id_var(), alias=True)
    6648
    6649    def _parse_respect_or_ignore_nulls(
    6650        self, this: t.Optional[exp.Expression]
    6651    ) -> t.Optional[exp.Expression]:
    6652        if self._match_text_seq("IGNORE", "NULLS"):
    6653            return self.expression(exp.IgnoreNulls, this=this)
    6654        if self._match_text_seq("RESPECT", "NULLS"):
    6655            return self.expression(exp.RespectNulls, this=this)
    6656        return this
    6657
    6658    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6659        if self._match(TokenType.HAVING):
    6660            self._match_texts(("MAX", "MIN"))
    6661            max = self._prev.text.upper() != "MIN"
    6662            return self.expression(
    6663                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    6664            )
    6665
    6666        return this
    6667
    6668    def _parse_window(
    6669        self, this: t.Optional[exp.Expression], alias: bool = False
    6670    ) -> t.Optional[exp.Expression]:
    6671        func = this
    6672        comments = func.comments if isinstance(func, exp.Expression) else None
    6673
    6674        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    6675        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    6676        if self._match_text_seq("WITHIN", "GROUP"):
    6677            order = self._parse_wrapped(self._parse_order)
    6678            this = self.expression(exp.WithinGroup, this=this, expression=order)
    6679
    6680        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    6681            self._match(TokenType.WHERE)
    6682            this = self.expression(
    6683                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    6684            )
    6685            self._match_r_paren()
    6686
    6687        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    6688        # Some dialects choose to implement and some do not.
    6689        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    6690
    6691        # There is some code above in _parse_lambda that handles
    6692        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    6693
    6694        # The below changes handle
    6695        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    6696
    6697        # Oracle allows both formats
    6698        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    6699        #   and Snowflake chose to do the same for familiarity
    6700        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    6701        if isinstance(this, exp.AggFunc):
    6702            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    6703
    6704            if ignore_respect and ignore_respect is not this:
    6705                ignore_respect.replace(ignore_respect.this)
    6706                this = self.expression(ignore_respect.__class__, this=this)
    6707
    6708        this = self._parse_respect_or_ignore_nulls(this)
    6709
    6710        # bigquery select from window x AS (partition by ...)
    6711        if alias:
    6712            over = None
    6713            self._match(TokenType.ALIAS)
    6714        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    6715            return this
    6716        else:
    6717            over = self._prev.text.upper()
    6718
    6719        if comments and isinstance(func, exp.Expression):
    6720            func.pop_comments()
    6721
    6722        if not self._match(TokenType.L_PAREN):
    6723            return self.expression(
    6724                exp.Window,
    6725                comments=comments,
    6726                this=this,
    6727                alias=self._parse_id_var(False),
    6728                over=over,
    6729            )
    6730
    6731        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    6732
    6733        first = self._match(TokenType.FIRST)
    6734        if self._match_text_seq("LAST"):
    6735            first = False
    6736
    6737        partition, order = self._parse_partition_and_order()
    6738        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    6739
    6740        if kind:
    6741            self._match(TokenType.BETWEEN)
    6742            start = self._parse_window_spec()
    6743            self._match(TokenType.AND)
    6744            end = self._parse_window_spec()
    6745
    6746            spec = self.expression(
    6747                exp.WindowSpec,
    6748                kind=kind,
    6749                start=start["value"],
    6750                start_side=start["side"],
    6751                end=end["value"],
    6752                end_side=end["side"],
    6753            )
    6754        else:
    6755            spec = None
    6756
    6757        self._match_r_paren()
    6758
    6759        window = self.expression(
    6760            exp.Window,
    6761            comments=comments,
    6762            this=this,
    6763            partition_by=partition,
    6764            order=order,
    6765            spec=spec,
    6766            alias=window_alias,
    6767            over=over,
    6768            first=first,
    6769        )
    6770
    6771        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    6772        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    6773            return self._parse_window(window, alias=alias)
    6774
    6775        return window
    6776
    6777    def _parse_partition_and_order(
    6778        self,
    6779    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    6780        return self._parse_partition_by(), self._parse_order()
    6781
    6782    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    6783        self._match(TokenType.BETWEEN)
    6784
    6785        return {
    6786            "value": (
    6787                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    6788                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    6789                or self._parse_bitwise()
    6790            ),
    6791            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    6792        }
    6793
    6794    def _parse_alias(
    6795        self, this: t.Optional[exp.Expression], explicit: bool = False
    6796    ) -> t.Optional[exp.Expression]:
    6797        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    6798        # so this section tries to parse the clause version and if it fails, it treats the token
    6799        # as an identifier (alias)
    6800        if self._can_parse_limit_or_offset():
    6801            return this
    6802
    6803        any_token = self._match(TokenType.ALIAS)
    6804        comments = self._prev_comments or []
    6805
    6806        if explicit and not any_token:
    6807            return this
    6808
    6809        if self._match(TokenType.L_PAREN):
    6810            aliases = self.expression(
    6811                exp.Aliases,
    6812                comments=comments,
    6813                this=this,
    6814                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    6815            )
    6816            self._match_r_paren(aliases)
    6817            return aliases
    6818
    6819        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    6820            self.STRING_ALIASES and self._parse_string_as_identifier()
    6821        )
    6822
    6823        if alias:
    6824            comments.extend(alias.pop_comments())
    6825            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    6826            column = this.this
    6827
    6828            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    6829            if not this.comments and column and column.comments:
    6830                this.comments = column.pop_comments()
    6831
    6832        return this
    6833
    6834    def _parse_id_var(
    6835        self,
    6836        any_token: bool = True,
    6837        tokens: t.Optional[t.Collection[TokenType]] = None,
    6838    ) -> t.Optional[exp.Expression]:
    6839        expression = self._parse_identifier()
    6840        if not expression and (
    6841            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    6842        ):
    6843            quoted = self._prev.token_type == TokenType.STRING
    6844            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    6845
    6846        return expression
    6847
    6848    def _parse_string(self) -> t.Optional[exp.Expression]:
    6849        if self._match_set(self.STRING_PARSERS):
    6850            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    6851        return self._parse_placeholder()
    6852
    6853    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    6854        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    6855
    6856    def _parse_number(self) -> t.Optional[exp.Expression]:
    6857        if self._match_set(self.NUMERIC_PARSERS):
    6858            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    6859        return self._parse_placeholder()
    6860
    6861    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    6862        if self._match(TokenType.IDENTIFIER):
    6863            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    6864        return self._parse_placeholder()
    6865
    6866    def _parse_var(
    6867        self,
    6868        any_token: bool = False,
    6869        tokens: t.Optional[t.Collection[TokenType]] = None,
    6870        upper: bool = False,
    6871    ) -> t.Optional[exp.Expression]:
    6872        if (
    6873            (any_token and self._advance_any())
    6874            or self._match(TokenType.VAR)
    6875            or (self._match_set(tokens) if tokens else False)
    6876        ):
    6877            return self.expression(
    6878                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    6879            )
    6880        return self._parse_placeholder()
    6881
    6882    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    6883        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    6884            self._advance()
    6885            return self._prev
    6886        return None
    6887
    6888    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
    6889        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
    6890
    6891    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    6892        return self._parse_primary() or self._parse_var(any_token=True)
    6893
    6894    def _parse_null(self) -> t.Optional[exp.Expression]:
    6895        if self._match_set(self.NULL_TOKENS):
    6896            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    6897        return self._parse_placeholder()
    6898
    6899    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    6900        if self._match(TokenType.TRUE):
    6901            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    6902        if self._match(TokenType.FALSE):
    6903            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    6904        return self._parse_placeholder()
    6905
    6906    def _parse_star(self) -> t.Optional[exp.Expression]:
    6907        if self._match(TokenType.STAR):
    6908            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    6909        return self._parse_placeholder()
    6910
    6911    def _parse_parameter(self) -> exp.Parameter:
    6912        this = self._parse_identifier() or self._parse_primary_or_var()
    6913        return self.expression(exp.Parameter, this=this)
    6914
    6915    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    6916        if self._match_set(self.PLACEHOLDER_PARSERS):
    6917            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    6918            if placeholder:
    6919                return placeholder
    6920            self._advance(-1)
    6921        return None
    6922
    6923    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    6924        if not self._match_texts(keywords):
    6925            return None
    6926        if self._match(TokenType.L_PAREN, advance=False):
    6927            return self._parse_wrapped_csv(self._parse_expression)
    6928
    6929        expression = self._parse_expression()
    6930        return [expression] if expression else None
    6931
    6932    def _parse_csv(
    6933        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    6934    ) -> t.List[exp.Expression]:
    6935        parse_result = parse_method()
    6936        items = [parse_result] if parse_result is not None else []
    6937
    6938        while self._match(sep):
    6939            self._add_comments(parse_result)
    6940            parse_result = parse_method()
    6941            if parse_result is not None:
    6942                items.append(parse_result)
    6943
    6944        return items
    6945
    6946    def _parse_tokens(
    6947        self, parse_method: t.Callable, expressions: t.Dict
    6948    ) -> t.Optional[exp.Expression]:
    6949        this = parse_method()
    6950
    6951        while self._match_set(expressions):
    6952            this = self.expression(
    6953                expressions[self._prev.token_type],
    6954                this=this,
    6955                comments=self._prev_comments,
    6956                expression=parse_method(),
    6957            )
    6958
    6959        return this
    6960
    6961    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    6962        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    6963
    6964    def _parse_wrapped_csv(
    6965        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    6966    ) -> t.List[exp.Expression]:
    6967        return self._parse_wrapped(
    6968            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    6969        )
    6970
    6971    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    6972        wrapped = self._match(TokenType.L_PAREN)
    6973        if not wrapped and not optional:
    6974            self.raise_error("Expecting (")
    6975        parse_result = parse_method()
    6976        if wrapped:
    6977            self._match_r_paren()
    6978        return parse_result
    6979
    6980    def _parse_expressions(self) -> t.List[exp.Expression]:
    6981        return self._parse_csv(self._parse_expression)
    6982
    6983    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    6984        return self._parse_select() or self._parse_set_operations(
    6985            self._parse_alias(self._parse_assignment(), explicit=True)
    6986            if alias
    6987            else self._parse_assignment()
    6988        )
    6989
    6990    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    6991        return self._parse_query_modifiers(
    6992            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    6993        )
    6994
    6995    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    6996        this = None
    6997        if self._match_texts(self.TRANSACTION_KIND):
    6998            this = self._prev.text
    6999
    7000        self._match_texts(("TRANSACTION", "WORK"))
    7001
    7002        modes = []
    7003        while True:
    7004            mode = []
    7005            while self._match(TokenType.VAR):
    7006                mode.append(self._prev.text)
    7007
    7008            if mode:
    7009                modes.append(" ".join(mode))
    7010            if not self._match(TokenType.COMMA):
    7011                break
    7012
    7013        return self.expression(exp.Transaction, this=this, modes=modes)
    7014
    7015    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    7016        chain = None
    7017        savepoint = None
    7018        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    7019
    7020        self._match_texts(("TRANSACTION", "WORK"))
    7021
    7022        if self._match_text_seq("TO"):
    7023            self._match_text_seq("SAVEPOINT")
    7024            savepoint = self._parse_id_var()
    7025
    7026        if self._match(TokenType.AND):
    7027            chain = not self._match_text_seq("NO")
    7028            self._match_text_seq("CHAIN")
    7029
    7030        if is_rollback:
    7031            return self.expression(exp.Rollback, savepoint=savepoint)
    7032
    7033        return self.expression(exp.Commit, chain=chain)
    7034
    7035    def _parse_refresh(self) -> exp.Refresh:
    7036        self._match(TokenType.TABLE)
    7037        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    7038
    7039    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    7040        if not self._match_text_seq("ADD"):
    7041            return None
    7042
    7043        self._match(TokenType.COLUMN)
    7044        exists_column = self._parse_exists(not_=True)
    7045        expression = self._parse_field_def()
    7046
    7047        if expression:
    7048            expression.set("exists", exists_column)
    7049
    7050            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    7051            if self._match_texts(("FIRST", "AFTER")):
    7052                position = self._prev.text
    7053                column_position = self.expression(
    7054                    exp.ColumnPosition, this=self._parse_column(), position=position
    7055                )
    7056                expression.set("position", column_position)
    7057
    7058        return expression
    7059
    7060    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    7061        drop = self._match(TokenType.DROP) and self._parse_drop()
    7062        if drop and not isinstance(drop, exp.Command):
    7063            drop.set("kind", drop.args.get("kind", "COLUMN"))
    7064        return drop
    7065
    7066    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    7067    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    7068        return self.expression(
    7069            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    7070        )
    7071
    7072    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    7073        index = self._index - 1
    7074
    7075        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    7076            return self._parse_csv(
    7077                lambda: self.expression(
    7078                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    7079                )
    7080            )
    7081
    7082        self._retreat(index)
    7083        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    7084            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    7085
    7086        if self._match_text_seq("ADD", "COLUMNS"):
    7087            schema = self._parse_schema()
    7088            if schema:
    7089                return [schema]
    7090            return []
    7091
    7092        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    7093
    7094    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    7095        if self._match_texts(self.ALTER_ALTER_PARSERS):
    7096            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    7097
    7098        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    7099        # keyword after ALTER we default to parsing this statement
    7100        self._match(TokenType.COLUMN)
    7101        column = self._parse_field(any_token=True)
    7102
    7103        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    7104            return self.expression(exp.AlterColumn, this=column, drop=True)
    7105        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    7106            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    7107        if self._match(TokenType.COMMENT):
    7108            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    7109        if self._match_text_seq("DROP", "NOT", "NULL"):
    7110            return self.expression(
    7111                exp.AlterColumn,
    7112                this=column,
    7113                drop=True,
    7114                allow_null=True,
    7115            )
    7116        if self._match_text_seq("SET", "NOT", "NULL"):
    7117            return self.expression(
    7118                exp.AlterColumn,
    7119                this=column,
    7120                allow_null=False,
    7121            )
    7122
    7123        if self._match_text_seq("SET", "VISIBLE"):
    7124            return self.expression(exp.AlterColumn, this=column, visible="VISIBLE")
    7125        if self._match_text_seq("SET", "INVISIBLE"):
    7126            return self.expression(exp.AlterColumn, this=column, visible="INVISIBLE")
    7127
    7128        self._match_text_seq("SET", "DATA")
    7129        self._match_text_seq("TYPE")
    7130        return self.expression(
    7131            exp.AlterColumn,
    7132            this=column,
    7133            dtype=self._parse_types(),
    7134            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    7135            using=self._match(TokenType.USING) and self._parse_assignment(),
    7136        )
    7137
    7138    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    7139        if self._match_texts(("ALL", "EVEN", "AUTO")):
    7140            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    7141
    7142        self._match_text_seq("KEY", "DISTKEY")
    7143        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    7144
    7145    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    7146        if compound:
    7147            self._match_text_seq("SORTKEY")
    7148
    7149        if self._match(TokenType.L_PAREN, advance=False):
    7150            return self.expression(
    7151                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    7152            )
    7153
    7154        self._match_texts(("AUTO", "NONE"))
    7155        return self.expression(
    7156            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    7157        )
    7158
    7159    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    7160        index = self._index - 1
    7161
    7162        partition_exists = self._parse_exists()
    7163        if self._match(TokenType.PARTITION, advance=False):
    7164            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    7165
    7166        self._retreat(index)
    7167        return self._parse_csv(self._parse_drop_column)
    7168
    7169    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
    7170        if self._match(TokenType.COLUMN):
    7171            exists = self._parse_exists()
    7172            old_column = self._parse_column()
    7173            to = self._match_text_seq("TO")
    7174            new_column = self._parse_column()
    7175
    7176            if old_column is None or to is None or new_column is None:
    7177                return None
    7178
    7179            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    7180
    7181        self._match_text_seq("TO")
    7182        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
    7183
    7184    def _parse_alter_table_set(self) -> exp.AlterSet:
    7185        alter_set = self.expression(exp.AlterSet)
    7186
    7187        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    7188            "TABLE", "PROPERTIES"
    7189        ):
    7190            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    7191        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    7192            alter_set.set("expressions", [self._parse_assignment()])
    7193        elif self._match_texts(("LOGGED", "UNLOGGED")):
    7194            alter_set.set("option", exp.var(self._prev.text.upper()))
    7195        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    7196            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    7197        elif self._match_text_seq("LOCATION"):
    7198            alter_set.set("location", self._parse_field())
    7199        elif self._match_text_seq("ACCESS", "METHOD"):
    7200            alter_set.set("access_method", self._parse_field())
    7201        elif self._match_text_seq("TABLESPACE"):
    7202            alter_set.set("tablespace", self._parse_field())
    7203        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    7204            alter_set.set("file_format", [self._parse_field()])
    7205        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    7206            alter_set.set("file_format", self._parse_wrapped_options())
    7207        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    7208            alter_set.set("copy_options", self._parse_wrapped_options())
    7209        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    7210            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    7211        else:
    7212            if self._match_text_seq("SERDE"):
    7213                alter_set.set("serde", self._parse_field())
    7214
    7215            alter_set.set("expressions", [self._parse_properties()])
    7216
    7217        return alter_set
    7218
    7219    def _parse_alter(self) -> exp.Alter | exp.Command:
    7220        start = self._prev
    7221
    7222        alter_token = self._match_set(self.ALTERABLES) and self._prev
    7223        if not alter_token:
    7224            return self._parse_as_command(start)
    7225
    7226        exists = self._parse_exists()
    7227        only = self._match_text_seq("ONLY")
    7228        this = self._parse_table(schema=True)
    7229        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7230
    7231        if self._next:
    7232            self._advance()
    7233
    7234        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    7235        if parser:
    7236            actions = ensure_list(parser(self))
    7237            not_valid = self._match_text_seq("NOT", "VALID")
    7238            options = self._parse_csv(self._parse_property)
    7239
    7240            if not self._curr and actions:
    7241                return self.expression(
    7242                    exp.Alter,
    7243                    this=this,
    7244                    kind=alter_token.text.upper(),
    7245                    exists=exists,
    7246                    actions=actions,
    7247                    only=only,
    7248                    options=options,
    7249                    cluster=cluster,
    7250                    not_valid=not_valid,
    7251                )
    7252
    7253        return self._parse_as_command(start)
    7254
    7255    def _parse_analyze(self) -> exp.Analyze | exp.Command:
    7256        start = self._prev
    7257        # https://duckdb.org/docs/sql/statements/analyze
    7258        if not self._curr:
    7259            return self.expression(exp.Analyze)
    7260
    7261        options = []
    7262        while self._match_texts(self.ANALYZE_STYLES):
    7263            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
    7264                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
    7265            else:
    7266                options.append(self._prev.text.upper())
    7267
    7268        this: t.Optional[exp.Expression] = None
    7269        inner_expression: t.Optional[exp.Expression] = None
    7270
    7271        kind = self._curr and self._curr.text.upper()
    7272
    7273        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
    7274            this = self._parse_table_parts()
    7275        elif self._match_text_seq("TABLES"):
    7276            if self._match_set((TokenType.FROM, TokenType.IN)):
    7277                kind = f"{kind} {self._prev.text.upper()}"
    7278                this = self._parse_table(schema=True, is_db_reference=True)
    7279        elif self._match_text_seq("DATABASE"):
    7280            this = self._parse_table(schema=True, is_db_reference=True)
    7281        elif self._match_text_seq("CLUSTER"):
    7282            this = self._parse_table()
    7283        # Try matching inner expr keywords before fallback to parse table.
    7284        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7285            kind = None
    7286            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7287        else:
    7288            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
    7289            kind = None
    7290            this = self._parse_table_parts()
    7291
    7292        partition = self._try_parse(self._parse_partition)
    7293        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
    7294            return self._parse_as_command(start)
    7295
    7296        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7297        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
    7298            "WITH", "ASYNC", "MODE"
    7299        ):
    7300            mode = f"WITH {self._tokens[self._index-2].text.upper()} MODE"
    7301        else:
    7302            mode = None
    7303
    7304        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7305            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7306
    7307        properties = self._parse_properties()
    7308        return self.expression(
    7309            exp.Analyze,
    7310            kind=kind,
    7311            this=this,
    7312            mode=mode,
    7313            partition=partition,
    7314            properties=properties,
    7315            expression=inner_expression,
    7316            options=options,
    7317        )
    7318
    7319    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
    7320    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
    7321        this = None
    7322        kind = self._prev.text.upper()
    7323        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
    7324        expressions = []
    7325
    7326        if not self._match_text_seq("STATISTICS"):
    7327            self.raise_error("Expecting token STATISTICS")
    7328
    7329        if self._match_text_seq("NOSCAN"):
    7330            this = "NOSCAN"
    7331        elif self._match(TokenType.FOR):
    7332            if self._match_text_seq("ALL", "COLUMNS"):
    7333                this = "FOR ALL COLUMNS"
    7334            if self._match_texts("COLUMNS"):
    7335                this = "FOR COLUMNS"
    7336                expressions = self._parse_csv(self._parse_column_reference)
    7337        elif self._match_text_seq("SAMPLE"):
    7338            sample = self._parse_number()
    7339            expressions = [
    7340                self.expression(
    7341                    exp.AnalyzeSample,
    7342                    sample=sample,
    7343                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
    7344                )
    7345            ]
    7346
    7347        return self.expression(
    7348            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
    7349        )
    7350
    7351    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
    7352    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
    7353        kind = None
    7354        this = None
    7355        expression: t.Optional[exp.Expression] = None
    7356        if self._match_text_seq("REF", "UPDATE"):
    7357            kind = "REF"
    7358            this = "UPDATE"
    7359            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
    7360                this = "UPDATE SET DANGLING TO NULL"
    7361        elif self._match_text_seq("STRUCTURE"):
    7362            kind = "STRUCTURE"
    7363            if self._match_text_seq("CASCADE", "FAST"):
    7364                this = "CASCADE FAST"
    7365            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
    7366                ("ONLINE", "OFFLINE")
    7367            ):
    7368                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
    7369                expression = self._parse_into()
    7370
    7371        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
    7372
    7373    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
    7374        this = self._prev.text.upper()
    7375        if self._match_text_seq("COLUMNS"):
    7376            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
    7377        return None
    7378
    7379    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
    7380        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
    7381        if self._match_text_seq("STATISTICS"):
    7382            return self.expression(exp.AnalyzeDelete, kind=kind)
    7383        return None
    7384
    7385    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
    7386        if self._match_text_seq("CHAINED", "ROWS"):
    7387            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
    7388        return None
    7389
    7390    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
    7391    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
    7392        this = self._prev.text.upper()
    7393        expression: t.Optional[exp.Expression] = None
    7394        expressions = []
    7395        update_options = None
    7396
    7397        if self._match_text_seq("HISTOGRAM", "ON"):
    7398            expressions = self._parse_csv(self._parse_column_reference)
    7399            with_expressions = []
    7400            while self._match(TokenType.WITH):
    7401                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7402                if self._match_texts(("SYNC", "ASYNC")):
    7403                    if self._match_text_seq("MODE", advance=False):
    7404                        with_expressions.append(f"{self._prev.text.upper()} MODE")
    7405                        self._advance()
    7406                else:
    7407                    buckets = self._parse_number()
    7408                    if self._match_text_seq("BUCKETS"):
    7409                        with_expressions.append(f"{buckets} BUCKETS")
    7410            if with_expressions:
    7411                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
    7412
    7413            if self._match_texts(("MANUAL", "AUTO")) and self._match(
    7414                TokenType.UPDATE, advance=False
    7415            ):
    7416                update_options = self._prev.text.upper()
    7417                self._advance()
    7418            elif self._match_text_seq("USING", "DATA"):
    7419                expression = self.expression(exp.UsingData, this=self._parse_string())
    7420
    7421        return self.expression(
    7422            exp.AnalyzeHistogram,
    7423            this=this,
    7424            expressions=expressions,
    7425            expression=expression,
    7426            update_options=update_options,
    7427        )
    7428
    7429    def _parse_merge(self) -> exp.Merge:
    7430        self._match(TokenType.INTO)
    7431        target = self._parse_table()
    7432
    7433        if target and self._match(TokenType.ALIAS, advance=False):
    7434            target.set("alias", self._parse_table_alias())
    7435
    7436        self._match(TokenType.USING)
    7437        using = self._parse_table()
    7438
    7439        self._match(TokenType.ON)
    7440        on = self._parse_assignment()
    7441
    7442        return self.expression(
    7443            exp.Merge,
    7444            this=target,
    7445            using=using,
    7446            on=on,
    7447            whens=self._parse_when_matched(),
    7448            returning=self._parse_returning(),
    7449        )
    7450
    7451    def _parse_when_matched(self) -> exp.Whens:
    7452        whens = []
    7453
    7454        while self._match(TokenType.WHEN):
    7455            matched = not self._match(TokenType.NOT)
    7456            self._match_text_seq("MATCHED")
    7457            source = (
    7458                False
    7459                if self._match_text_seq("BY", "TARGET")
    7460                else self._match_text_seq("BY", "SOURCE")
    7461            )
    7462            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    7463
    7464            self._match(TokenType.THEN)
    7465
    7466            if self._match(TokenType.INSERT):
    7467                this = self._parse_star()
    7468                if this:
    7469                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
    7470                else:
    7471                    then = self.expression(
    7472                        exp.Insert,
    7473                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
    7474                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    7475                    )
    7476            elif self._match(TokenType.UPDATE):
    7477                expressions = self._parse_star()
    7478                if expressions:
    7479                    then = self.expression(exp.Update, expressions=expressions)
    7480                else:
    7481                    then = self.expression(
    7482                        exp.Update,
    7483                        expressions=self._match(TokenType.SET)
    7484                        and self._parse_csv(self._parse_equality),
    7485                    )
    7486            elif self._match(TokenType.DELETE):
    7487                then = self.expression(exp.Var, this=self._prev.text)
    7488            else:
    7489                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    7490
    7491            whens.append(
    7492                self.expression(
    7493                    exp.When,
    7494                    matched=matched,
    7495                    source=source,
    7496                    condition=condition,
    7497                    then=then,
    7498                )
    7499            )
    7500        return self.expression(exp.Whens, expressions=whens)
    7501
    7502    def _parse_show(self) -> t.Optional[exp.Expression]:
    7503        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    7504        if parser:
    7505            return parser(self)
    7506        return self._parse_as_command(self._prev)
    7507
    7508    def _parse_set_item_assignment(
    7509        self, kind: t.Optional[str] = None
    7510    ) -> t.Optional[exp.Expression]:
    7511        index = self._index
    7512
    7513        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    7514            return self._parse_set_transaction(global_=kind == "GLOBAL")
    7515
    7516        left = self._parse_primary() or self._parse_column()
    7517        assignment_delimiter = self._match_texts(("=", "TO"))
    7518
    7519        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    7520            self._retreat(index)
    7521            return None
    7522
    7523        right = self._parse_statement() or self._parse_id_var()
    7524        if isinstance(right, (exp.Column, exp.Identifier)):
    7525            right = exp.var(right.name)
    7526
    7527        this = self.expression(exp.EQ, this=left, expression=right)
    7528        return self.expression(exp.SetItem, this=this, kind=kind)
    7529
    7530    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    7531        self._match_text_seq("TRANSACTION")
    7532        characteristics = self._parse_csv(
    7533            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    7534        )
    7535        return self.expression(
    7536            exp.SetItem,
    7537            expressions=characteristics,
    7538            kind="TRANSACTION",
    7539            **{"global": global_},  # type: ignore
    7540        )
    7541
    7542    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    7543        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    7544        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    7545
    7546    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    7547        index = self._index
    7548        set_ = self.expression(
    7549            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    7550        )
    7551
    7552        if self._curr:
    7553            self._retreat(index)
    7554            return self._parse_as_command(self._prev)
    7555
    7556        return set_
    7557
    7558    def _parse_var_from_options(
    7559        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    7560    ) -> t.Optional[exp.Var]:
    7561        start = self._curr
    7562        if not start:
    7563            return None
    7564
    7565        option = start.text.upper()
    7566        continuations = options.get(option)
    7567
    7568        index = self._index
    7569        self._advance()
    7570        for keywords in continuations or []:
    7571            if isinstance(keywords, str):
    7572                keywords = (keywords,)
    7573
    7574            if self._match_text_seq(*keywords):
    7575                option = f"{option} {' '.join(keywords)}"
    7576                break
    7577        else:
    7578            if continuations or continuations is None:
    7579                if raise_unmatched:
    7580                    self.raise_error(f"Unknown option {option}")
    7581
    7582                self._retreat(index)
    7583                return None
    7584
    7585        return exp.var(option)
    7586
    7587    def _parse_as_command(self, start: Token) -> exp.Command:
    7588        while self._curr:
    7589            self._advance()
    7590        text = self._find_sql(start, self._prev)
    7591        size = len(start.text)
    7592        self._warn_unsupported()
    7593        return exp.Command(this=text[:size], expression=text[size:])
    7594
    7595    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    7596        settings = []
    7597
    7598        self._match_l_paren()
    7599        kind = self._parse_id_var()
    7600
    7601        if self._match(TokenType.L_PAREN):
    7602            while True:
    7603                key = self._parse_id_var()
    7604                value = self._parse_primary()
    7605                if not key and value is None:
    7606                    break
    7607                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    7608            self._match(TokenType.R_PAREN)
    7609
    7610        self._match_r_paren()
    7611
    7612        return self.expression(
    7613            exp.DictProperty,
    7614            this=this,
    7615            kind=kind.this if kind else None,
    7616            settings=settings,
    7617        )
    7618
    7619    def _parse_dict_range(self, this: str) -> exp.DictRange:
    7620        self._match_l_paren()
    7621        has_min = self._match_text_seq("MIN")
    7622        if has_min:
    7623            min = self._parse_var() or self._parse_primary()
    7624            self._match_text_seq("MAX")
    7625            max = self._parse_var() or self._parse_primary()
    7626        else:
    7627            max = self._parse_var() or self._parse_primary()
    7628            min = exp.Literal.number(0)
    7629        self._match_r_paren()
    7630        return self.expression(exp.DictRange, this=this, min=min, max=max)
    7631
    7632    def _parse_comprehension(
    7633        self, this: t.Optional[exp.Expression]
    7634    ) -> t.Optional[exp.Comprehension]:
    7635        index = self._index
    7636        expression = self._parse_column()
    7637        if not self._match(TokenType.IN):
    7638            self._retreat(index - 1)
    7639            return None
    7640        iterator = self._parse_column()
    7641        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    7642        return self.expression(
    7643            exp.Comprehension,
    7644            this=this,
    7645            expression=expression,
    7646            iterator=iterator,
    7647            condition=condition,
    7648        )
    7649
    7650    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    7651        if self._match(TokenType.HEREDOC_STRING):
    7652            return self.expression(exp.Heredoc, this=self._prev.text)
    7653
    7654        if not self._match_text_seq("$"):
    7655            return None
    7656
    7657        tags = ["$"]
    7658        tag_text = None
    7659
    7660        if self._is_connected():
    7661            self._advance()
    7662            tags.append(self._prev.text.upper())
    7663        else:
    7664            self.raise_error("No closing $ found")
    7665
    7666        if tags[-1] != "$":
    7667            if self._is_connected() and self._match_text_seq("$"):
    7668                tag_text = tags[-1]
    7669                tags.append("$")
    7670            else:
    7671                self.raise_error("No closing $ found")
    7672
    7673        heredoc_start = self._curr
    7674
    7675        while self._curr:
    7676            if self._match_text_seq(*tags, advance=False):
    7677                this = self._find_sql(heredoc_start, self._prev)
    7678                self._advance(len(tags))
    7679                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    7680
    7681            self._advance()
    7682
    7683        self.raise_error(f"No closing {''.join(tags)} found")
    7684        return None
    7685
    7686    def _find_parser(
    7687        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    7688    ) -> t.Optional[t.Callable]:
    7689        if not self._curr:
    7690            return None
    7691
    7692        index = self._index
    7693        this = []
    7694        while True:
    7695            # The current token might be multiple words
    7696            curr = self._curr.text.upper()
    7697            key = curr.split(" ")
    7698            this.append(curr)
    7699
    7700            self._advance()
    7701            result, trie = in_trie(trie, key)
    7702            if result == TrieResult.FAILED:
    7703                break
    7704
    7705            if result == TrieResult.EXISTS:
    7706                subparser = parsers[" ".join(this)]
    7707                return subparser
    7708
    7709        self._retreat(index)
    7710        return None
    7711
    7712    def _match(self, token_type, advance=True, expression=None):
    7713        if not self._curr:
    7714            return None
    7715
    7716        if self._curr.token_type == token_type:
    7717            if advance:
    7718                self._advance()
    7719            self._add_comments(expression)
    7720            return True
    7721
    7722        return None
    7723
    7724    def _match_set(self, types, advance=True):
    7725        if not self._curr:
    7726            return None
    7727
    7728        if self._curr.token_type in types:
    7729            if advance:
    7730                self._advance()
    7731            return True
    7732
    7733        return None
    7734
    7735    def _match_pair(self, token_type_a, token_type_b, advance=True):
    7736        if not self._curr or not self._next:
    7737            return None
    7738
    7739        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    7740            if advance:
    7741                self._advance(2)
    7742            return True
    7743
    7744        return None
    7745
    7746    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7747        if not self._match(TokenType.L_PAREN, expression=expression):
    7748            self.raise_error("Expecting (")
    7749
    7750    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7751        if not self._match(TokenType.R_PAREN, expression=expression):
    7752            self.raise_error("Expecting )")
    7753
    7754    def _match_texts(self, texts, advance=True):
    7755        if (
    7756            self._curr
    7757            and self._curr.token_type != TokenType.STRING
    7758            and self._curr.text.upper() in texts
    7759        ):
    7760            if advance:
    7761                self._advance()
    7762            return True
    7763        return None
    7764
    7765    def _match_text_seq(self, *texts, advance=True):
    7766        index = self._index
    7767        for text in texts:
    7768            if (
    7769                self._curr
    7770                and self._curr.token_type != TokenType.STRING
    7771                and self._curr.text.upper() == text
    7772            ):
    7773                self._advance()
    7774            else:
    7775                self._retreat(index)
    7776                return None
    7777
    7778        if not advance:
    7779            self._retreat(index)
    7780
    7781        return True
    7782
    7783    def _replace_lambda(
    7784        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    7785    ) -> t.Optional[exp.Expression]:
    7786        if not node:
    7787            return node
    7788
    7789        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    7790
    7791        for column in node.find_all(exp.Column):
    7792            typ = lambda_types.get(column.parts[0].name)
    7793            if typ is not None:
    7794                dot_or_id = column.to_dot() if column.table else column.this
    7795
    7796                if typ:
    7797                    dot_or_id = self.expression(
    7798                        exp.Cast,
    7799                        this=dot_or_id,
    7800                        to=typ,
    7801                    )
    7802
    7803                parent = column.parent
    7804
    7805                while isinstance(parent, exp.Dot):
    7806                    if not isinstance(parent.parent, exp.Dot):
    7807                        parent.replace(dot_or_id)
    7808                        break
    7809                    parent = parent.parent
    7810                else:
    7811                    if column is node:
    7812                        node = dot_or_id
    7813                    else:
    7814                        column.replace(dot_or_id)
    7815        return node
    7816
    7817    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    7818        start = self._prev
    7819
    7820        # Not to be confused with TRUNCATE(number, decimals) function call
    7821        if self._match(TokenType.L_PAREN):
    7822            self._retreat(self._index - 2)
    7823            return self._parse_function()
    7824
    7825        # Clickhouse supports TRUNCATE DATABASE as well
    7826        is_database = self._match(TokenType.DATABASE)
    7827
    7828        self._match(TokenType.TABLE)
    7829
    7830        exists = self._parse_exists(not_=False)
    7831
    7832        expressions = self._parse_csv(
    7833            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    7834        )
    7835
    7836        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7837
    7838        if self._match_text_seq("RESTART", "IDENTITY"):
    7839            identity = "RESTART"
    7840        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    7841            identity = "CONTINUE"
    7842        else:
    7843            identity = None
    7844
    7845        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    7846            option = self._prev.text
    7847        else:
    7848            option = None
    7849
    7850        partition = self._parse_partition()
    7851
    7852        # Fallback case
    7853        if self._curr:
    7854            return self._parse_as_command(start)
    7855
    7856        return self.expression(
    7857            exp.TruncateTable,
    7858            expressions=expressions,
    7859            is_database=is_database,
    7860            exists=exists,
    7861            cluster=cluster,
    7862            identity=identity,
    7863            option=option,
    7864            partition=partition,
    7865        )
    7866
    7867    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    7868        this = self._parse_ordered(self._parse_opclass)
    7869
    7870        if not self._match(TokenType.WITH):
    7871            return this
    7872
    7873        op = self._parse_var(any_token=True)
    7874
    7875        return self.expression(exp.WithOperator, this=this, op=op)
    7876
    7877    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    7878        self._match(TokenType.EQ)
    7879        self._match(TokenType.L_PAREN)
    7880
    7881        opts: t.List[t.Optional[exp.Expression]] = []
    7882        while self._curr and not self._match(TokenType.R_PAREN):
    7883            if self._match_text_seq("FORMAT_NAME", "="):
    7884                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
    7885                # so we parse it separately to use _parse_field()
    7886                prop = self.expression(
    7887                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
    7888                )
    7889                opts.append(prop)
    7890            else:
    7891                opts.append(self._parse_property())
    7892
    7893            self._match(TokenType.COMMA)
    7894
    7895        return opts
    7896
    7897    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    7898        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    7899
    7900        options = []
    7901        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    7902            option = self._parse_var(any_token=True)
    7903            prev = self._prev.text.upper()
    7904
    7905            # Different dialects might separate options and values by white space, "=" and "AS"
    7906            self._match(TokenType.EQ)
    7907            self._match(TokenType.ALIAS)
    7908
    7909            param = self.expression(exp.CopyParameter, this=option)
    7910
    7911            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    7912                TokenType.L_PAREN, advance=False
    7913            ):
    7914                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    7915                param.set("expressions", self._parse_wrapped_options())
    7916            elif prev == "FILE_FORMAT":
    7917                # T-SQL's external file format case
    7918                param.set("expression", self._parse_field())
    7919            else:
    7920                param.set("expression", self._parse_unquoted_field())
    7921
    7922            options.append(param)
    7923            self._match(sep)
    7924
    7925        return options
    7926
    7927    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    7928        expr = self.expression(exp.Credentials)
    7929
    7930        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    7931            expr.set("storage", self._parse_field())
    7932        if self._match_text_seq("CREDENTIALS"):
    7933            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    7934            creds = (
    7935                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    7936            )
    7937            expr.set("credentials", creds)
    7938        if self._match_text_seq("ENCRYPTION"):
    7939            expr.set("encryption", self._parse_wrapped_options())
    7940        if self._match_text_seq("IAM_ROLE"):
    7941            expr.set("iam_role", self._parse_field())
    7942        if self._match_text_seq("REGION"):
    7943            expr.set("region", self._parse_field())
    7944
    7945        return expr
    7946
    7947    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    7948        return self._parse_field()
    7949
    7950    def _parse_copy(self) -> exp.Copy | exp.Command:
    7951        start = self._prev
    7952
    7953        self._match(TokenType.INTO)
    7954
    7955        this = (
    7956            self._parse_select(nested=True, parse_subquery_alias=False)
    7957            if self._match(TokenType.L_PAREN, advance=False)
    7958            else self._parse_table(schema=True)
    7959        )
    7960
    7961        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    7962
    7963        files = self._parse_csv(self._parse_file_location)
    7964        credentials = self._parse_credentials()
    7965
    7966        self._match_text_seq("WITH")
    7967
    7968        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    7969
    7970        # Fallback case
    7971        if self._curr:
    7972            return self._parse_as_command(start)
    7973
    7974        return self.expression(
    7975            exp.Copy,
    7976            this=this,
    7977            kind=kind,
    7978            credentials=credentials,
    7979            files=files,
    7980            params=params,
    7981        )
    7982
    7983    def _parse_normalize(self) -> exp.Normalize:
    7984        return self.expression(
    7985            exp.Normalize,
    7986            this=self._parse_bitwise(),
    7987            form=self._match(TokenType.COMMA) and self._parse_var(),
    7988        )
    7989
    7990    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
    7991        args = self._parse_csv(lambda: self._parse_lambda())
    7992
    7993        this = seq_get(args, 0)
    7994        decimals = seq_get(args, 1)
    7995
    7996        return expr_type(
    7997            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
    7998        )
    7999
    8000    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
    8001        if self._match_text_seq("COLUMNS", "(", advance=False):
    8002            this = self._parse_function()
    8003            if isinstance(this, exp.Columns):
    8004                this.set("unpack", True)
    8005            return this
    8006
    8007        return self.expression(
    8008            exp.Star,
    8009            **{  # type: ignore
    8010                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
    8011                "replace": self._parse_star_op("REPLACE"),
    8012                "rename": self._parse_star_op("RENAME"),
    8013            },
    8014        )
    8015
    8016    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
    8017        privilege_parts = []
    8018
    8019        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
    8020        # (end of privilege list) or L_PAREN (start of column list) are met
    8021        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
    8022            privilege_parts.append(self._curr.text.upper())
    8023            self._advance()
    8024
    8025        this = exp.var(" ".join(privilege_parts))
    8026        expressions = (
    8027            self._parse_wrapped_csv(self._parse_column)
    8028            if self._match(TokenType.L_PAREN, advance=False)
    8029            else None
    8030        )
    8031
    8032        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
    8033
    8034    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
    8035        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
    8036        principal = self._parse_id_var()
    8037
    8038        if not principal:
    8039            return None
    8040
    8041        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
    8042
    8043    def _parse_grant(self) -> exp.Grant | exp.Command:
    8044        start = self._prev
    8045
    8046        privileges = self._parse_csv(self._parse_grant_privilege)
    8047
    8048        self._match(TokenType.ON)
    8049        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    8050
    8051        # Attempt to parse the securable e.g. MySQL allows names
    8052        # such as "foo.*", "*.*" which are not easily parseable yet
    8053        securable = self._try_parse(self._parse_table_parts)
    8054
    8055        if not securable or not self._match_text_seq("TO"):
    8056            return self._parse_as_command(start)
    8057
    8058        principals = self._parse_csv(self._parse_grant_principal)
    8059
    8060        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
    8061
    8062        if self._curr:
    8063            return self._parse_as_command(start)
    8064
    8065        return self.expression(
    8066            exp.Grant,
    8067            privileges=privileges,
    8068            kind=kind,
    8069            securable=securable,
    8070            principals=principals,
    8071            grant_option=grant_option,
    8072        )
    8073
    8074    def _parse_overlay(self) -> exp.Overlay:
    8075        return self.expression(
    8076            exp.Overlay,
    8077            **{  # type: ignore
    8078                "this": self._parse_bitwise(),
    8079                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
    8080                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
    8081                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
    8082            },
    8083        )

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: View Source

    27def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    28    if len(args) == 1 and args[0].is_star:
    29        return exp.StarMap(this=args[0])
    30
    31    keys = []
    32    values = []
    33    for i in range(0, len(args), 2):
    34        keys.append(args[i])
    35        values.append(args[i + 1])
    36
    37    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: View Source

    40def build_like(args: t.List) -> exp.Escape | exp.Like:
    41    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    42    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]]: View Source

    45def binary_range_parser(
    46    expr_type: t.Type[exp.Expression], reverse_args: bool = False
    47) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
    48    def _parse_binary_range(
    49        self: Parser, this: t.Optional[exp.Expression]
    50    ) -> t.Optional[exp.Expression]:
    51        expression = self._parse_bitwise()
    52        if reverse_args:
    53            this, expression = expression, this
    54        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
    55
    56    return _parse_binary_range

def build_logarithm( args: List, dialect: sqlglot.dialects.Dialect) -> sqlglot.expressions.Func: View Source

    59def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    60    # Default argument order is base, expression
    61    this = seq_get(args, 0)
    62    expression = seq_get(args, 1)
    63
    64    if expression:
    65        if not dialect.LOG_BASE_FIRST:
    66            this, expression = expression, this
    67        return exp.Log(this=this, expression=expression)
    68
    69    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) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex: View Source

    72def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
    73    arg = seq_get(args, 0)
    74    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: View Source

    77def build_lower(args: t.List) -> exp.Lower | exp.Hex:
    78    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
    79    arg = seq_get(args, 0)
    80    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: View Source

    83def build_upper(args: t.List) -> exp.Upper | exp.Hex:
    84    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
    85    arg = seq_get(args, 0)
    86    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], ~E]: View Source

    89def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
    90    def _builder(args: t.List, dialect: Dialect) -> E:
    91        expression = expr_type(
    92            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
    93        )
    94        if len(args) > 2 and expr_type is exp.JSONExtract:
    95            expression.set("expressions", args[2:])
    96
    97        return expression
    98
    99    return _builder

def build_mod(args: List) -> sqlglot.expressions.Mod: View Source

    102def build_mod(args: t.List) -> exp.Mod:
    103    this = seq_get(args, 0)
    104    expression = seq_get(args, 1)
    105
    106    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
    107    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
    108    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
    109
    110    return exp.Mod(this=this, expression=expression)

def build_pad(args: List, is_left: bool = True): View Source

    113def build_pad(args: t.List, is_left: bool = True):
    114    return exp.Pad(
    115        this=seq_get(args, 0),
    116        expression=seq_get(args, 1),
    117        fill_pattern=seq_get(args, 2),
    118        is_left=is_left,
    119    )

def build_array_constructor( exp_class: Type[~E], args: List, bracket_kind: sqlglot.tokens.TokenType, dialect: sqlglot.dialects.Dialect) -> sqlglot.expressions.Expression: View Source

    122def build_array_constructor(
    123    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
    124) -> exp.Expression:
    125    array_exp = exp_class(expressions=args)
    126
    127    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
    128        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
    129
    130    return array_exp

def build_convert_timezone( args: List, default_source_tz: Optional[str] = None) -> Union[sqlglot.expressions.ConvertTimezone, sqlglot.expressions.Anonymous]: View Source

    133def build_convert_timezone(
    134    args: t.List, default_source_tz: t.Optional[str] = None
    135) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
    136    if len(args) == 2:
    137        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
    138        return exp.ConvertTimezone(
    139            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
    140        )
    141
    142    return exp.ConvertTimezone.from_arg_list(args)

def build_trim(args: List, is_left: bool = True): View Source

    145def build_trim(args: t.List, is_left: bool = True):
    146    return exp.Trim(
    147        this=seq_get(args, 0),
    148        expression=seq_get(args, 1),
    149        position="LEADING" if is_left else "TRAILING",
    150    )

def build_coalesce( args: List, is_nvl: Optional[bool] = None) -> sqlglot.expressions.Coalesce: View Source

    153def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
    154    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)

def build_locate_strposition(args: List): View Source

    157def build_locate_strposition(args: t.List):
    158    return exp.StrPosition(
    159        this=seq_get(args, 1),
    160        substr=seq_get(args, 0),
    161        position=seq_get(args, 2),
    162    )

class Parser: View Source

     175class Parser(metaclass=_Parser):
     176    """
     177    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     178
     179    Args:
     180        error_level: The desired error level.
     181            Default: ErrorLevel.IMMEDIATE
     182        error_message_context: The amount of context to capture from a query string when displaying
     183            the error message (in number of characters).
     184            Default: 100
     185        max_errors: Maximum number of error messages to include in a raised ParseError.
     186            This is only relevant if error_level is ErrorLevel.RAISE.
     187            Default: 3
     188    """
     189
     190    FUNCTIONS: t.Dict[str, t.Callable] = {
     191        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     192        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
     193        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
     194        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
     195            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     196        ),
     197        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
     198            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     199        ),
     200        "CHAR": lambda args: exp.Chr(expressions=args),
     201        "CHR": lambda args: exp.Chr(expressions=args),
     202        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
     203        "CONCAT": lambda args, dialect: exp.Concat(
     204            expressions=args,
     205            safe=not dialect.STRICT_STRING_CONCAT,
     206            coalesce=dialect.CONCAT_COALESCE,
     207        ),
     208        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     209            expressions=args,
     210            safe=not dialect.STRICT_STRING_CONCAT,
     211            coalesce=dialect.CONCAT_COALESCE,
     212        ),
     213        "CONVERT_TIMEZONE": build_convert_timezone,
     214        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     215            this=seq_get(args, 0),
     216            to=exp.DataType(this=exp.DataType.Type.TEXT),
     217        ),
     218        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
     219            start=seq_get(args, 0),
     220            end=seq_get(args, 1),
     221            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
     222        ),
     223        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     224        "HEX": build_hex,
     225        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     226        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     227        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     228        "LIKE": build_like,
     229        "LOG": build_logarithm,
     230        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     231        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     232        "LOWER": build_lower,
     233        "LPAD": lambda args: build_pad(args),
     234        "LEFTPAD": lambda args: build_pad(args),
     235        "LTRIM": lambda args: build_trim(args),
     236        "MOD": build_mod,
     237        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
     238        "RPAD": lambda args: build_pad(args, is_left=False),
     239        "RTRIM": lambda args: build_trim(args, is_left=False),
     240        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
     241        if len(args) != 2
     242        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
     243        "STRPOS": exp.StrPosition.from_arg_list,
     244        "CHARINDEX": lambda args: build_locate_strposition(args),
     245        "INSTR": exp.StrPosition.from_arg_list,
     246        "LOCATE": lambda args: build_locate_strposition(args),
     247        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     248            this=seq_get(args, 0),
     249            to=exp.DataType(this=exp.DataType.Type.TEXT),
     250        ),
     251        "TO_HEX": build_hex,
     252        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     253            this=exp.Cast(
     254                this=seq_get(args, 0),
     255                to=exp.DataType(this=exp.DataType.Type.TEXT),
     256            ),
     257            start=exp.Literal.number(1),
     258            length=exp.Literal.number(10),
     259        ),
     260        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
     261        "UPPER": build_upper,
     262        "VAR_MAP": build_var_map,
     263    }
     264
     265    NO_PAREN_FUNCTIONS = {
     266        TokenType.CURRENT_DATE: exp.CurrentDate,
     267        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     268        TokenType.CURRENT_TIME: exp.CurrentTime,
     269        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     270        TokenType.CURRENT_USER: exp.CurrentUser,
     271    }
     272
     273    STRUCT_TYPE_TOKENS = {
     274        TokenType.NESTED,
     275        TokenType.OBJECT,
     276        TokenType.STRUCT,
     277        TokenType.UNION,
     278    }
     279
     280    NESTED_TYPE_TOKENS = {
     281        TokenType.ARRAY,
     282        TokenType.LIST,
     283        TokenType.LOWCARDINALITY,
     284        TokenType.MAP,
     285        TokenType.NULLABLE,
     286        TokenType.RANGE,
     287        *STRUCT_TYPE_TOKENS,
     288    }
     289
     290    ENUM_TYPE_TOKENS = {
     291        TokenType.DYNAMIC,
     292        TokenType.ENUM,
     293        TokenType.ENUM8,
     294        TokenType.ENUM16,
     295    }
     296
     297    AGGREGATE_TYPE_TOKENS = {
     298        TokenType.AGGREGATEFUNCTION,
     299        TokenType.SIMPLEAGGREGATEFUNCTION,
     300    }
     301
     302    TYPE_TOKENS = {
     303        TokenType.BIT,
     304        TokenType.BOOLEAN,
     305        TokenType.TINYINT,
     306        TokenType.UTINYINT,
     307        TokenType.SMALLINT,
     308        TokenType.USMALLINT,
     309        TokenType.INT,
     310        TokenType.UINT,
     311        TokenType.BIGINT,
     312        TokenType.UBIGINT,
     313        TokenType.INT128,
     314        TokenType.UINT128,
     315        TokenType.INT256,
     316        TokenType.UINT256,
     317        TokenType.MEDIUMINT,
     318        TokenType.UMEDIUMINT,
     319        TokenType.FIXEDSTRING,
     320        TokenType.FLOAT,
     321        TokenType.DOUBLE,
     322        TokenType.UDOUBLE,
     323        TokenType.CHAR,
     324        TokenType.NCHAR,
     325        TokenType.VARCHAR,
     326        TokenType.NVARCHAR,
     327        TokenType.BPCHAR,
     328        TokenType.TEXT,
     329        TokenType.MEDIUMTEXT,
     330        TokenType.LONGTEXT,
     331        TokenType.MEDIUMBLOB,
     332        TokenType.LONGBLOB,
     333        TokenType.BINARY,
     334        TokenType.VARBINARY,
     335        TokenType.JSON,
     336        TokenType.JSONB,
     337        TokenType.INTERVAL,
     338        TokenType.TINYBLOB,
     339        TokenType.TINYTEXT,
     340        TokenType.TIME,
     341        TokenType.TIMETZ,
     342        TokenType.TIMESTAMP,
     343        TokenType.TIMESTAMP_S,
     344        TokenType.TIMESTAMP_MS,
     345        TokenType.TIMESTAMP_NS,
     346        TokenType.TIMESTAMPTZ,
     347        TokenType.TIMESTAMPLTZ,
     348        TokenType.TIMESTAMPNTZ,
     349        TokenType.DATETIME,
     350        TokenType.DATETIME2,
     351        TokenType.DATETIME64,
     352        TokenType.SMALLDATETIME,
     353        TokenType.DATE,
     354        TokenType.DATE32,
     355        TokenType.INT4RANGE,
     356        TokenType.INT4MULTIRANGE,
     357        TokenType.INT8RANGE,
     358        TokenType.INT8MULTIRANGE,
     359        TokenType.NUMRANGE,
     360        TokenType.NUMMULTIRANGE,
     361        TokenType.TSRANGE,
     362        TokenType.TSMULTIRANGE,
     363        TokenType.TSTZRANGE,
     364        TokenType.TSTZMULTIRANGE,
     365        TokenType.DATERANGE,
     366        TokenType.DATEMULTIRANGE,
     367        TokenType.DECIMAL,
     368        TokenType.DECIMAL32,
     369        TokenType.DECIMAL64,
     370        TokenType.DECIMAL128,
     371        TokenType.DECIMAL256,
     372        TokenType.UDECIMAL,
     373        TokenType.BIGDECIMAL,
     374        TokenType.UUID,
     375        TokenType.GEOGRAPHY,
     376        TokenType.GEOMETRY,
     377        TokenType.POINT,
     378        TokenType.RING,
     379        TokenType.LINESTRING,
     380        TokenType.MULTILINESTRING,
     381        TokenType.POLYGON,
     382        TokenType.MULTIPOLYGON,
     383        TokenType.HLLSKETCH,
     384        TokenType.HSTORE,
     385        TokenType.PSEUDO_TYPE,
     386        TokenType.SUPER,
     387        TokenType.SERIAL,
     388        TokenType.SMALLSERIAL,
     389        TokenType.BIGSERIAL,
     390        TokenType.XML,
     391        TokenType.YEAR,
     392        TokenType.USERDEFINED,
     393        TokenType.MONEY,
     394        TokenType.SMALLMONEY,
     395        TokenType.ROWVERSION,
     396        TokenType.IMAGE,
     397        TokenType.VARIANT,
     398        TokenType.VECTOR,
     399        TokenType.OBJECT,
     400        TokenType.OBJECT_IDENTIFIER,
     401        TokenType.INET,
     402        TokenType.IPADDRESS,
     403        TokenType.IPPREFIX,
     404        TokenType.IPV4,
     405        TokenType.IPV6,
     406        TokenType.UNKNOWN,
     407        TokenType.NULL,
     408        TokenType.NAME,
     409        TokenType.TDIGEST,
     410        TokenType.DYNAMIC,
     411        *ENUM_TYPE_TOKENS,
     412        *NESTED_TYPE_TOKENS,
     413        *AGGREGATE_TYPE_TOKENS,
     414    }
     415
     416    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     417        TokenType.BIGINT: TokenType.UBIGINT,
     418        TokenType.INT: TokenType.UINT,
     419        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     420        TokenType.SMALLINT: TokenType.USMALLINT,
     421        TokenType.TINYINT: TokenType.UTINYINT,
     422        TokenType.DECIMAL: TokenType.UDECIMAL,
     423        TokenType.DOUBLE: TokenType.UDOUBLE,
     424    }
     425
     426    SUBQUERY_PREDICATES = {
     427        TokenType.ANY: exp.Any,
     428        TokenType.ALL: exp.All,
     429        TokenType.EXISTS: exp.Exists,
     430        TokenType.SOME: exp.Any,
     431    }
     432
     433    RESERVED_TOKENS = {
     434        *Tokenizer.SINGLE_TOKENS.values(),
     435        TokenType.SELECT,
     436    } - {TokenType.IDENTIFIER}
     437
     438    DB_CREATABLES = {
     439        TokenType.DATABASE,
     440        TokenType.DICTIONARY,
     441        TokenType.MODEL,
     442        TokenType.NAMESPACE,
     443        TokenType.SCHEMA,
     444        TokenType.SEQUENCE,
     445        TokenType.SINK,
     446        TokenType.SOURCE,
     447        TokenType.STORAGE_INTEGRATION,
     448        TokenType.STREAMLIT,
     449        TokenType.TABLE,
     450        TokenType.TAG,
     451        TokenType.VIEW,
     452        TokenType.WAREHOUSE,
     453    }
     454
     455    CREATABLES = {
     456        TokenType.COLUMN,
     457        TokenType.CONSTRAINT,
     458        TokenType.FOREIGN_KEY,
     459        TokenType.FUNCTION,
     460        TokenType.INDEX,
     461        TokenType.PROCEDURE,
     462        *DB_CREATABLES,
     463    }
     464
     465    ALTERABLES = {
     466        TokenType.INDEX,
     467        TokenType.TABLE,
     468        TokenType.VIEW,
     469    }
     470
     471    # Tokens that can represent identifiers
     472    ID_VAR_TOKENS = {
     473        TokenType.ALL,
     474        TokenType.ATTACH,
     475        TokenType.VAR,
     476        TokenType.ANTI,
     477        TokenType.APPLY,
     478        TokenType.ASC,
     479        TokenType.ASOF,
     480        TokenType.AUTO_INCREMENT,
     481        TokenType.BEGIN,
     482        TokenType.BPCHAR,
     483        TokenType.CACHE,
     484        TokenType.CASE,
     485        TokenType.COLLATE,
     486        TokenType.COMMAND,
     487        TokenType.COMMENT,
     488        TokenType.COMMIT,
     489        TokenType.CONSTRAINT,
     490        TokenType.COPY,
     491        TokenType.CUBE,
     492        TokenType.CURRENT_SCHEMA,
     493        TokenType.DEFAULT,
     494        TokenType.DELETE,
     495        TokenType.DESC,
     496        TokenType.DESCRIBE,
     497        TokenType.DETACH,
     498        TokenType.DICTIONARY,
     499        TokenType.DIV,
     500        TokenType.END,
     501        TokenType.EXECUTE,
     502        TokenType.EXPORT,
     503        TokenType.ESCAPE,
     504        TokenType.FALSE,
     505        TokenType.FIRST,
     506        TokenType.FILTER,
     507        TokenType.FINAL,
     508        TokenType.FORMAT,
     509        TokenType.FULL,
     510        TokenType.IDENTIFIER,
     511        TokenType.IS,
     512        TokenType.ISNULL,
     513        TokenType.INTERVAL,
     514        TokenType.KEEP,
     515        TokenType.KILL,
     516        TokenType.LEFT,
     517        TokenType.LIMIT,
     518        TokenType.LOAD,
     519        TokenType.MERGE,
     520        TokenType.NATURAL,
     521        TokenType.NEXT,
     522        TokenType.OFFSET,
     523        TokenType.OPERATOR,
     524        TokenType.ORDINALITY,
     525        TokenType.OVERLAPS,
     526        TokenType.OVERWRITE,
     527        TokenType.PARTITION,
     528        TokenType.PERCENT,
     529        TokenType.PIVOT,
     530        TokenType.PRAGMA,
     531        TokenType.RANGE,
     532        TokenType.RECURSIVE,
     533        TokenType.REFERENCES,
     534        TokenType.REFRESH,
     535        TokenType.RENAME,
     536        TokenType.REPLACE,
     537        TokenType.RIGHT,
     538        TokenType.ROLLUP,
     539        TokenType.ROW,
     540        TokenType.ROWS,
     541        TokenType.SEMI,
     542        TokenType.SET,
     543        TokenType.SETTINGS,
     544        TokenType.SHOW,
     545        TokenType.TEMPORARY,
     546        TokenType.TOP,
     547        TokenType.TRUE,
     548        TokenType.TRUNCATE,
     549        TokenType.UNIQUE,
     550        TokenType.UNNEST,
     551        TokenType.UNPIVOT,
     552        TokenType.UPDATE,
     553        TokenType.USE,
     554        TokenType.VOLATILE,
     555        TokenType.WINDOW,
     556        *CREATABLES,
     557        *SUBQUERY_PREDICATES,
     558        *TYPE_TOKENS,
     559        *NO_PAREN_FUNCTIONS,
     560    }
     561    ID_VAR_TOKENS.remove(TokenType.UNION)
     562
     563    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     564        TokenType.ANTI,
     565        TokenType.APPLY,
     566        TokenType.ASOF,
     567        TokenType.FULL,
     568        TokenType.LEFT,
     569        TokenType.LOCK,
     570        TokenType.NATURAL,
     571        TokenType.RIGHT,
     572        TokenType.SEMI,
     573        TokenType.WINDOW,
     574    }
     575
     576    ALIAS_TOKENS = ID_VAR_TOKENS
     577
     578    ARRAY_CONSTRUCTORS = {
     579        "ARRAY": exp.Array,
     580        "LIST": exp.List,
     581    }
     582
     583    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     584
     585    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     586
     587    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     588
     589    FUNC_TOKENS = {
     590        TokenType.COLLATE,
     591        TokenType.COMMAND,
     592        TokenType.CURRENT_DATE,
     593        TokenType.CURRENT_DATETIME,
     594        TokenType.CURRENT_SCHEMA,
     595        TokenType.CURRENT_TIMESTAMP,
     596        TokenType.CURRENT_TIME,
     597        TokenType.CURRENT_USER,
     598        TokenType.FILTER,
     599        TokenType.FIRST,
     600        TokenType.FORMAT,
     601        TokenType.GLOB,
     602        TokenType.IDENTIFIER,
     603        TokenType.INDEX,
     604        TokenType.ISNULL,
     605        TokenType.ILIKE,
     606        TokenType.INSERT,
     607        TokenType.LIKE,
     608        TokenType.MERGE,
     609        TokenType.NEXT,
     610        TokenType.OFFSET,
     611        TokenType.PRIMARY_KEY,
     612        TokenType.RANGE,
     613        TokenType.REPLACE,
     614        TokenType.RLIKE,
     615        TokenType.ROW,
     616        TokenType.UNNEST,
     617        TokenType.VAR,
     618        TokenType.LEFT,
     619        TokenType.RIGHT,
     620        TokenType.SEQUENCE,
     621        TokenType.DATE,
     622        TokenType.DATETIME,
     623        TokenType.TABLE,
     624        TokenType.TIMESTAMP,
     625        TokenType.TIMESTAMPTZ,
     626        TokenType.TRUNCATE,
     627        TokenType.WINDOW,
     628        TokenType.XOR,
     629        *TYPE_TOKENS,
     630        *SUBQUERY_PREDICATES,
     631    }
     632
     633    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     634        TokenType.AND: exp.And,
     635    }
     636
     637    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     638        TokenType.COLON_EQ: exp.PropertyEQ,
     639    }
     640
     641    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     642        TokenType.OR: exp.Or,
     643    }
     644
     645    EQUALITY = {
     646        TokenType.EQ: exp.EQ,
     647        TokenType.NEQ: exp.NEQ,
     648        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     649    }
     650
     651    COMPARISON = {
     652        TokenType.GT: exp.GT,
     653        TokenType.GTE: exp.GTE,
     654        TokenType.LT: exp.LT,
     655        TokenType.LTE: exp.LTE,
     656    }
     657
     658    BITWISE = {
     659        TokenType.AMP: exp.BitwiseAnd,
     660        TokenType.CARET: exp.BitwiseXor,
     661        TokenType.PIPE: exp.BitwiseOr,
     662    }
     663
     664    TERM = {
     665        TokenType.DASH: exp.Sub,
     666        TokenType.PLUS: exp.Add,
     667        TokenType.MOD: exp.Mod,
     668        TokenType.COLLATE: exp.Collate,
     669    }
     670
     671    FACTOR = {
     672        TokenType.DIV: exp.IntDiv,
     673        TokenType.LR_ARROW: exp.Distance,
     674        TokenType.SLASH: exp.Div,
     675        TokenType.STAR: exp.Mul,
     676    }
     677
     678    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     679
     680    TIMES = {
     681        TokenType.TIME,
     682        TokenType.TIMETZ,
     683    }
     684
     685    TIMESTAMPS = {
     686        TokenType.TIMESTAMP,
     687        TokenType.TIMESTAMPTZ,
     688        TokenType.TIMESTAMPLTZ,
     689        *TIMES,
     690    }
     691
     692    SET_OPERATIONS = {
     693        TokenType.UNION,
     694        TokenType.INTERSECT,
     695        TokenType.EXCEPT,
     696    }
     697
     698    JOIN_METHODS = {
     699        TokenType.ASOF,
     700        TokenType.NATURAL,
     701        TokenType.POSITIONAL,
     702    }
     703
     704    JOIN_SIDES = {
     705        TokenType.LEFT,
     706        TokenType.RIGHT,
     707        TokenType.FULL,
     708    }
     709
     710    JOIN_KINDS = {
     711        TokenType.ANTI,
     712        TokenType.CROSS,
     713        TokenType.INNER,
     714        TokenType.OUTER,
     715        TokenType.SEMI,
     716        TokenType.STRAIGHT_JOIN,
     717    }
     718
     719    JOIN_HINTS: t.Set[str] = set()
     720
     721    LAMBDAS = {
     722        TokenType.ARROW: lambda self, expressions: self.expression(
     723            exp.Lambda,
     724            this=self._replace_lambda(
     725                self._parse_assignment(),
     726                expressions,
     727            ),
     728            expressions=expressions,
     729        ),
     730        TokenType.FARROW: lambda self, expressions: self.expression(
     731            exp.Kwarg,
     732            this=exp.var(expressions[0].name),
     733            expression=self._parse_assignment(),
     734        ),
     735    }
     736
     737    COLUMN_OPERATORS = {
     738        TokenType.DOT: None,
     739        TokenType.DOTCOLON: lambda self, this, to: self.expression(
     740            exp.JSONCast,
     741            this=this,
     742            to=to,
     743        ),
     744        TokenType.DCOLON: lambda self, this, to: self.expression(
     745            exp.Cast if self.STRICT_CAST else exp.TryCast,
     746            this=this,
     747            to=to,
     748        ),
     749        TokenType.ARROW: lambda self, this, path: self.expression(
     750            exp.JSONExtract,
     751            this=this,
     752            expression=self.dialect.to_json_path(path),
     753            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     754        ),
     755        TokenType.DARROW: lambda self, this, path: self.expression(
     756            exp.JSONExtractScalar,
     757            this=this,
     758            expression=self.dialect.to_json_path(path),
     759            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     760        ),
     761        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     762            exp.JSONBExtract,
     763            this=this,
     764            expression=path,
     765        ),
     766        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     767            exp.JSONBExtractScalar,
     768            this=this,
     769            expression=path,
     770        ),
     771        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     772            exp.JSONBContains,
     773            this=this,
     774            expression=key,
     775        ),
     776    }
     777
     778    EXPRESSION_PARSERS = {
     779        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     780        exp.Column: lambda self: self._parse_column(),
     781        exp.Condition: lambda self: self._parse_assignment(),
     782        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
     783        exp.Expression: lambda self: self._parse_expression(),
     784        exp.From: lambda self: self._parse_from(joins=True),
     785        exp.Group: lambda self: self._parse_group(),
     786        exp.Having: lambda self: self._parse_having(),
     787        exp.Hint: lambda self: self._parse_hint_body(),
     788        exp.Identifier: lambda self: self._parse_id_var(),
     789        exp.Join: lambda self: self._parse_join(),
     790        exp.Lambda: lambda self: self._parse_lambda(),
     791        exp.Lateral: lambda self: self._parse_lateral(),
     792        exp.Limit: lambda self: self._parse_limit(),
     793        exp.Offset: lambda self: self._parse_offset(),
     794        exp.Order: lambda self: self._parse_order(),
     795        exp.Ordered: lambda self: self._parse_ordered(),
     796        exp.Properties: lambda self: self._parse_properties(),
     797        exp.Qualify: lambda self: self._parse_qualify(),
     798        exp.Returning: lambda self: self._parse_returning(),
     799        exp.Select: lambda self: self._parse_select(),
     800        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     801        exp.Table: lambda self: self._parse_table_parts(),
     802        exp.TableAlias: lambda self: self._parse_table_alias(),
     803        exp.Tuple: lambda self: self._parse_value(),
     804        exp.Whens: lambda self: self._parse_when_matched(),
     805        exp.Where: lambda self: self._parse_where(),
     806        exp.Window: lambda self: self._parse_named_window(),
     807        exp.With: lambda self: self._parse_with(),
     808        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     809    }
     810
     811    STATEMENT_PARSERS = {
     812        TokenType.ALTER: lambda self: self._parse_alter(),
     813        TokenType.ANALYZE: lambda self: self._parse_analyze(),
     814        TokenType.BEGIN: lambda self: self._parse_transaction(),
     815        TokenType.CACHE: lambda self: self._parse_cache(),
     816        TokenType.COMMENT: lambda self: self._parse_comment(),
     817        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     818        TokenType.COPY: lambda self: self._parse_copy(),
     819        TokenType.CREATE: lambda self: self._parse_create(),
     820        TokenType.DELETE: lambda self: self._parse_delete(),
     821        TokenType.DESC: lambda self: self._parse_describe(),
     822        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     823        TokenType.DROP: lambda self: self._parse_drop(),
     824        TokenType.GRANT: lambda self: self._parse_grant(),
     825        TokenType.INSERT: lambda self: self._parse_insert(),
     826        TokenType.KILL: lambda self: self._parse_kill(),
     827        TokenType.LOAD: lambda self: self._parse_load(),
     828        TokenType.MERGE: lambda self: self._parse_merge(),
     829        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     830        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     831        TokenType.REFRESH: lambda self: self._parse_refresh(),
     832        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     833        TokenType.SET: lambda self: self._parse_set(),
     834        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     835        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     836        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
     837        TokenType.UPDATE: lambda self: self._parse_update(),
     838        TokenType.USE: lambda self: self._parse_use(),
     839        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
     840    }
     841
     842    UNARY_PARSERS = {
     843        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     844        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     845        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     846        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     847        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     848        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     849    }
     850
     851    STRING_PARSERS = {
     852        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     853            exp.RawString, this=token.text
     854        ),
     855        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     856            exp.National, this=token.text
     857        ),
     858        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     859        TokenType.STRING: lambda self, token: self.expression(
     860            exp.Literal, this=token.text, is_string=True
     861        ),
     862        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     863            exp.UnicodeString,
     864            this=token.text,
     865            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     866        ),
     867    }
     868
     869    NUMERIC_PARSERS = {
     870        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     871        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     872        TokenType.HEX_STRING: lambda self, token: self.expression(
     873            exp.HexString,
     874            this=token.text,
     875            is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
     876        ),
     877        TokenType.NUMBER: lambda self, token: self.expression(
     878            exp.Literal, this=token.text, is_string=False
     879        ),
     880    }
     881
     882    PRIMARY_PARSERS = {
     883        **STRING_PARSERS,
     884        **NUMERIC_PARSERS,
     885        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     886        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     887        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     888        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     889        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     890        TokenType.STAR: lambda self, _: self._parse_star_ops(),
     891    }
     892
     893    PLACEHOLDER_PARSERS = {
     894        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     895        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     896        TokenType.COLON: lambda self: (
     897            self.expression(exp.Placeholder, this=self._prev.text)
     898            if self._match_set(self.ID_VAR_TOKENS)
     899            else None
     900        ),
     901    }
     902
     903    RANGE_PARSERS = {
     904        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
     905        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     906        TokenType.GLOB: binary_range_parser(exp.Glob),
     907        TokenType.ILIKE: binary_range_parser(exp.ILike),
     908        TokenType.IN: lambda self, this: self._parse_in(this),
     909        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     910        TokenType.IS: lambda self, this: self._parse_is(this),
     911        TokenType.LIKE: binary_range_parser(exp.Like),
     912        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
     913        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     914        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     915        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     916        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     917    }
     918
     919    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     920        "ALLOWED_VALUES": lambda self: self.expression(
     921            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     922        ),
     923        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     924        "AUTO": lambda self: self._parse_auto_property(),
     925        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     926        "BACKUP": lambda self: self.expression(
     927            exp.BackupProperty, this=self._parse_var(any_token=True)
     928        ),
     929        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     930        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     931        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     932        "CHECKSUM": lambda self: self._parse_checksum(),
     933        "CLUSTER BY": lambda self: self._parse_cluster(),
     934        "CLUSTERED": lambda self: self._parse_clustered_by(),
     935        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     936            exp.CollateProperty, **kwargs
     937        ),
     938        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     939        "CONTAINS": lambda self: self._parse_contains_property(),
     940        "COPY": lambda self: self._parse_copy_property(),
     941        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     942        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     943        "DEFINER": lambda self: self._parse_definer(),
     944        "DETERMINISTIC": lambda self: self.expression(
     945            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     946        ),
     947        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
     948        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
     949        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
     950        "DISTKEY": lambda self: self._parse_distkey(),
     951        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     952        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
     953        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     954        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     955        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     956        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     957        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     958        "FREESPACE": lambda self: self._parse_freespace(),
     959        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     960        "HEAP": lambda self: self.expression(exp.HeapProperty),
     961        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     962        "IMMUTABLE": lambda self: self.expression(
     963            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     964        ),
     965        "INHERITS": lambda self: self.expression(
     966            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     967        ),
     968        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     969        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     970        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     971        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     972        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     973        "LIKE": lambda self: self._parse_create_like(),
     974        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     975        "LOCK": lambda self: self._parse_locking(),
     976        "LOCKING": lambda self: self._parse_locking(),
     977        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     978        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     979        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     980        "MODIFIES": lambda self: self._parse_modifies_property(),
     981        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     982        "NO": lambda self: self._parse_no_property(),
     983        "ON": lambda self: self._parse_on_property(),
     984        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     985        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     986        "PARTITION": lambda self: self._parse_partitioned_of(),
     987        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     988        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     989        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     990        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     991        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     992        "READS": lambda self: self._parse_reads_property(),
     993        "REMOTE": lambda self: self._parse_remote_with_connection(),
     994        "RETURNS": lambda self: self._parse_returns(),
     995        "STRICT": lambda self: self.expression(exp.StrictProperty),
     996        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
     997        "ROW": lambda self: self._parse_row(),
     998        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     999        "SAMPLE": lambda self: self.expression(
    1000            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
    1001        ),
    1002        "SECURE": lambda self: self.expression(exp.SecureProperty),
    1003        "SECURITY": lambda self: self._parse_security(),
    1004        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
    1005        "SETTINGS": lambda self: self._parse_settings_property(),
    1006        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
    1007        "SORTKEY": lambda self: self._parse_sortkey(),
    1008        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
    1009        "STABLE": lambda self: self.expression(
    1010            exp.StabilityProperty, this=exp.Literal.string("STABLE")
    1011        ),
    1012        "STORED": lambda self: self._parse_stored(),
    1013        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
    1014        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
    1015        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
    1016        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
    1017        "TO": lambda self: self._parse_to_table(),
    1018        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
    1019        "TRANSFORM": lambda self: self.expression(
    1020            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
    1021        ),
    1022        "TTL": lambda self: self._parse_ttl(),
    1023        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
    1024        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
    1025        "VOLATILE": lambda self: self._parse_volatile_property(),
    1026        "WITH": lambda self: self._parse_with_property(),
    1027    }
    1028
    1029    CONSTRAINT_PARSERS = {
    1030        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
    1031        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
    1032        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
    1033        "CHARACTER SET": lambda self: self.expression(
    1034            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
    1035        ),
    1036        "CHECK": lambda self: self.expression(
    1037            exp.CheckColumnConstraint,
    1038            this=self._parse_wrapped(self._parse_assignment),
    1039            enforced=self._match_text_seq("ENFORCED"),
    1040        ),
    1041        "COLLATE": lambda self: self.expression(
    1042            exp.CollateColumnConstraint,
    1043            this=self._parse_identifier() or self._parse_column(),
    1044        ),
    1045        "COMMENT": lambda self: self.expression(
    1046            exp.CommentColumnConstraint, this=self._parse_string()
    1047        ),
    1048        "COMPRESS": lambda self: self._parse_compress(),
    1049        "CLUSTERED": lambda self: self.expression(
    1050            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1051        ),
    1052        "NONCLUSTERED": lambda self: self.expression(
    1053            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1054        ),
    1055        "DEFAULT": lambda self: self.expression(
    1056            exp.DefaultColumnConstraint, this=self._parse_bitwise()
    1057        ),
    1058        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
    1059        "EPHEMERAL": lambda self: self.expression(
    1060            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
    1061        ),
    1062        "EXCLUDE": lambda self: self.expression(
    1063            exp.ExcludeColumnConstraint, this=self._parse_index_params()
    1064        ),
    1065        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
    1066        "FORMAT": lambda self: self.expression(
    1067            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
    1068        ),
    1069        "GENERATED": lambda self: self._parse_generated_as_identity(),
    1070        "IDENTITY": lambda self: self._parse_auto_increment(),
    1071        "INLINE": lambda self: self._parse_inline(),
    1072        "LIKE": lambda self: self._parse_create_like(),
    1073        "NOT": lambda self: self._parse_not_constraint(),
    1074        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
    1075        "ON": lambda self: (
    1076            self._match(TokenType.UPDATE)
    1077            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
    1078        )
    1079        or self.expression(exp.OnProperty, this=self._parse_id_var()),
    1080        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
    1081        "PERIOD": lambda self: self._parse_period_for_system_time(),
    1082        "PRIMARY KEY": lambda self: self._parse_primary_key(),
    1083        "REFERENCES": lambda self: self._parse_references(match=False),
    1084        "TITLE": lambda self: self.expression(
    1085            exp.TitleColumnConstraint, this=self._parse_var_or_string()
    1086        ),
    1087        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
    1088        "UNIQUE": lambda self: self._parse_unique(),
    1089        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
    1090        "WATERMARK": lambda self: self.expression(
    1091            exp.WatermarkColumnConstraint,
    1092            this=self._match(TokenType.FOR) and self._parse_column(),
    1093            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
    1094        ),
    1095        "WITH": lambda self: self.expression(
    1096            exp.Properties, expressions=self._parse_wrapped_properties()
    1097        ),
    1098    }
    1099
    1100    ALTER_PARSERS = {
    1101        "ADD": lambda self: self._parse_alter_table_add(),
    1102        "AS": lambda self: self._parse_select(),
    1103        "ALTER": lambda self: self._parse_alter_table_alter(),
    1104        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
    1105        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
    1106        "DROP": lambda self: self._parse_alter_table_drop(),
    1107        "RENAME": lambda self: self._parse_alter_table_rename(),
    1108        "SET": lambda self: self._parse_alter_table_set(),
    1109        "SWAP": lambda self: self.expression(
    1110            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
    1111        ),
    1112    }
    1113
    1114    ALTER_ALTER_PARSERS = {
    1115        "DISTKEY": lambda self: self._parse_alter_diststyle(),
    1116        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
    1117        "SORTKEY": lambda self: self._parse_alter_sortkey(),
    1118        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
    1119    }
    1120
    1121    SCHEMA_UNNAMED_CONSTRAINTS = {
    1122        "CHECK",
    1123        "EXCLUDE",
    1124        "FOREIGN KEY",
    1125        "LIKE",
    1126        "PERIOD",
    1127        "PRIMARY KEY",
    1128        "UNIQUE",
    1129        "WATERMARK",
    1130    }
    1131
    1132    NO_PAREN_FUNCTION_PARSERS = {
    1133        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
    1134        "CASE": lambda self: self._parse_case(),
    1135        "CONNECT_BY_ROOT": lambda self: self.expression(
    1136            exp.ConnectByRoot, this=self._parse_column()
    1137        ),
    1138        "IF": lambda self: self._parse_if(),
    1139    }
    1140
    1141    INVALID_FUNC_NAME_TOKENS = {
    1142        TokenType.IDENTIFIER,
    1143        TokenType.STRING,
    1144    }
    1145
    1146    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1147
    1148    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1149
    1150    FUNCTION_PARSERS = {
    1151        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1152        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
    1153        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1154        "DECODE": lambda self: self._parse_decode(),
    1155        "EXTRACT": lambda self: self._parse_extract(),
    1156        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
    1157        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1158        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1159        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1160        "JSON_TABLE": lambda self: self._parse_json_table(),
    1161        "MATCH": lambda self: self._parse_match_against(),
    1162        "NORMALIZE": lambda self: self._parse_normalize(),
    1163        "OPENJSON": lambda self: self._parse_open_json(),
    1164        "OVERLAY": lambda self: self._parse_overlay(),
    1165        "POSITION": lambda self: self._parse_position(),
    1166        "PREDICT": lambda self: self._parse_predict(),
    1167        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1168        "STRING_AGG": lambda self: self._parse_string_agg(),
    1169        "SUBSTRING": lambda self: self._parse_substring(),
    1170        "TRIM": lambda self: self._parse_trim(),
    1171        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1172        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1173        "XMLELEMENT": lambda self: self.expression(
    1174            exp.XMLElement,
    1175            this=self._match_text_seq("NAME") and self._parse_id_var(),
    1176            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
    1177        ),
    1178        "XMLTABLE": lambda self: self._parse_xml_table(),
    1179    }
    1180
    1181    QUERY_MODIFIER_PARSERS = {
    1182        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1183        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1184        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1185        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1186        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1187        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1188        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1189        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1190        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1191        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1192        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1193        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1194        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1195        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1196        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1197        TokenType.CLUSTER_BY: lambda self: (
    1198            "cluster",
    1199            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1200        ),
    1201        TokenType.DISTRIBUTE_BY: lambda self: (
    1202            "distribute",
    1203            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1204        ),
    1205        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1206        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1207        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1208    }
    1209
    1210    SET_PARSERS = {
    1211        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1212        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1213        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1214        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1215    }
    1216
    1217    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1218
    1219    TYPE_LITERAL_PARSERS = {
    1220        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1221    }
    1222
    1223    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1224
    1225    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1226
    1227    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1228
    1229    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1230    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1231        "ISOLATION": (
    1232            ("LEVEL", "REPEATABLE", "READ"),
    1233            ("LEVEL", "READ", "COMMITTED"),
    1234            ("LEVEL", "READ", "UNCOMITTED"),
    1235            ("LEVEL", "SERIALIZABLE"),
    1236        ),
    1237        "READ": ("WRITE", "ONLY"),
    1238    }
    1239
    1240    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1241        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1242    )
    1243    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1244
    1245    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1246        "SCALE": ("EXTEND", "NOEXTEND"),
    1247        "SHARD": ("EXTEND", "NOEXTEND"),
    1248        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1249        **dict.fromkeys(
    1250            (
    1251                "SESSION",
    1252                "GLOBAL",
    1253                "KEEP",
    1254                "NOKEEP",
    1255                "ORDER",
    1256                "NOORDER",
    1257                "NOCACHE",
    1258                "CYCLE",
    1259                "NOCYCLE",
    1260                "NOMINVALUE",
    1261                "NOMAXVALUE",
    1262                "NOSCALE",
    1263                "NOSHARD",
    1264            ),
    1265            tuple(),
    1266        ),
    1267    }
    1268
    1269    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1270
    1271    USABLES: OPTIONS_TYPE = dict.fromkeys(
    1272        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
    1273    )
    1274
    1275    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1276
    1277    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
    1278        "TYPE": ("EVOLUTION",),
    1279        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
    1280    }
    1281
    1282    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
    1283
    1284    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
    1285
    1286    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
    1287        "NOT": ("ENFORCED",),
    1288        "MATCH": (
    1289            "FULL",
    1290            "PARTIAL",
    1291            "SIMPLE",
    1292        ),
    1293        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
    1294        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
    1295    }
    1296
    1297    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1298
    1299    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1300    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
    1301    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1302
    1303    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1304
    1305    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1306
    1307    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1308
    1309    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1310
    1311    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1312    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1313    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1314
    1315    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1316
    1317    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1318
    1319    ADD_CONSTRAINT_TOKENS = {
    1320        TokenType.CONSTRAINT,
    1321        TokenType.FOREIGN_KEY,
    1322        TokenType.INDEX,
    1323        TokenType.KEY,
    1324        TokenType.PRIMARY_KEY,
    1325        TokenType.UNIQUE,
    1326    }
    1327
    1328    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1329
    1330    NULL_TOKENS = {TokenType.NULL}
    1331
    1332    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
    1333
    1334    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1335
    1336    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1337
    1338    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
    1339
    1340    ODBC_DATETIME_LITERALS = {
    1341        "d": exp.Date,
    1342        "t": exp.Time,
    1343        "ts": exp.Timestamp,
    1344    }
    1345
    1346    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
    1347
    1348    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
    1349
    1350    # The style options for the DESCRIBE statement
    1351    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
    1352
    1353    # The style options for the ANALYZE statement
    1354    ANALYZE_STYLES = {
    1355        "BUFFER_USAGE_LIMIT",
    1356        "FULL",
    1357        "LOCAL",
    1358        "NO_WRITE_TO_BINLOG",
    1359        "SAMPLE",
    1360        "SKIP_LOCKED",
    1361        "VERBOSE",
    1362    }
    1363
    1364    ANALYZE_EXPRESSION_PARSERS = {
    1365        "ALL": lambda self: self._parse_analyze_columns(),
    1366        "COMPUTE": lambda self: self._parse_analyze_statistics(),
    1367        "DELETE": lambda self: self._parse_analyze_delete(),
    1368        "DROP": lambda self: self._parse_analyze_histogram(),
    1369        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
    1370        "LIST": lambda self: self._parse_analyze_list(),
    1371        "PREDICATE": lambda self: self._parse_analyze_columns(),
    1372        "UPDATE": lambda self: self._parse_analyze_histogram(),
    1373        "VALIDATE": lambda self: self._parse_analyze_validate(),
    1374    }
    1375
    1376    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
    1377
    1378    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
    1379
    1380    OPERATION_MODIFIERS: t.Set[str] = set()
    1381
    1382    RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
    1383
    1384    STRICT_CAST = True
    1385
    1386    PREFIXED_PIVOT_COLUMNS = False
    1387    IDENTIFY_PIVOT_STRINGS = False
    1388
    1389    LOG_DEFAULTS_TO_LN = False
    1390
    1391    # Whether ADD is present for each column added by ALTER TABLE
    1392    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1393
    1394    # Whether the table sample clause expects CSV syntax
    1395    TABLESAMPLE_CSV = False
    1396
    1397    # The default method used for table sampling
    1398    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1399
    1400    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1401    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1402
    1403    # Whether the TRIM function expects the characters to trim as its first argument
    1404    TRIM_PATTERN_FIRST = False
    1405
    1406    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1407    STRING_ALIASES = False
    1408
    1409    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1410    MODIFIERS_ATTACHED_TO_SET_OP = True
    1411    SET_OP_MODIFIERS = {"order", "limit", "offset"}
    1412
    1413    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1414    NO_PAREN_IF_COMMANDS = True
    1415
    1416    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1417    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1418
    1419    # Whether the `:` operator is used to extract a value from a VARIANT column
    1420    COLON_IS_VARIANT_EXTRACT = False
    1421
    1422    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1423    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1424    VALUES_FOLLOWED_BY_PAREN = True
    1425
    1426    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1427    SUPPORTS_IMPLICIT_UNNEST = False
    1428
    1429    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1430    INTERVAL_SPANS = True
    1431
    1432    # Whether a PARTITION clause can follow a table reference
    1433    SUPPORTS_PARTITION_SELECTION = False
    1434
    1435    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
    1436    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
    1437
    1438    # Whether the 'AS' keyword is optional in the CTE definition syntax
    1439    OPTIONAL_ALIAS_TOKEN_CTE = True
    1440
    1441    __slots__ = (
    1442        "error_level",
    1443        "error_message_context",
    1444        "max_errors",
    1445        "dialect",
    1446        "sql",
    1447        "errors",
    1448        "_tokens",
    1449        "_index",
    1450        "_curr",
    1451        "_next",
    1452        "_prev",
    1453        "_prev_comments",
    1454    )
    1455
    1456    # Autofilled
    1457    SHOW_TRIE: t.Dict = {}
    1458    SET_TRIE: t.Dict = {}
    1459
    1460    def __init__(
    1461        self,
    1462        error_level: t.Optional[ErrorLevel] = None,
    1463        error_message_context: int = 100,
    1464        max_errors: int = 3,
    1465        dialect: DialectType = None,
    1466    ):
    1467        from sqlglot.dialects import Dialect
    1468
    1469        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1470        self.error_message_context = error_message_context
    1471        self.max_errors = max_errors
    1472        self.dialect = Dialect.get_or_raise(dialect)
    1473        self.reset()
    1474
    1475    def reset(self):
    1476        self.sql = ""
    1477        self.errors = []
    1478        self._tokens = []
    1479        self._index = 0
    1480        self._curr = None
    1481        self._next = None
    1482        self._prev = None
    1483        self._prev_comments = None
    1484
    1485    def parse(
    1486        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1487    ) -> t.List[t.Optional[exp.Expression]]:
    1488        """
    1489        Parses a list of tokens and returns a list of syntax trees, one tree
    1490        per parsed SQL statement.
    1491
    1492        Args:
    1493            raw_tokens: The list of tokens.
    1494            sql: The original SQL string, used to produce helpful debug messages.
    1495
    1496        Returns:
    1497            The list of the produced syntax trees.
    1498        """
    1499        return self._parse(
    1500            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1501        )
    1502
    1503    def parse_into(
    1504        self,
    1505        expression_types: exp.IntoType,
    1506        raw_tokens: t.List[Token],
    1507        sql: t.Optional[str] = None,
    1508    ) -> t.List[t.Optional[exp.Expression]]:
    1509        """
    1510        Parses a list of tokens into a given Expression type. If a collection of Expression
    1511        types is given instead, this method will try to parse the token list into each one
    1512        of them, stopping at the first for which the parsing succeeds.
    1513
    1514        Args:
    1515            expression_types: The expression type(s) to try and parse the token list into.
    1516            raw_tokens: The list of tokens.
    1517            sql: The original SQL string, used to produce helpful debug messages.
    1518
    1519        Returns:
    1520            The target Expression.
    1521        """
    1522        errors = []
    1523        for expression_type in ensure_list(expression_types):
    1524            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1525            if not parser:
    1526                raise TypeError(f"No parser registered for {expression_type}")
    1527
    1528            try:
    1529                return self._parse(parser, raw_tokens, sql)
    1530            except ParseError as e:
    1531                e.errors[0]["into_expression"] = expression_type
    1532                errors.append(e)
    1533
    1534        raise ParseError(
    1535            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1536            errors=merge_errors(errors),
    1537        ) from errors[-1]
    1538
    1539    def _parse(
    1540        self,
    1541        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1542        raw_tokens: t.List[Token],
    1543        sql: t.Optional[str] = None,
    1544    ) -> t.List[t.Optional[exp.Expression]]:
    1545        self.reset()
    1546        self.sql = sql or ""
    1547
    1548        total = len(raw_tokens)
    1549        chunks: t.List[t.List[Token]] = [[]]
    1550
    1551        for i, token in enumerate(raw_tokens):
    1552            if token.token_type == TokenType.SEMICOLON:
    1553                if token.comments:
    1554                    chunks.append([token])
    1555
    1556                if i < total - 1:
    1557                    chunks.append([])
    1558            else:
    1559                chunks[-1].append(token)
    1560
    1561        expressions = []
    1562
    1563        for tokens in chunks:
    1564            self._index = -1
    1565            self._tokens = tokens
    1566            self._advance()
    1567
    1568            expressions.append(parse_method(self))
    1569
    1570            if self._index < len(self._tokens):
    1571                self.raise_error("Invalid expression / Unexpected token")
    1572
    1573            self.check_errors()
    1574
    1575        return expressions
    1576
    1577    def check_errors(self) -> None:
    1578        """Logs or raises any found errors, depending on the chosen error level setting."""
    1579        if self.error_level == ErrorLevel.WARN:
    1580            for error in self.errors:
    1581                logger.error(str(error))
    1582        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1583            raise ParseError(
    1584                concat_messages(self.errors, self.max_errors),
    1585                errors=merge_errors(self.errors),
    1586            )
    1587
    1588    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1589        """
    1590        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1591        error level setting.
    1592        """
    1593        token = token or self._curr or self._prev or Token.string("")
    1594        start = token.start
    1595        end = token.end + 1
    1596        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1597        highlight = self.sql[start:end]
    1598        end_context = self.sql[end : end + self.error_message_context]
    1599
    1600        error = ParseError.new(
    1601            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1602            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1603            description=message,
    1604            line=token.line,
    1605            col=token.col,
    1606            start_context=start_context,
    1607            highlight=highlight,
    1608            end_context=end_context,
    1609        )
    1610
    1611        if self.error_level == ErrorLevel.IMMEDIATE:
    1612            raise error
    1613
    1614        self.errors.append(error)
    1615
    1616    def expression(
    1617        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1618    ) -> E:
    1619        """
    1620        Creates a new, validated Expression.
    1621
    1622        Args:
    1623            exp_class: The expression class to instantiate.
    1624            comments: An optional list of comments to attach to the expression.
    1625            kwargs: The arguments to set for the expression along with their respective values.
    1626
    1627        Returns:
    1628            The target expression.
    1629        """
    1630        instance = exp_class(**kwargs)
    1631        instance.add_comments(comments) if comments else self._add_comments(instance)
    1632        return self.validate_expression(instance)
    1633
    1634    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1635        if expression and self._prev_comments:
    1636            expression.add_comments(self._prev_comments)
    1637            self._prev_comments = None
    1638
    1639    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1640        """
    1641        Validates an Expression, making sure that all its mandatory arguments are set.
    1642
    1643        Args:
    1644            expression: The expression to validate.
    1645            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1646
    1647        Returns:
    1648            The validated expression.
    1649        """
    1650        if self.error_level != ErrorLevel.IGNORE:
    1651            for error_message in expression.error_messages(args):
    1652                self.raise_error(error_message)
    1653
    1654        return expression
    1655
    1656    def _find_sql(self, start: Token, end: Token) -> str:
    1657        return self.sql[start.start : end.end + 1]
    1658
    1659    def _is_connected(self) -> bool:
    1660        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1661
    1662    def _advance(self, times: int = 1) -> None:
    1663        self._index += times
    1664        self._curr = seq_get(self._tokens, self._index)
    1665        self._next = seq_get(self._tokens, self._index + 1)
    1666
    1667        if self._index > 0:
    1668            self._prev = self._tokens[self._index - 1]
    1669            self._prev_comments = self._prev.comments
    1670        else:
    1671            self._prev = None
    1672            self._prev_comments = None
    1673
    1674    def _retreat(self, index: int) -> None:
    1675        if index != self._index:
    1676            self._advance(index - self._index)
    1677
    1678    def _warn_unsupported(self) -> None:
    1679        if len(self._tokens) <= 1:
    1680            return
    1681
    1682        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1683        # interested in emitting a warning for the one being currently processed.
    1684        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1685
    1686        logger.warning(
    1687            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1688        )
    1689
    1690    def _parse_command(self) -> exp.Command:
    1691        self._warn_unsupported()
    1692        return self.expression(
    1693            exp.Command,
    1694            comments=self._prev_comments,
    1695            this=self._prev.text.upper(),
    1696            expression=self._parse_string(),
    1697        )
    1698
    1699    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1700        """
    1701        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
    1702        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
    1703        solve this by setting & resetting the parser state accordingly
    1704        """
    1705        index = self._index
    1706        error_level = self.error_level
    1707
    1708        self.error_level = ErrorLevel.IMMEDIATE
    1709        try:
    1710            this = parse_method()
    1711        except ParseError:
    1712            this = None
    1713        finally:
    1714            if not this or retreat:
    1715                self._retreat(index)
    1716            self.error_level = error_level
    1717
    1718        return this
    1719
    1720    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1721        start = self._prev
    1722        exists = self._parse_exists() if allow_exists else None
    1723
    1724        self._match(TokenType.ON)
    1725
    1726        materialized = self._match_text_seq("MATERIALIZED")
    1727        kind = self._match_set(self.CREATABLES) and self._prev
    1728        if not kind:
    1729            return self._parse_as_command(start)
    1730
    1731        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1732            this = self._parse_user_defined_function(kind=kind.token_type)
    1733        elif kind.token_type == TokenType.TABLE:
    1734            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1735        elif kind.token_type == TokenType.COLUMN:
    1736            this = self._parse_column()
    1737        else:
    1738            this = self._parse_id_var()
    1739
    1740        self._match(TokenType.IS)
    1741
    1742        return self.expression(
    1743            exp.Comment,
    1744            this=this,
    1745            kind=kind.text,
    1746            expression=self._parse_string(),
    1747            exists=exists,
    1748            materialized=materialized,
    1749        )
    1750
    1751    def _parse_to_table(
    1752        self,
    1753    ) -> exp.ToTableProperty:
    1754        table = self._parse_table_parts(schema=True)
    1755        return self.expression(exp.ToTableProperty, this=table)
    1756
    1757    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1758    def _parse_ttl(self) -> exp.Expression:
    1759        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1760            this = self._parse_bitwise()
    1761
    1762            if self._match_text_seq("DELETE"):
    1763                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1764            if self._match_text_seq("RECOMPRESS"):
    1765                return self.expression(
    1766                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1767                )
    1768            if self._match_text_seq("TO", "DISK"):
    1769                return self.expression(
    1770                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1771                )
    1772            if self._match_text_seq("TO", "VOLUME"):
    1773                return self.expression(
    1774                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1775                )
    1776
    1777            return this
    1778
    1779        expressions = self._parse_csv(_parse_ttl_action)
    1780        where = self._parse_where()
    1781        group = self._parse_group()
    1782
    1783        aggregates = None
    1784        if group and self._match(TokenType.SET):
    1785            aggregates = self._parse_csv(self._parse_set_item)
    1786
    1787        return self.expression(
    1788            exp.MergeTreeTTL,
    1789            expressions=expressions,
    1790            where=where,
    1791            group=group,
    1792            aggregates=aggregates,
    1793        )
    1794
    1795    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1796        if self._curr is None:
    1797            return None
    1798
    1799        if self._match_set(self.STATEMENT_PARSERS):
    1800            comments = self._prev_comments
    1801            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
    1802            stmt.add_comments(comments, prepend=True)
    1803            return stmt
    1804
    1805        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1806            return self._parse_command()
    1807
    1808        expression = self._parse_expression()
    1809        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1810        return self._parse_query_modifiers(expression)
    1811
    1812    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1813        start = self._prev
    1814        temporary = self._match(TokenType.TEMPORARY)
    1815        materialized = self._match_text_seq("MATERIALIZED")
    1816
    1817        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    1818        if not kind:
    1819            return self._parse_as_command(start)
    1820
    1821        concurrently = self._match_text_seq("CONCURRENTLY")
    1822        if_exists = exists or self._parse_exists()
    1823
    1824        if kind == "COLUMN":
    1825            this = self._parse_column()
    1826        else:
    1827            this = self._parse_table_parts(
    1828                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1829            )
    1830
    1831        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1832
    1833        if self._match(TokenType.L_PAREN, advance=False):
    1834            expressions = self._parse_wrapped_csv(self._parse_types)
    1835        else:
    1836            expressions = None
    1837
    1838        return self.expression(
    1839            exp.Drop,
    1840            exists=if_exists,
    1841            this=this,
    1842            expressions=expressions,
    1843            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
    1844            temporary=temporary,
    1845            materialized=materialized,
    1846            cascade=self._match_text_seq("CASCADE"),
    1847            constraints=self._match_text_seq("CONSTRAINTS"),
    1848            purge=self._match_text_seq("PURGE"),
    1849            cluster=cluster,
    1850            concurrently=concurrently,
    1851        )
    1852
    1853    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1854        return (
    1855            self._match_text_seq("IF")
    1856            and (not not_ or self._match(TokenType.NOT))
    1857            and self._match(TokenType.EXISTS)
    1858        )
    1859
    1860    def _parse_create(self) -> exp.Create | exp.Command:
    1861        # Note: this can't be None because we've matched a statement parser
    1862        start = self._prev
    1863
    1864        replace = (
    1865            start.token_type == TokenType.REPLACE
    1866            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1867            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1868        )
    1869        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
    1870
    1871        unique = self._match(TokenType.UNIQUE)
    1872
    1873        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
    1874            clustered = True
    1875        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
    1876            "COLUMNSTORE"
    1877        ):
    1878            clustered = False
    1879        else:
    1880            clustered = None
    1881
    1882        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1883            self._advance()
    1884
    1885        properties = None
    1886        create_token = self._match_set(self.CREATABLES) and self._prev
    1887
    1888        if not create_token:
    1889            # exp.Properties.Location.POST_CREATE
    1890            properties = self._parse_properties()
    1891            create_token = self._match_set(self.CREATABLES) and self._prev
    1892
    1893            if not properties or not create_token:
    1894                return self._parse_as_command(start)
    1895
    1896        concurrently = self._match_text_seq("CONCURRENTLY")
    1897        exists = self._parse_exists(not_=True)
    1898        this = None
    1899        expression: t.Optional[exp.Expression] = None
    1900        indexes = None
    1901        no_schema_binding = None
    1902        begin = None
    1903        end = None
    1904        clone = None
    1905
    1906        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1907            nonlocal properties
    1908            if properties and temp_props:
    1909                properties.expressions.extend(temp_props.expressions)
    1910            elif temp_props:
    1911                properties = temp_props
    1912
    1913        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1914            this = self._parse_user_defined_function(kind=create_token.token_type)
    1915
    1916            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1917            extend_props(self._parse_properties())
    1918
    1919            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1920            extend_props(self._parse_properties())
    1921
    1922            if not expression:
    1923                if self._match(TokenType.COMMAND):
    1924                    expression = self._parse_as_command(self._prev)
    1925                else:
    1926                    begin = self._match(TokenType.BEGIN)
    1927                    return_ = self._match_text_seq("RETURN")
    1928
    1929                    if self._match(TokenType.STRING, advance=False):
    1930                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1931                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1932                        expression = self._parse_string()
    1933                        extend_props(self._parse_properties())
    1934                    else:
    1935                        expression = self._parse_user_defined_function_expression()
    1936
    1937                    end = self._match_text_seq("END")
    1938
    1939                    if return_:
    1940                        expression = self.expression(exp.Return, this=expression)
    1941        elif create_token.token_type == TokenType.INDEX:
    1942            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1943            if not self._match(TokenType.ON):
    1944                index = self._parse_id_var()
    1945                anonymous = False
    1946            else:
    1947                index = None
    1948                anonymous = True
    1949
    1950            this = self._parse_index(index=index, anonymous=anonymous)
    1951        elif create_token.token_type in self.DB_CREATABLES:
    1952            table_parts = self._parse_table_parts(
    1953                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1954            )
    1955
    1956            # exp.Properties.Location.POST_NAME
    1957            self._match(TokenType.COMMA)
    1958            extend_props(self._parse_properties(before=True))
    1959
    1960            this = self._parse_schema(this=table_parts)
    1961
    1962            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1963            extend_props(self._parse_properties())
    1964
    1965            self._match(TokenType.ALIAS)
    1966            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1967                # exp.Properties.Location.POST_ALIAS
    1968                extend_props(self._parse_properties())
    1969
    1970            if create_token.token_type == TokenType.SEQUENCE:
    1971                expression = self._parse_types()
    1972                extend_props(self._parse_properties())
    1973            else:
    1974                expression = self._parse_ddl_select()
    1975
    1976            if create_token.token_type == TokenType.TABLE:
    1977                # exp.Properties.Location.POST_EXPRESSION
    1978                extend_props(self._parse_properties())
    1979
    1980                indexes = []
    1981                while True:
    1982                    index = self._parse_index()
    1983
    1984                    # exp.Properties.Location.POST_INDEX
    1985                    extend_props(self._parse_properties())
    1986                    if not index:
    1987                        break
    1988                    else:
    1989                        self._match(TokenType.COMMA)
    1990                        indexes.append(index)
    1991            elif create_token.token_type == TokenType.VIEW:
    1992                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1993                    no_schema_binding = True
    1994            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
    1995                extend_props(self._parse_properties())
    1996
    1997            shallow = self._match_text_seq("SHALLOW")
    1998
    1999            if self._match_texts(self.CLONE_KEYWORDS):
    2000                copy = self._prev.text.lower() == "copy"
    2001                clone = self.expression(
    2002                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    2003                )
    2004
    2005        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    2006            return self._parse_as_command(start)
    2007
    2008        create_kind_text = create_token.text.upper()
    2009        return self.expression(
    2010            exp.Create,
    2011            this=this,
    2012            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
    2013            replace=replace,
    2014            refresh=refresh,
    2015            unique=unique,
    2016            expression=expression,
    2017            exists=exists,
    2018            properties=properties,
    2019            indexes=indexes,
    2020            no_schema_binding=no_schema_binding,
    2021            begin=begin,
    2022            end=end,
    2023            clone=clone,
    2024            concurrently=concurrently,
    2025            clustered=clustered,
    2026        )
    2027
    2028    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    2029        seq = exp.SequenceProperties()
    2030
    2031        options = []
    2032        index = self._index
    2033
    2034        while self._curr:
    2035            self._match(TokenType.COMMA)
    2036            if self._match_text_seq("INCREMENT"):
    2037                self._match_text_seq("BY")
    2038                self._match_text_seq("=")
    2039                seq.set("increment", self._parse_term())
    2040            elif self._match_text_seq("MINVALUE"):
    2041                seq.set("minvalue", self._parse_term())
    2042            elif self._match_text_seq("MAXVALUE"):
    2043                seq.set("maxvalue", self._parse_term())
    2044            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    2045                self._match_text_seq("=")
    2046                seq.set("start", self._parse_term())
    2047            elif self._match_text_seq("CACHE"):
    2048                # T-SQL allows empty CACHE which is initialized dynamically
    2049                seq.set("cache", self._parse_number() or True)
    2050            elif self._match_text_seq("OWNED", "BY"):
    2051                # "OWNED BY NONE" is the default
    2052                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    2053            else:
    2054                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    2055                if opt:
    2056                    options.append(opt)
    2057                else:
    2058                    break
    2059
    2060        seq.set("options", options if options else None)
    2061        return None if self._index == index else seq
    2062
    2063    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    2064        # only used for teradata currently
    2065        self._match(TokenType.COMMA)
    2066
    2067        kwargs = {
    2068            "no": self._match_text_seq("NO"),
    2069            "dual": self._match_text_seq("DUAL"),
    2070            "before": self._match_text_seq("BEFORE"),
    2071            "default": self._match_text_seq("DEFAULT"),
    2072            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    2073            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    2074            "after": self._match_text_seq("AFTER"),
    2075            "minimum": self._match_texts(("MIN", "MINIMUM")),
    2076            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    2077        }
    2078
    2079        if self._match_texts(self.PROPERTY_PARSERS):
    2080            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    2081            try:
    2082                return parser(self, **{k: v for k, v in kwargs.items() if v})
    2083            except TypeError:
    2084                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    2085
    2086        return None
    2087
    2088    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    2089        return self._parse_wrapped_csv(self._parse_property)
    2090
    2091    def _parse_property(self) -> t.Optional[exp.Expression]:
    2092        if self._match_texts(self.PROPERTY_PARSERS):
    2093            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    2094
    2095        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    2096            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    2097
    2098        if self._match_text_seq("COMPOUND", "SORTKEY"):
    2099            return self._parse_sortkey(compound=True)
    2100
    2101        if self._match_text_seq("SQL", "SECURITY"):
    2102            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    2103
    2104        index = self._index
    2105        key = self._parse_column()
    2106
    2107        if not self._match(TokenType.EQ):
    2108            self._retreat(index)
    2109            return self._parse_sequence_properties()
    2110
    2111        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    2112        if isinstance(key, exp.Column):
    2113            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    2114
    2115        value = self._parse_bitwise() or self._parse_var(any_token=True)
    2116
    2117        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    2118        if isinstance(value, exp.Column):
    2119            value = exp.var(value.name)
    2120
    2121        return self.expression(exp.Property, this=key, value=value)
    2122
    2123    def _parse_stored(self) -> exp.FileFormatProperty:
    2124        self._match(TokenType.ALIAS)
    2125
    2126        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    2127        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    2128
    2129        return self.expression(
    2130            exp.FileFormatProperty,
    2131            this=(
    2132                self.expression(
    2133                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
    2134                )
    2135                if input_format or output_format
    2136                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    2137            ),
    2138        )
    2139
    2140    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    2141        field = self._parse_field()
    2142        if isinstance(field, exp.Identifier) and not field.quoted:
    2143            field = exp.var(field)
    2144
    2145        return field
    2146
    2147    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    2148        self._match(TokenType.EQ)
    2149        self._match(TokenType.ALIAS)
    2150
    2151        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    2152
    2153    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    2154        properties = []
    2155        while True:
    2156            if before:
    2157                prop = self._parse_property_before()
    2158            else:
    2159                prop = self._parse_property()
    2160            if not prop:
    2161                break
    2162            for p in ensure_list(prop):
    2163                properties.append(p)
    2164
    2165        if properties:
    2166            return self.expression(exp.Properties, expressions=properties)
    2167
    2168        return None
    2169
    2170    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    2171        return self.expression(
    2172            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    2173        )
    2174
    2175    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
    2176        if self._match_texts(("DEFINER", "INVOKER")):
    2177            security_specifier = self._prev.text.upper()
    2178            return self.expression(exp.SecurityProperty, this=security_specifier)
    2179        return None
    2180
    2181    def _parse_settings_property(self) -> exp.SettingsProperty:
    2182        return self.expression(
    2183            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
    2184        )
    2185
    2186    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    2187        if self._index >= 2:
    2188            pre_volatile_token = self._tokens[self._index - 2]
    2189        else:
    2190            pre_volatile_token = None
    2191
    2192        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    2193            return exp.VolatileProperty()
    2194
    2195        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    2196
    2197    def _parse_retention_period(self) -> exp.Var:
    2198        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    2199        number = self._parse_number()
    2200        number_str = f"{number} " if number else ""
    2201        unit = self._parse_var(any_token=True)
    2202        return exp.var(f"{number_str}{unit}")
    2203
    2204    def _parse_system_versioning_property(
    2205        self, with_: bool = False
    2206    ) -> exp.WithSystemVersioningProperty:
    2207        self._match(TokenType.EQ)
    2208        prop = self.expression(
    2209            exp.WithSystemVersioningProperty,
    2210            **{  # type: ignore
    2211                "on": True,
    2212                "with": with_,
    2213            },
    2214        )
    2215
    2216        if self._match_text_seq("OFF"):
    2217            prop.set("on", False)
    2218            return prop
    2219
    2220        self._match(TokenType.ON)
    2221        if self._match(TokenType.L_PAREN):
    2222            while self._curr and not self._match(TokenType.R_PAREN):
    2223                if self._match_text_seq("HISTORY_TABLE", "="):
    2224                    prop.set("this", self._parse_table_parts())
    2225                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    2226                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    2227                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    2228                    prop.set("retention_period", self._parse_retention_period())
    2229
    2230                self._match(TokenType.COMMA)
    2231
    2232        return prop
    2233
    2234    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    2235        self._match(TokenType.EQ)
    2236        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    2237        prop = self.expression(exp.DataDeletionProperty, on=on)
    2238
    2239        if self._match(TokenType.L_PAREN):
    2240            while self._curr and not self._match(TokenType.R_PAREN):
    2241                if self._match_text_seq("FILTER_COLUMN", "="):
    2242                    prop.set("filter_column", self._parse_column())
    2243                elif self._match_text_seq("RETENTION_PERIOD", "="):
    2244                    prop.set("retention_period", self._parse_retention_period())
    2245
    2246                self._match(TokenType.COMMA)
    2247
    2248        return prop
    2249
    2250    def _parse_distributed_property(self) -> exp.DistributedByProperty:
    2251        kind = "HASH"
    2252        expressions: t.Optional[t.List[exp.Expression]] = None
    2253        if self._match_text_seq("BY", "HASH"):
    2254            expressions = self._parse_wrapped_csv(self._parse_id_var)
    2255        elif self._match_text_seq("BY", "RANDOM"):
    2256            kind = "RANDOM"
    2257
    2258        # If the BUCKETS keyword is not present, the number of buckets is AUTO
    2259        buckets: t.Optional[exp.Expression] = None
    2260        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
    2261            buckets = self._parse_number()
    2262
    2263        return self.expression(
    2264            exp.DistributedByProperty,
    2265            expressions=expressions,
    2266            kind=kind,
    2267            buckets=buckets,
    2268            order=self._parse_order(),
    2269        )
    2270
    2271    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
    2272        self._match_text_seq("KEY")
    2273        expressions = self._parse_wrapped_id_vars()
    2274        return self.expression(expr_type, expressions=expressions)
    2275
    2276    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    2277        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    2278            prop = self._parse_system_versioning_property(with_=True)
    2279            self._match_r_paren()
    2280            return prop
    2281
    2282        if self._match(TokenType.L_PAREN, advance=False):
    2283            return self._parse_wrapped_properties()
    2284
    2285        if self._match_text_seq("JOURNAL"):
    2286            return self._parse_withjournaltable()
    2287
    2288        if self._match_texts(self.VIEW_ATTRIBUTES):
    2289            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    2290
    2291        if self._match_text_seq("DATA"):
    2292            return self._parse_withdata(no=False)
    2293        elif self._match_text_seq("NO", "DATA"):
    2294            return self._parse_withdata(no=True)
    2295
    2296        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    2297            return self._parse_serde_properties(with_=True)
    2298
    2299        if self._match(TokenType.SCHEMA):
    2300            return self.expression(
    2301                exp.WithSchemaBindingProperty,
    2302                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
    2303            )
    2304
    2305        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
    2306            return self.expression(
    2307                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
    2308            )
    2309
    2310        if not self._next:
    2311            return None
    2312
    2313        return self._parse_withisolatedloading()
    2314
    2315    def _parse_procedure_option(self) -> exp.Expression | None:
    2316        if self._match_text_seq("EXECUTE", "AS"):
    2317            return self.expression(
    2318                exp.ExecuteAsProperty,
    2319                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
    2320                or self._parse_string(),
    2321            )
    2322
    2323        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
    2324
    2325    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2326    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2327        self._match(TokenType.EQ)
    2328
    2329        user = self._parse_id_var()
    2330        self._match(TokenType.PARAMETER)
    2331        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2332
    2333        if not user or not host:
    2334            return None
    2335
    2336        return exp.DefinerProperty(this=f"{user}@{host}")
    2337
    2338    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2339        self._match(TokenType.TABLE)
    2340        self._match(TokenType.EQ)
    2341        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2342
    2343    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2344        return self.expression(exp.LogProperty, no=no)
    2345
    2346    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2347        return self.expression(exp.JournalProperty, **kwargs)
    2348
    2349    def _parse_checksum(self) -> exp.ChecksumProperty:
    2350        self._match(TokenType.EQ)
    2351
    2352        on = None
    2353        if self._match(TokenType.ON):
    2354            on = True
    2355        elif self._match_text_seq("OFF"):
    2356            on = False
    2357
    2358        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2359
    2360    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2361        return self.expression(
    2362            exp.Cluster,
    2363            expressions=(
    2364                self._parse_wrapped_csv(self._parse_ordered)
    2365                if wrapped
    2366                else self._parse_csv(self._parse_ordered)
    2367            ),
    2368        )
    2369
    2370    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2371        self._match_text_seq("BY")
    2372
    2373        self._match_l_paren()
    2374        expressions = self._parse_csv(self._parse_column)
    2375        self._match_r_paren()
    2376
    2377        if self._match_text_seq("SORTED", "BY"):
    2378            self._match_l_paren()
    2379            sorted_by = self._parse_csv(self._parse_ordered)
    2380            self._match_r_paren()
    2381        else:
    2382            sorted_by = None
    2383
    2384        self._match(TokenType.INTO)
    2385        buckets = self._parse_number()
    2386        self._match_text_seq("BUCKETS")
    2387
    2388        return self.expression(
    2389            exp.ClusteredByProperty,
    2390            expressions=expressions,
    2391            sorted_by=sorted_by,
    2392            buckets=buckets,
    2393        )
    2394
    2395    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2396        if not self._match_text_seq("GRANTS"):
    2397            self._retreat(self._index - 1)
    2398            return None
    2399
    2400        return self.expression(exp.CopyGrantsProperty)
    2401
    2402    def _parse_freespace(self) -> exp.FreespaceProperty:
    2403        self._match(TokenType.EQ)
    2404        return self.expression(
    2405            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2406        )
    2407
    2408    def _parse_mergeblockratio(
    2409        self, no: bool = False, default: bool = False
    2410    ) -> exp.MergeBlockRatioProperty:
    2411        if self._match(TokenType.EQ):
    2412            return self.expression(
    2413                exp.MergeBlockRatioProperty,
    2414                this=self._parse_number(),
    2415                percent=self._match(TokenType.PERCENT),
    2416            )
    2417
    2418        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2419
    2420    def _parse_datablocksize(
    2421        self,
    2422        default: t.Optional[bool] = None,
    2423        minimum: t.Optional[bool] = None,
    2424        maximum: t.Optional[bool] = None,
    2425    ) -> exp.DataBlocksizeProperty:
    2426        self._match(TokenType.EQ)
    2427        size = self._parse_number()
    2428
    2429        units = None
    2430        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2431            units = self._prev.text
    2432
    2433        return self.expression(
    2434            exp.DataBlocksizeProperty,
    2435            size=size,
    2436            units=units,
    2437            default=default,
    2438            minimum=minimum,
    2439            maximum=maximum,
    2440        )
    2441
    2442    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2443        self._match(TokenType.EQ)
    2444        always = self._match_text_seq("ALWAYS")
    2445        manual = self._match_text_seq("MANUAL")
    2446        never = self._match_text_seq("NEVER")
    2447        default = self._match_text_seq("DEFAULT")
    2448
    2449        autotemp = None
    2450        if self._match_text_seq("AUTOTEMP"):
    2451            autotemp = self._parse_schema()
    2452
    2453        return self.expression(
    2454            exp.BlockCompressionProperty,
    2455            always=always,
    2456            manual=manual,
    2457            never=never,
    2458            default=default,
    2459            autotemp=autotemp,
    2460        )
    2461
    2462    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2463        index = self._index
    2464        no = self._match_text_seq("NO")
    2465        concurrent = self._match_text_seq("CONCURRENT")
    2466
    2467        if not self._match_text_seq("ISOLATED", "LOADING"):
    2468            self._retreat(index)
    2469            return None
    2470
    2471        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2472        return self.expression(
    2473            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2474        )
    2475
    2476    def _parse_locking(self) -> exp.LockingProperty:
    2477        if self._match(TokenType.TABLE):
    2478            kind = "TABLE"
    2479        elif self._match(TokenType.VIEW):
    2480            kind = "VIEW"
    2481        elif self._match(TokenType.ROW):
    2482            kind = "ROW"
    2483        elif self._match_text_seq("DATABASE"):
    2484            kind = "DATABASE"
    2485        else:
    2486            kind = None
    2487
    2488        if kind in ("DATABASE", "TABLE", "VIEW"):
    2489            this = self._parse_table_parts()
    2490        else:
    2491            this = None
    2492
    2493        if self._match(TokenType.FOR):
    2494            for_or_in = "FOR"
    2495        elif self._match(TokenType.IN):
    2496            for_or_in = "IN"
    2497        else:
    2498            for_or_in = None
    2499
    2500        if self._match_text_seq("ACCESS"):
    2501            lock_type = "ACCESS"
    2502        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2503            lock_type = "EXCLUSIVE"
    2504        elif self._match_text_seq("SHARE"):
    2505            lock_type = "SHARE"
    2506        elif self._match_text_seq("READ"):
    2507            lock_type = "READ"
    2508        elif self._match_text_seq("WRITE"):
    2509            lock_type = "WRITE"
    2510        elif self._match_text_seq("CHECKSUM"):
    2511            lock_type = "CHECKSUM"
    2512        else:
    2513            lock_type = None
    2514
    2515        override = self._match_text_seq("OVERRIDE")
    2516
    2517        return self.expression(
    2518            exp.LockingProperty,
    2519            this=this,
    2520            kind=kind,
    2521            for_or_in=for_or_in,
    2522            lock_type=lock_type,
    2523            override=override,
    2524        )
    2525
    2526    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2527        if self._match(TokenType.PARTITION_BY):
    2528            return self._parse_csv(self._parse_assignment)
    2529        return []
    2530
    2531    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2532        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2533            if self._match_text_seq("MINVALUE"):
    2534                return exp.var("MINVALUE")
    2535            if self._match_text_seq("MAXVALUE"):
    2536                return exp.var("MAXVALUE")
    2537            return self._parse_bitwise()
    2538
    2539        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2540        expression = None
    2541        from_expressions = None
    2542        to_expressions = None
    2543
    2544        if self._match(TokenType.IN):
    2545            this = self._parse_wrapped_csv(self._parse_bitwise)
    2546        elif self._match(TokenType.FROM):
    2547            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2548            self._match_text_seq("TO")
    2549            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2550        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2551            this = self._parse_number()
    2552            self._match_text_seq(",", "REMAINDER")
    2553            expression = self._parse_number()
    2554            self._match_r_paren()
    2555        else:
    2556            self.raise_error("Failed to parse partition bound spec.")
    2557
    2558        return self.expression(
    2559            exp.PartitionBoundSpec,
    2560            this=this,
    2561            expression=expression,
    2562            from_expressions=from_expressions,
    2563            to_expressions=to_expressions,
    2564        )
    2565
    2566    # https://www.postgresql.org/docs/current/sql-createtable.html
    2567    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2568        if not self._match_text_seq("OF"):
    2569            self._retreat(self._index - 1)
    2570            return None
    2571
    2572        this = self._parse_table(schema=True)
    2573
    2574        if self._match(TokenType.DEFAULT):
    2575            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2576        elif self._match_text_seq("FOR", "VALUES"):
    2577            expression = self._parse_partition_bound_spec()
    2578        else:
    2579            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2580
    2581        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2582
    2583    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2584        self._match(TokenType.EQ)
    2585        return self.expression(
    2586            exp.PartitionedByProperty,
    2587            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2588        )
    2589
    2590    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2591        if self._match_text_seq("AND", "STATISTICS"):
    2592            statistics = True
    2593        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2594            statistics = False
    2595        else:
    2596            statistics = None
    2597
    2598        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2599
    2600    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2601        if self._match_text_seq("SQL"):
    2602            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2603        return None
    2604
    2605    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2606        if self._match_text_seq("SQL", "DATA"):
    2607            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2608        return None
    2609
    2610    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2611        if self._match_text_seq("PRIMARY", "INDEX"):
    2612            return exp.NoPrimaryIndexProperty()
    2613        if self._match_text_seq("SQL"):
    2614            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2615        return None
    2616
    2617    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2618        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2619            return exp.OnCommitProperty()
    2620        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2621            return exp.OnCommitProperty(delete=True)
    2622        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2623
    2624    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2625        if self._match_text_seq("SQL", "DATA"):
    2626            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2627        return None
    2628
    2629    def _parse_distkey(self) -> exp.DistKeyProperty:
    2630        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2631
    2632    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2633        table = self._parse_table(schema=True)
    2634
    2635        options = []
    2636        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2637            this = self._prev.text.upper()
    2638
    2639            id_var = self._parse_id_var()
    2640            if not id_var:
    2641                return None
    2642
    2643            options.append(
    2644                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2645            )
    2646
    2647        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2648
    2649    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2650        return self.expression(
    2651            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2652        )
    2653
    2654    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2655        self._match(TokenType.EQ)
    2656        return self.expression(
    2657            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2658        )
    2659
    2660    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2661        self._match_text_seq("WITH", "CONNECTION")
    2662        return self.expression(
    2663            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2664        )
    2665
    2666    def _parse_returns(self) -> exp.ReturnsProperty:
    2667        value: t.Optional[exp.Expression]
    2668        null = None
    2669        is_table = self._match(TokenType.TABLE)
    2670
    2671        if is_table:
    2672            if self._match(TokenType.LT):
    2673                value = self.expression(
    2674                    exp.Schema,
    2675                    this="TABLE",
    2676                    expressions=self._parse_csv(self._parse_struct_types),
    2677                )
    2678                if not self._match(TokenType.GT):
    2679                    self.raise_error("Expecting >")
    2680            else:
    2681                value = self._parse_schema(exp.var("TABLE"))
    2682        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2683            null = True
    2684            value = None
    2685        else:
    2686            value = self._parse_types()
    2687
    2688        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2689
    2690    def _parse_describe(self) -> exp.Describe:
    2691        kind = self._match_set(self.CREATABLES) and self._prev.text
    2692        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
    2693        if self._match(TokenType.DOT):
    2694            style = None
    2695            self._retreat(self._index - 2)
    2696
    2697        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
    2698
    2699        if self._match_set(self.STATEMENT_PARSERS, advance=False):
    2700            this = self._parse_statement()
    2701        else:
    2702            this = self._parse_table(schema=True)
    2703
    2704        properties = self._parse_properties()
    2705        expressions = properties.expressions if properties else None
    2706        partition = self._parse_partition()
    2707        return self.expression(
    2708            exp.Describe,
    2709            this=this,
    2710            style=style,
    2711            kind=kind,
    2712            expressions=expressions,
    2713            partition=partition,
    2714            format=format,
    2715        )
    2716
    2717    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
    2718        kind = self._prev.text.upper()
    2719        expressions = []
    2720
    2721        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
    2722            if self._match(TokenType.WHEN):
    2723                expression = self._parse_disjunction()
    2724                self._match(TokenType.THEN)
    2725            else:
    2726                expression = None
    2727
    2728            else_ = self._match(TokenType.ELSE)
    2729
    2730            if not self._match(TokenType.INTO):
    2731                return None
    2732
    2733            return self.expression(
    2734                exp.ConditionalInsert,
    2735                this=self.expression(
    2736                    exp.Insert,
    2737                    this=self._parse_table(schema=True),
    2738                    expression=self._parse_derived_table_values(),
    2739                ),
    2740                expression=expression,
    2741                else_=else_,
    2742            )
    2743
    2744        expression = parse_conditional_insert()
    2745        while expression is not None:
    2746            expressions.append(expression)
    2747            expression = parse_conditional_insert()
    2748
    2749        return self.expression(
    2750            exp.MultitableInserts,
    2751            kind=kind,
    2752            comments=comments,
    2753            expressions=expressions,
    2754            source=self._parse_table(),
    2755        )
    2756
    2757    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
    2758        comments = []
    2759        hint = self._parse_hint()
    2760        overwrite = self._match(TokenType.OVERWRITE)
    2761        ignore = self._match(TokenType.IGNORE)
    2762        local = self._match_text_seq("LOCAL")
    2763        alternative = None
    2764        is_function = None
    2765
    2766        if self._match_text_seq("DIRECTORY"):
    2767            this: t.Optional[exp.Expression] = self.expression(
    2768                exp.Directory,
    2769                this=self._parse_var_or_string(),
    2770                local=local,
    2771                row_format=self._parse_row_format(match_row=True),
    2772            )
    2773        else:
    2774            if self._match_set((TokenType.FIRST, TokenType.ALL)):
    2775                comments += ensure_list(self._prev_comments)
    2776                return self._parse_multitable_inserts(comments)
    2777
    2778            if self._match(TokenType.OR):
    2779                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2780
    2781            self._match(TokenType.INTO)
    2782            comments += ensure_list(self._prev_comments)
    2783            self._match(TokenType.TABLE)
    2784            is_function = self._match(TokenType.FUNCTION)
    2785
    2786            this = (
    2787                self._parse_table(schema=True, parse_partition=True)
    2788                if not is_function
    2789                else self._parse_function()
    2790            )
    2791            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
    2792                this.set("alias", self._parse_table_alias())
    2793
    2794        returning = self._parse_returning()
    2795
    2796        return self.expression(
    2797            exp.Insert,
    2798            comments=comments,
    2799            hint=hint,
    2800            is_function=is_function,
    2801            this=this,
    2802            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2803            by_name=self._match_text_seq("BY", "NAME"),
    2804            exists=self._parse_exists(),
    2805            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2806            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
    2807            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
    2808            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2809            conflict=self._parse_on_conflict(),
    2810            returning=returning or self._parse_returning(),
    2811            overwrite=overwrite,
    2812            alternative=alternative,
    2813            ignore=ignore,
    2814            source=self._match(TokenType.TABLE) and self._parse_table(),
    2815        )
    2816
    2817    def _parse_kill(self) -> exp.Kill:
    2818        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2819
    2820        return self.expression(
    2821            exp.Kill,
    2822            this=self._parse_primary(),
    2823            kind=kind,
    2824        )
    2825
    2826    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2827        conflict = self._match_text_seq("ON", "CONFLICT")
    2828        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2829
    2830        if not conflict and not duplicate:
    2831            return None
    2832
    2833        conflict_keys = None
    2834        constraint = None
    2835
    2836        if conflict:
    2837            if self._match_text_seq("ON", "CONSTRAINT"):
    2838                constraint = self._parse_id_var()
    2839            elif self._match(TokenType.L_PAREN):
    2840                conflict_keys = self._parse_csv(self._parse_id_var)
    2841                self._match_r_paren()
    2842
    2843        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2844        if self._prev.token_type == TokenType.UPDATE:
    2845            self._match(TokenType.SET)
    2846            expressions = self._parse_csv(self._parse_equality)
    2847        else:
    2848            expressions = None
    2849
    2850        return self.expression(
    2851            exp.OnConflict,
    2852            duplicate=duplicate,
    2853            expressions=expressions,
    2854            action=action,
    2855            conflict_keys=conflict_keys,
    2856            constraint=constraint,
    2857            where=self._parse_where(),
    2858        )
    2859
    2860    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2861        if not self._match(TokenType.RETURNING):
    2862            return None
    2863        return self.expression(
    2864            exp.Returning,
    2865            expressions=self._parse_csv(self._parse_expression),
    2866            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2867        )
    2868
    2869    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2870        if not self._match(TokenType.FORMAT):
    2871            return None
    2872        return self._parse_row_format()
    2873
    2874    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2875        index = self._index
    2876        with_ = with_ or self._match_text_seq("WITH")
    2877
    2878        if not self._match(TokenType.SERDE_PROPERTIES):
    2879            self._retreat(index)
    2880            return None
    2881        return self.expression(
    2882            exp.SerdeProperties,
    2883            **{  # type: ignore
    2884                "expressions": self._parse_wrapped_properties(),
    2885                "with": with_,
    2886            },
    2887        )
    2888
    2889    def _parse_row_format(
    2890        self, match_row: bool = False
    2891    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2892        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2893            return None
    2894
    2895        if self._match_text_seq("SERDE"):
    2896            this = self._parse_string()
    2897
    2898            serde_properties = self._parse_serde_properties()
    2899
    2900            return self.expression(
    2901                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2902            )
    2903
    2904        self._match_text_seq("DELIMITED")
    2905
    2906        kwargs = {}
    2907
    2908        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2909            kwargs["fields"] = self._parse_string()
    2910            if self._match_text_seq("ESCAPED", "BY"):
    2911                kwargs["escaped"] = self._parse_string()
    2912        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2913            kwargs["collection_items"] = self._parse_string()
    2914        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2915            kwargs["map_keys"] = self._parse_string()
    2916        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2917            kwargs["lines"] = self._parse_string()
    2918        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2919            kwargs["null"] = self._parse_string()
    2920
    2921        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2922
    2923    def _parse_load(self) -> exp.LoadData | exp.Command:
    2924        if self._match_text_seq("DATA"):
    2925            local = self._match_text_seq("LOCAL")
    2926            self._match_text_seq("INPATH")
    2927            inpath = self._parse_string()
    2928            overwrite = self._match(TokenType.OVERWRITE)
    2929            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2930
    2931            return self.expression(
    2932                exp.LoadData,
    2933                this=self._parse_table(schema=True),
    2934                local=local,
    2935                overwrite=overwrite,
    2936                inpath=inpath,
    2937                partition=self._parse_partition(),
    2938                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2939                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2940            )
    2941        return self._parse_as_command(self._prev)
    2942
    2943    def _parse_delete(self) -> exp.Delete:
    2944        # This handles MySQL's "Multiple-Table Syntax"
    2945        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2946        tables = None
    2947        if not self._match(TokenType.FROM, advance=False):
    2948            tables = self._parse_csv(self._parse_table) or None
    2949
    2950        returning = self._parse_returning()
    2951
    2952        return self.expression(
    2953            exp.Delete,
    2954            tables=tables,
    2955            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    2956            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    2957            cluster=self._match(TokenType.ON) and self._parse_on_property(),
    2958            where=self._parse_where(),
    2959            returning=returning or self._parse_returning(),
    2960            limit=self._parse_limit(),
    2961        )
    2962
    2963    def _parse_update(self) -> exp.Update:
    2964        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    2965        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    2966        returning = self._parse_returning()
    2967        return self.expression(
    2968            exp.Update,
    2969            **{  # type: ignore
    2970                "this": this,
    2971                "expressions": expressions,
    2972                "from": self._parse_from(joins=True),
    2973                "where": self._parse_where(),
    2974                "returning": returning or self._parse_returning(),
    2975                "order": self._parse_order(),
    2976                "limit": self._parse_limit(),
    2977            },
    2978        )
    2979
    2980    def _parse_use(self) -> exp.Use:
    2981        return self.expression(
    2982            exp.Use,
    2983            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
    2984            this=self._parse_table(schema=False),
    2985        )
    2986
    2987    def _parse_uncache(self) -> exp.Uncache:
    2988        if not self._match(TokenType.TABLE):
    2989            self.raise_error("Expecting TABLE after UNCACHE")
    2990
    2991        return self.expression(
    2992            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    2993        )
    2994
    2995    def _parse_cache(self) -> exp.Cache:
    2996        lazy = self._match_text_seq("LAZY")
    2997        self._match(TokenType.TABLE)
    2998        table = self._parse_table(schema=True)
    2999
    3000        options = []
    3001        if self._match_text_seq("OPTIONS"):
    3002            self._match_l_paren()
    3003            k = self._parse_string()
    3004            self._match(TokenType.EQ)
    3005            v = self._parse_string()
    3006            options = [k, v]
    3007            self._match_r_paren()
    3008
    3009        self._match(TokenType.ALIAS)
    3010        return self.expression(
    3011            exp.Cache,
    3012            this=table,
    3013            lazy=lazy,
    3014            options=options,
    3015            expression=self._parse_select(nested=True),
    3016        )
    3017
    3018    def _parse_partition(self) -> t.Optional[exp.Partition]:
    3019        if not self._match_texts(self.PARTITION_KEYWORDS):
    3020            return None
    3021
    3022        return self.expression(
    3023            exp.Partition,
    3024            subpartition=self._prev.text.upper() == "SUBPARTITION",
    3025            expressions=self._parse_wrapped_csv(self._parse_assignment),
    3026        )
    3027
    3028    def _parse_value(self) -> t.Optional[exp.Tuple]:
    3029        def _parse_value_expression() -> t.Optional[exp.Expression]:
    3030            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
    3031                return exp.var(self._prev.text.upper())
    3032            return self._parse_expression()
    3033
    3034        if self._match(TokenType.L_PAREN):
    3035            expressions = self._parse_csv(_parse_value_expression)
    3036            self._match_r_paren()
    3037            return self.expression(exp.Tuple, expressions=expressions)
    3038
    3039        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    3040        expression = self._parse_expression()
    3041        if expression:
    3042            return self.expression(exp.Tuple, expressions=[expression])
    3043        return None
    3044
    3045    def _parse_projections(self) -> t.List[exp.Expression]:
    3046        return self._parse_expressions()
    3047
    3048    def _parse_select(
    3049        self,
    3050        nested: bool = False,
    3051        table: bool = False,
    3052        parse_subquery_alias: bool = True,
    3053        parse_set_operation: bool = True,
    3054    ) -> t.Optional[exp.Expression]:
    3055        cte = self._parse_with()
    3056
    3057        if cte:
    3058            this = self._parse_statement()
    3059
    3060            if not this:
    3061                self.raise_error("Failed to parse any statement following CTE")
    3062                return cte
    3063
    3064            if "with" in this.arg_types:
    3065                this.set("with", cte)
    3066            else:
    3067                self.raise_error(f"{this.key} does not support CTE")
    3068                this = cte
    3069
    3070            return this
    3071
    3072        # duckdb supports leading with FROM x
    3073        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    3074
    3075        if self._match(TokenType.SELECT):
    3076            comments = self._prev_comments
    3077
    3078            hint = self._parse_hint()
    3079
    3080            if self._next and not self._next.token_type == TokenType.DOT:
    3081                all_ = self._match(TokenType.ALL)
    3082                distinct = self._match_set(self.DISTINCT_TOKENS)
    3083            else:
    3084                all_, distinct = None, None
    3085
    3086            kind = (
    3087                self._match(TokenType.ALIAS)
    3088                and self._match_texts(("STRUCT", "VALUE"))
    3089                and self._prev.text.upper()
    3090            )
    3091
    3092            if distinct:
    3093                distinct = self.expression(
    3094                    exp.Distinct,
    3095                    on=self._parse_value() if self._match(TokenType.ON) else None,
    3096                )
    3097
    3098            if all_ and distinct:
    3099                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    3100
    3101            operation_modifiers = []
    3102            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
    3103                operation_modifiers.append(exp.var(self._prev.text.upper()))
    3104
    3105            limit = self._parse_limit(top=True)
    3106            projections = self._parse_projections()
    3107
    3108            this = self.expression(
    3109                exp.Select,
    3110                kind=kind,
    3111                hint=hint,
    3112                distinct=distinct,
    3113                expressions=projections,
    3114                limit=limit,
    3115                operation_modifiers=operation_modifiers or None,
    3116            )
    3117            this.comments = comments
    3118
    3119            into = self._parse_into()
    3120            if into:
    3121                this.set("into", into)
    3122
    3123            if not from_:
    3124                from_ = self._parse_from()
    3125
    3126            if from_:
    3127                this.set("from", from_)
    3128
    3129            this = self._parse_query_modifiers(this)
    3130        elif (table or nested) and self._match(TokenType.L_PAREN):
    3131            if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
    3132                this = self._parse_simplified_pivot(
    3133                    is_unpivot=self._prev.token_type == TokenType.UNPIVOT
    3134                )
    3135            elif self._match(TokenType.FROM):
    3136                from_ = self._parse_from(skip_from_token=True)
    3137                # Support parentheses for duckdb FROM-first syntax
    3138                select = self._parse_select()
    3139                if select:
    3140                    select.set("from", from_)
    3141                    this = select
    3142                else:
    3143                    this = exp.select("*").from_(t.cast(exp.From, from_))
    3144            else:
    3145                this = (
    3146                    self._parse_table()
    3147                    if table
    3148                    else self._parse_select(nested=True, parse_set_operation=False)
    3149                )
    3150
    3151                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
    3152                # in case a modifier (e.g. join) is following
    3153                if table and isinstance(this, exp.Values) and this.alias:
    3154                    alias = this.args["alias"].pop()
    3155                    this = exp.Table(this=this, alias=alias)
    3156
    3157                this = self._parse_query_modifiers(self._parse_set_operations(this))
    3158
    3159            self._match_r_paren()
    3160
    3161            # We return early here so that the UNION isn't attached to the subquery by the
    3162            # following call to _parse_set_operations, but instead becomes the parent node
    3163            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    3164        elif self._match(TokenType.VALUES, advance=False):
    3165            this = self._parse_derived_table_values()
    3166        elif from_:
    3167            this = exp.select("*").from_(from_.this, copy=False)
    3168        elif self._match(TokenType.SUMMARIZE):
    3169            table = self._match(TokenType.TABLE)
    3170            this = self._parse_select() or self._parse_string() or self._parse_table()
    3171            return self.expression(exp.Summarize, this=this, table=table)
    3172        elif self._match(TokenType.DESCRIBE):
    3173            this = self._parse_describe()
    3174        elif self._match_text_seq("STREAM"):
    3175            this = self._parse_function()
    3176            if this:
    3177                this = self.expression(exp.Stream, this=this)
    3178            else:
    3179                self._retreat(self._index - 1)
    3180        else:
    3181            this = None
    3182
    3183        return self._parse_set_operations(this) if parse_set_operation else this
    3184
    3185    def _parse_recursive_with_search(self) -> t.Optional[exp.RecursiveWithSearch]:
    3186        self._match_text_seq("SEARCH")
    3187
    3188        kind = self._match_texts(self.RECURSIVE_CTE_SEARCH_KIND) and self._prev.text.upper()
    3189
    3190        if not kind:
    3191            return None
    3192
    3193        self._match_text_seq("FIRST", "BY")
    3194
    3195        return self.expression(
    3196            exp.RecursiveWithSearch,
    3197            kind=kind,
    3198            this=self._parse_id_var(),
    3199            expression=self._match_text_seq("SET") and self._parse_id_var(),
    3200            using=self._match_text_seq("USING") and self._parse_id_var(),
    3201        )
    3202
    3203    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    3204        if not skip_with_token and not self._match(TokenType.WITH):
    3205            return None
    3206
    3207        comments = self._prev_comments
    3208        recursive = self._match(TokenType.RECURSIVE)
    3209
    3210        last_comments = None
    3211        expressions = []
    3212        while True:
    3213            cte = self._parse_cte()
    3214            if isinstance(cte, exp.CTE):
    3215                expressions.append(cte)
    3216                if last_comments:
    3217                    cte.add_comments(last_comments)
    3218
    3219            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    3220                break
    3221            else:
    3222                self._match(TokenType.WITH)
    3223
    3224            last_comments = self._prev_comments
    3225
    3226        return self.expression(
    3227            exp.With,
    3228            comments=comments,
    3229            expressions=expressions,
    3230            recursive=recursive,
    3231            search=self._parse_recursive_with_search(),
    3232        )
    3233
    3234    def _parse_cte(self) -> t.Optional[exp.CTE]:
    3235        index = self._index
    3236
    3237        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    3238        if not alias or not alias.this:
    3239            self.raise_error("Expected CTE to have alias")
    3240
    3241        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
    3242            self._retreat(index)
    3243            return None
    3244
    3245        comments = self._prev_comments
    3246
    3247        if self._match_text_seq("NOT", "MATERIALIZED"):
    3248            materialized = False
    3249        elif self._match_text_seq("MATERIALIZED"):
    3250            materialized = True
    3251        else:
    3252            materialized = None
    3253
    3254        cte = self.expression(
    3255            exp.CTE,
    3256            this=self._parse_wrapped(self._parse_statement),
    3257            alias=alias,
    3258            materialized=materialized,
    3259            comments=comments,
    3260        )
    3261
    3262        if isinstance(cte.this, exp.Values):
    3263            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
    3264
    3265        return cte
    3266
    3267    def _parse_table_alias(
    3268        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    3269    ) -> t.Optional[exp.TableAlias]:
    3270        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    3271        # so this section tries to parse the clause version and if it fails, it treats the token
    3272        # as an identifier (alias)
    3273        if self._can_parse_limit_or_offset():
    3274            return None
    3275
    3276        any_token = self._match(TokenType.ALIAS)
    3277        alias = (
    3278            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3279            or self._parse_string_as_identifier()
    3280        )
    3281
    3282        index = self._index
    3283        if self._match(TokenType.L_PAREN):
    3284            columns = self._parse_csv(self._parse_function_parameter)
    3285            self._match_r_paren() if columns else self._retreat(index)
    3286        else:
    3287            columns = None
    3288
    3289        if not alias and not columns:
    3290            return None
    3291
    3292        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    3293
    3294        # We bubble up comments from the Identifier to the TableAlias
    3295        if isinstance(alias, exp.Identifier):
    3296            table_alias.add_comments(alias.pop_comments())
    3297
    3298        return table_alias
    3299
    3300    def _parse_subquery(
    3301        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    3302    ) -> t.Optional[exp.Subquery]:
    3303        if not this:
    3304            return None
    3305
    3306        return self.expression(
    3307            exp.Subquery,
    3308            this=this,
    3309            pivots=self._parse_pivots(),
    3310            alias=self._parse_table_alias() if parse_alias else None,
    3311            sample=self._parse_table_sample(),
    3312        )
    3313
    3314    def _implicit_unnests_to_explicit(self, this: E) -> E:
    3315        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    3316
    3317        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    3318        for i, join in enumerate(this.args.get("joins") or []):
    3319            table = join.this
    3320            normalized_table = table.copy()
    3321            normalized_table.meta["maybe_column"] = True
    3322            normalized_table = _norm(normalized_table, dialect=self.dialect)
    3323
    3324            if isinstance(table, exp.Table) and not join.args.get("on"):
    3325                if normalized_table.parts[0].name in refs:
    3326                    table_as_column = table.to_column()
    3327                    unnest = exp.Unnest(expressions=[table_as_column])
    3328
    3329                    # Table.to_column creates a parent Alias node that we want to convert to
    3330                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    3331                    if isinstance(table.args.get("alias"), exp.TableAlias):
    3332                        table_as_column.replace(table_as_column.this)
    3333                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    3334
    3335                    table.replace(unnest)
    3336
    3337            refs.add(normalized_table.alias_or_name)
    3338
    3339        return this
    3340
    3341    def _parse_query_modifiers(
    3342        self, this: t.Optional[exp.Expression]
    3343    ) -> t.Optional[exp.Expression]:
    3344        if isinstance(this, (exp.Query, exp.Table)):
    3345            for join in self._parse_joins():
    3346                this.append("joins", join)
    3347            for lateral in iter(self._parse_lateral, None):
    3348                this.append("laterals", lateral)
    3349
    3350            while True:
    3351                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    3352                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    3353                    key, expression = parser(self)
    3354
    3355                    if expression:
    3356                        this.set(key, expression)
    3357                        if key == "limit":
    3358                            offset = expression.args.pop("offset", None)
    3359
    3360                            if offset:
    3361                                offset = exp.Offset(expression=offset)
    3362                                this.set("offset", offset)
    3363
    3364                                limit_by_expressions = expression.expressions
    3365                                expression.set("expressions", None)
    3366                                offset.set("expressions", limit_by_expressions)
    3367                        continue
    3368                break
    3369
    3370        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
    3371            this = self._implicit_unnests_to_explicit(this)
    3372
    3373        return this
    3374
    3375    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
    3376        start = self._curr
    3377        while self._curr:
    3378            self._advance()
    3379
    3380        end = self._tokens[self._index - 1]
    3381        return exp.Hint(expressions=[self._find_sql(start, end)])
    3382
    3383    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
    3384        return self._parse_function_call()
    3385
    3386    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
    3387        start_index = self._index
    3388        should_fallback_to_string = False
    3389
    3390        hints = []
    3391        try:
    3392            for hint in iter(
    3393                lambda: self._parse_csv(
    3394                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
    3395                ),
    3396                [],
    3397            ):
    3398                hints.extend(hint)
    3399        except ParseError:
    3400            should_fallback_to_string = True
    3401
    3402        if should_fallback_to_string or self._curr:
    3403            self._retreat(start_index)
    3404            return self._parse_hint_fallback_to_string()
    3405
    3406        return self.expression(exp.Hint, expressions=hints)
    3407
    3408    def _parse_hint(self) -> t.Optional[exp.Hint]:
    3409        if self._match(TokenType.HINT) and self._prev_comments:
    3410            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
    3411
    3412        return None
    3413
    3414    def _parse_into(self) -> t.Optional[exp.Into]:
    3415        if not self._match(TokenType.INTO):
    3416            return None
    3417
    3418        temp = self._match(TokenType.TEMPORARY)
    3419        unlogged = self._match_text_seq("UNLOGGED")
    3420        self._match(TokenType.TABLE)
    3421
    3422        return self.expression(
    3423            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    3424        )
    3425
    3426    def _parse_from(
    3427        self, joins: bool = False, skip_from_token: bool = False
    3428    ) -> t.Optional[exp.From]:
    3429        if not skip_from_token and not self._match(TokenType.FROM):
    3430            return None
    3431
    3432        return self.expression(
    3433            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    3434        )
    3435
    3436    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    3437        return self.expression(
    3438            exp.MatchRecognizeMeasure,
    3439            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    3440            this=self._parse_expression(),
    3441        )
    3442
    3443    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    3444        if not self._match(TokenType.MATCH_RECOGNIZE):
    3445            return None
    3446
    3447        self._match_l_paren()
    3448
    3449        partition = self._parse_partition_by()
    3450        order = self._parse_order()
    3451
    3452        measures = (
    3453            self._parse_csv(self._parse_match_recognize_measure)
    3454            if self._match_text_seq("MEASURES")
    3455            else None
    3456        )
    3457
    3458        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    3459            rows = exp.var("ONE ROW PER MATCH")
    3460        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    3461            text = "ALL ROWS PER MATCH"
    3462            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    3463                text += " SHOW EMPTY MATCHES"
    3464            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    3465                text += " OMIT EMPTY MATCHES"
    3466            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    3467                text += " WITH UNMATCHED ROWS"
    3468            rows = exp.var(text)
    3469        else:
    3470            rows = None
    3471
    3472        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    3473            text = "AFTER MATCH SKIP"
    3474            if self._match_text_seq("PAST", "LAST", "ROW"):
    3475                text += " PAST LAST ROW"
    3476            elif self._match_text_seq("TO", "NEXT", "ROW"):
    3477                text += " TO NEXT ROW"
    3478            elif self._match_text_seq("TO", "FIRST"):
    3479                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    3480            elif self._match_text_seq("TO", "LAST"):
    3481                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    3482            after = exp.var(text)
    3483        else:
    3484            after = None
    3485
    3486        if self._match_text_seq("PATTERN"):
    3487            self._match_l_paren()
    3488
    3489            if not self._curr:
    3490                self.raise_error("Expecting )", self._curr)
    3491
    3492            paren = 1
    3493            start = self._curr
    3494
    3495            while self._curr and paren > 0:
    3496                if self._curr.token_type == TokenType.L_PAREN:
    3497                    paren += 1
    3498                if self._curr.token_type == TokenType.R_PAREN:
    3499                    paren -= 1
    3500
    3501                end = self._prev
    3502                self._advance()
    3503
    3504            if paren > 0:
    3505                self.raise_error("Expecting )", self._curr)
    3506
    3507            pattern = exp.var(self._find_sql(start, end))
    3508        else:
    3509            pattern = None
    3510
    3511        define = (
    3512            self._parse_csv(self._parse_name_as_expression)
    3513            if self._match_text_seq("DEFINE")
    3514            else None
    3515        )
    3516
    3517        self._match_r_paren()
    3518
    3519        return self.expression(
    3520            exp.MatchRecognize,
    3521            partition_by=partition,
    3522            order=order,
    3523            measures=measures,
    3524            rows=rows,
    3525            after=after,
    3526            pattern=pattern,
    3527            define=define,
    3528            alias=self._parse_table_alias(),
    3529        )
    3530
    3531    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3532        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3533        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3534            cross_apply = False
    3535
    3536        if cross_apply is not None:
    3537            this = self._parse_select(table=True)
    3538            view = None
    3539            outer = None
    3540        elif self._match(TokenType.LATERAL):
    3541            this = self._parse_select(table=True)
    3542            view = self._match(TokenType.VIEW)
    3543            outer = self._match(TokenType.OUTER)
    3544        else:
    3545            return None
    3546
    3547        if not this:
    3548            this = (
    3549                self._parse_unnest()
    3550                or self._parse_function()
    3551                or self._parse_id_var(any_token=False)
    3552            )
    3553
    3554            while self._match(TokenType.DOT):
    3555                this = exp.Dot(
    3556                    this=this,
    3557                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3558                )
    3559
    3560        if view:
    3561            table = self._parse_id_var(any_token=False)
    3562            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3563            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3564                exp.TableAlias, this=table, columns=columns
    3565            )
    3566        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3567            # We move the alias from the lateral's child node to the lateral itself
    3568            table_alias = this.args["alias"].pop()
    3569        else:
    3570            table_alias = self._parse_table_alias()
    3571
    3572        return self.expression(
    3573            exp.Lateral,
    3574            this=this,
    3575            view=view,
    3576            outer=outer,
    3577            alias=table_alias,
    3578            cross_apply=cross_apply,
    3579        )
    3580
    3581    def _parse_join_parts(
    3582        self,
    3583    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3584        return (
    3585            self._match_set(self.JOIN_METHODS) and self._prev,
    3586            self._match_set(self.JOIN_SIDES) and self._prev,
    3587            self._match_set(self.JOIN_KINDS) and self._prev,
    3588        )
    3589
    3590    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
    3591        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
    3592            this = self._parse_column()
    3593            if isinstance(this, exp.Column):
    3594                return this.this
    3595            return this
    3596
    3597        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
    3598
    3599    def _parse_join(
    3600        self, skip_join_token: bool = False, parse_bracket: bool = False
    3601    ) -> t.Optional[exp.Join]:
    3602        if self._match(TokenType.COMMA):
    3603            return self.expression(exp.Join, this=self._parse_table())
    3604
    3605        index = self._index
    3606        method, side, kind = self._parse_join_parts()
    3607        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3608        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
    3609
    3610        if not skip_join_token and not join:
    3611            self._retreat(index)
    3612            kind = None
    3613            method = None
    3614            side = None
    3615
    3616        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3617        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3618
    3619        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3620            return None
    3621
    3622        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3623        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
    3624            kwargs["expressions"] = self._parse_csv(
    3625                lambda: self._parse_table(parse_bracket=parse_bracket)
    3626            )
    3627
    3628        if method:
    3629            kwargs["method"] = method.text
    3630        if side:
    3631            kwargs["side"] = side.text
    3632        if kind:
    3633            kwargs["kind"] = kind.text
    3634        if hint:
    3635            kwargs["hint"] = hint
    3636
    3637        if self._match(TokenType.MATCH_CONDITION):
    3638            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3639
    3640        if self._match(TokenType.ON):
    3641            kwargs["on"] = self._parse_assignment()
    3642        elif self._match(TokenType.USING):
    3643            kwargs["using"] = self._parse_using_identifiers()
    3644        elif (
    3645            not (outer_apply or cross_apply)
    3646            and not isinstance(kwargs["this"], exp.Unnest)
    3647            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
    3648        ):
    3649            index = self._index
    3650            joins: t.Optional[list] = list(self._parse_joins())
    3651
    3652            if joins and self._match(TokenType.ON):
    3653                kwargs["on"] = self._parse_assignment()
    3654            elif joins and self._match(TokenType.USING):
    3655                kwargs["using"] = self._parse_using_identifiers()
    3656            else:
    3657                joins = None
    3658                self._retreat(index)
    3659
    3660            kwargs["this"].set("joins", joins if joins else None)
    3661
    3662        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3663        return self.expression(exp.Join, comments=comments, **kwargs)
    3664
    3665    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3666        this = self._parse_assignment()
    3667
    3668        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3669            return this
    3670
    3671        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3672            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3673
    3674        return this
    3675
    3676    def _parse_index_params(self) -> exp.IndexParameters:
    3677        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3678
    3679        if self._match(TokenType.L_PAREN, advance=False):
    3680            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3681        else:
    3682            columns = None
    3683
    3684        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3685        partition_by = self._parse_partition_by()
    3686        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3687        tablespace = (
    3688            self._parse_var(any_token=True)
    3689            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3690            else None
    3691        )
    3692        where = self._parse_where()
    3693
    3694        on = self._parse_field() if self._match(TokenType.ON) else None
    3695
    3696        return self.expression(
    3697            exp.IndexParameters,
    3698            using=using,
    3699            columns=columns,
    3700            include=include,
    3701            partition_by=partition_by,
    3702            where=where,
    3703            with_storage=with_storage,
    3704            tablespace=tablespace,
    3705            on=on,
    3706        )
    3707
    3708    def _parse_index(
    3709        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3710    ) -> t.Optional[exp.Index]:
    3711        if index or anonymous:
    3712            unique = None
    3713            primary = None
    3714            amp = None
    3715
    3716            self._match(TokenType.ON)
    3717            self._match(TokenType.TABLE)  # hive
    3718            table = self._parse_table_parts(schema=True)
    3719        else:
    3720            unique = self._match(TokenType.UNIQUE)
    3721            primary = self._match_text_seq("PRIMARY")
    3722            amp = self._match_text_seq("AMP")
    3723
    3724            if not self._match(TokenType.INDEX):
    3725                return None
    3726
    3727            index = self._parse_id_var()
    3728            table = None
    3729
    3730        params = self._parse_index_params()
    3731
    3732        return self.expression(
    3733            exp.Index,
    3734            this=index,
    3735            table=table,
    3736            unique=unique,
    3737            primary=primary,
    3738            amp=amp,
    3739            params=params,
    3740        )
    3741
    3742    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3743        hints: t.List[exp.Expression] = []
    3744        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3745            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3746            hints.append(
    3747                self.expression(
    3748                    exp.WithTableHint,
    3749                    expressions=self._parse_csv(
    3750                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3751                    ),
    3752                )
    3753            )
    3754            self._match_r_paren()
    3755        else:
    3756            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3757            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3758                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3759
    3760                self._match_set((TokenType.INDEX, TokenType.KEY))
    3761                if self._match(TokenType.FOR):
    3762                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3763
    3764                hint.set("expressions", self._parse_wrapped_id_vars())
    3765                hints.append(hint)
    3766
    3767        return hints or None
    3768
    3769    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3770        return (
    3771            (not schema and self._parse_function(optional_parens=False))
    3772            or self._parse_id_var(any_token=False)
    3773            or self._parse_string_as_identifier()
    3774            or self._parse_placeholder()
    3775        )
    3776
    3777    def _parse_table_parts(
    3778        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3779    ) -> exp.Table:
    3780        catalog = None
    3781        db = None
    3782        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3783
    3784        while self._match(TokenType.DOT):
    3785            if catalog:
    3786                # This allows nesting the table in arbitrarily many dot expressions if needed
    3787                table = self.expression(
    3788                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3789                )
    3790            else:
    3791                catalog = db
    3792                db = table
    3793                # "" used for tsql FROM a..b case
    3794                table = self._parse_table_part(schema=schema) or ""
    3795
    3796        if (
    3797            wildcard
    3798            and self._is_connected()
    3799            and (isinstance(table, exp.Identifier) or not table)
    3800            and self._match(TokenType.STAR)
    3801        ):
    3802            if isinstance(table, exp.Identifier):
    3803                table.args["this"] += "*"
    3804            else:
    3805                table = exp.Identifier(this="*")
    3806
    3807        # We bubble up comments from the Identifier to the Table
    3808        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3809
    3810        if is_db_reference:
    3811            catalog = db
    3812            db = table
    3813            table = None
    3814
    3815        if not table and not is_db_reference:
    3816            self.raise_error(f"Expected table name but got {self._curr}")
    3817        if not db and is_db_reference:
    3818            self.raise_error(f"Expected database name but got {self._curr}")
    3819
    3820        table = self.expression(
    3821            exp.Table,
    3822            comments=comments,
    3823            this=table,
    3824            db=db,
    3825            catalog=catalog,
    3826        )
    3827
    3828        changes = self._parse_changes()
    3829        if changes:
    3830            table.set("changes", changes)
    3831
    3832        at_before = self._parse_historical_data()
    3833        if at_before:
    3834            table.set("when", at_before)
    3835
    3836        pivots = self._parse_pivots()
    3837        if pivots:
    3838            table.set("pivots", pivots)
    3839
    3840        return table
    3841
    3842    def _parse_table(
    3843        self,
    3844        schema: bool = False,
    3845        joins: bool = False,
    3846        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3847        parse_bracket: bool = False,
    3848        is_db_reference: bool = False,
    3849        parse_partition: bool = False,
    3850    ) -> t.Optional[exp.Expression]:
    3851        lateral = self._parse_lateral()
    3852        if lateral:
    3853            return lateral
    3854
    3855        unnest = self._parse_unnest()
    3856        if unnest:
    3857            return unnest
    3858
    3859        values = self._parse_derived_table_values()
    3860        if values:
    3861            return values
    3862
    3863        subquery = self._parse_select(table=True)
    3864        if subquery:
    3865            if not subquery.args.get("pivots"):
    3866                subquery.set("pivots", self._parse_pivots())
    3867            return subquery
    3868
    3869        bracket = parse_bracket and self._parse_bracket(None)
    3870        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3871
    3872        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
    3873            self._parse_table
    3874        )
    3875        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
    3876
    3877        only = self._match(TokenType.ONLY)
    3878
    3879        this = t.cast(
    3880            exp.Expression,
    3881            bracket
    3882            or rows_from
    3883            or self._parse_bracket(
    3884                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3885            ),
    3886        )
    3887
    3888        if only:
    3889            this.set("only", only)
    3890
    3891        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3892        self._match_text_seq("*")
    3893
    3894        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3895        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3896            this.set("partition", self._parse_partition())
    3897
    3898        if schema:
    3899            return self._parse_schema(this=this)
    3900
    3901        version = self._parse_version()
    3902
    3903        if version:
    3904            this.set("version", version)
    3905
    3906        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3907            this.set("sample", self._parse_table_sample())
    3908
    3909        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3910        if alias:
    3911            this.set("alias", alias)
    3912
    3913        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3914            return self.expression(
    3915                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3916            )
    3917
    3918        this.set("hints", self._parse_table_hints())
    3919
    3920        if not this.args.get("pivots"):
    3921            this.set("pivots", self._parse_pivots())
    3922
    3923        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3924            this.set("sample", self._parse_table_sample())
    3925
    3926        if joins:
    3927            for join in self._parse_joins():
    3928                this.append("joins", join)
    3929
    3930        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3931            this.set("ordinality", True)
    3932            this.set("alias", self._parse_table_alias())
    3933
    3934        return this
    3935
    3936    def _parse_version(self) -> t.Optional[exp.Version]:
    3937        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    3938            this = "TIMESTAMP"
    3939        elif self._match(TokenType.VERSION_SNAPSHOT):
    3940            this = "VERSION"
    3941        else:
    3942            return None
    3943
    3944        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    3945            kind = self._prev.text.upper()
    3946            start = self._parse_bitwise()
    3947            self._match_texts(("TO", "AND"))
    3948            end = self._parse_bitwise()
    3949            expression: t.Optional[exp.Expression] = self.expression(
    3950                exp.Tuple, expressions=[start, end]
    3951            )
    3952        elif self._match_text_seq("CONTAINED", "IN"):
    3953            kind = "CONTAINED IN"
    3954            expression = self.expression(
    3955                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    3956            )
    3957        elif self._match(TokenType.ALL):
    3958            kind = "ALL"
    3959            expression = None
    3960        else:
    3961            self._match_text_seq("AS", "OF")
    3962            kind = "AS OF"
    3963            expression = self._parse_type()
    3964
    3965        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    3966
    3967    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
    3968        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
    3969        index = self._index
    3970        historical_data = None
    3971        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
    3972            this = self._prev.text.upper()
    3973            kind = (
    3974                self._match(TokenType.L_PAREN)
    3975                and self._match_texts(self.HISTORICAL_DATA_KIND)
    3976                and self._prev.text.upper()
    3977            )
    3978            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    3979
    3980            if expression:
    3981                self._match_r_paren()
    3982                historical_data = self.expression(
    3983                    exp.HistoricalData, this=this, kind=kind, expression=expression
    3984                )
    3985            else:
    3986                self._retreat(index)
    3987
    3988        return historical_data
    3989
    3990    def _parse_changes(self) -> t.Optional[exp.Changes]:
    3991        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
    3992            return None
    3993
    3994        information = self._parse_var(any_token=True)
    3995        self._match_r_paren()
    3996
    3997        return self.expression(
    3998            exp.Changes,
    3999            information=information,
    4000            at_before=self._parse_historical_data(),
    4001            end=self._parse_historical_data(),
    4002        )
    4003
    4004    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    4005        if not self._match(TokenType.UNNEST):
    4006            return None
    4007
    4008        expressions = self._parse_wrapped_csv(self._parse_equality)
    4009        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    4010
    4011        alias = self._parse_table_alias() if with_alias else None
    4012
    4013        if alias:
    4014            if self.dialect.UNNEST_COLUMN_ONLY:
    4015                if alias.args.get("columns"):
    4016                    self.raise_error("Unexpected extra column alias in unnest.")
    4017
    4018                alias.set("columns", [alias.this])
    4019                alias.set("this", None)
    4020
    4021            columns = alias.args.get("columns") or []
    4022            if offset and len(expressions) < len(columns):
    4023                offset = columns.pop()
    4024
    4025        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    4026            self._match(TokenType.ALIAS)
    4027            offset = self._parse_id_var(
    4028                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    4029            ) or exp.to_identifier("offset")
    4030
    4031        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    4032
    4033    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    4034        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    4035        if not is_derived and not (
    4036            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
    4037            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
    4038        ):
    4039            return None
    4040
    4041        expressions = self._parse_csv(self._parse_value)
    4042        alias = self._parse_table_alias()
    4043
    4044        if is_derived:
    4045            self._match_r_paren()
    4046
    4047        return self.expression(
    4048            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    4049        )
    4050
    4051    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    4052        if not self._match(TokenType.TABLE_SAMPLE) and not (
    4053            as_modifier and self._match_text_seq("USING", "SAMPLE")
    4054        ):
    4055            return None
    4056
    4057        bucket_numerator = None
    4058        bucket_denominator = None
    4059        bucket_field = None
    4060        percent = None
    4061        size = None
    4062        seed = None
    4063
    4064        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    4065        matched_l_paren = self._match(TokenType.L_PAREN)
    4066
    4067        if self.TABLESAMPLE_CSV:
    4068            num = None
    4069            expressions = self._parse_csv(self._parse_primary)
    4070        else:
    4071            expressions = None
    4072            num = (
    4073                self._parse_factor()
    4074                if self._match(TokenType.NUMBER, advance=False)
    4075                else self._parse_primary() or self._parse_placeholder()
    4076            )
    4077
    4078        if self._match_text_seq("BUCKET"):
    4079            bucket_numerator = self._parse_number()
    4080            self._match_text_seq("OUT", "OF")
    4081            bucket_denominator = bucket_denominator = self._parse_number()
    4082            self._match(TokenType.ON)
    4083            bucket_field = self._parse_field()
    4084        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    4085            percent = num
    4086        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    4087            size = num
    4088        else:
    4089            percent = num
    4090
    4091        if matched_l_paren:
    4092            self._match_r_paren()
    4093
    4094        if self._match(TokenType.L_PAREN):
    4095            method = self._parse_var(upper=True)
    4096            seed = self._match(TokenType.COMMA) and self._parse_number()
    4097            self._match_r_paren()
    4098        elif self._match_texts(("SEED", "REPEATABLE")):
    4099            seed = self._parse_wrapped(self._parse_number)
    4100
    4101        if not method and self.DEFAULT_SAMPLING_METHOD:
    4102            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    4103
    4104        return self.expression(
    4105            exp.TableSample,
    4106            expressions=expressions,
    4107            method=method,
    4108            bucket_numerator=bucket_numerator,
    4109            bucket_denominator=bucket_denominator,
    4110            bucket_field=bucket_field,
    4111            percent=percent,
    4112            size=size,
    4113            seed=seed,
    4114        )
    4115
    4116    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    4117        return list(iter(self._parse_pivot, None)) or None
    4118
    4119    def _parse_joins(self) -> t.Iterator[exp.Join]:
    4120        return iter(self._parse_join, None)
    4121
    4122    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
    4123        if not self._match(TokenType.INTO):
    4124            return None
    4125
    4126        return self.expression(
    4127            exp.UnpivotColumns,
    4128            this=self._match_text_seq("NAME") and self._parse_column(),
    4129            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
    4130        )
    4131
    4132    # https://duckdb.org/docs/sql/statements/pivot
    4133    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
    4134        def _parse_on() -> t.Optional[exp.Expression]:
    4135            this = self._parse_bitwise()
    4136
    4137            if self._match(TokenType.IN):
    4138                # PIVOT ... ON col IN (row_val1, row_val2)
    4139                return self._parse_in(this)
    4140            if self._match(TokenType.ALIAS, advance=False):
    4141                # UNPIVOT ... ON (col1, col2, col3) AS row_val
    4142                return self._parse_alias(this)
    4143
    4144            return this
    4145
    4146        this = self._parse_table()
    4147        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    4148        into = self._parse_unpivot_columns()
    4149        using = self._match(TokenType.USING) and self._parse_csv(
    4150            lambda: self._parse_alias(self._parse_function())
    4151        )
    4152        group = self._parse_group()
    4153
    4154        return self.expression(
    4155            exp.Pivot,
    4156            this=this,
    4157            expressions=expressions,
    4158            using=using,
    4159            group=group,
    4160            unpivot=is_unpivot,
    4161            into=into,
    4162        )
    4163
    4164    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
    4165        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    4166            this = self._parse_select_or_expression()
    4167
    4168            self._match(TokenType.ALIAS)
    4169            alias = self._parse_bitwise()
    4170            if alias:
    4171                if isinstance(alias, exp.Column) and not alias.db:
    4172                    alias = alias.this
    4173                return self.expression(exp.PivotAlias, this=this, alias=alias)
    4174
    4175            return this
    4176
    4177        value = self._parse_column()
    4178
    4179        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    4180            self.raise_error("Expecting IN (")
    4181
    4182        if self._match(TokenType.ANY):
    4183            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
    4184        else:
    4185            exprs = self._parse_csv(_parse_aliased_expression)
    4186
    4187        self._match_r_paren()
    4188        return self.expression(exp.In, this=value, expressions=exprs)
    4189
    4190    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    4191        index = self._index
    4192        include_nulls = None
    4193
    4194        if self._match(TokenType.PIVOT):
    4195            unpivot = False
    4196        elif self._match(TokenType.UNPIVOT):
    4197            unpivot = True
    4198
    4199            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    4200            if self._match_text_seq("INCLUDE", "NULLS"):
    4201                include_nulls = True
    4202            elif self._match_text_seq("EXCLUDE", "NULLS"):
    4203                include_nulls = False
    4204        else:
    4205            return None
    4206
    4207        expressions = []
    4208
    4209        if not self._match(TokenType.L_PAREN):
    4210            self._retreat(index)
    4211            return None
    4212
    4213        if unpivot:
    4214            expressions = self._parse_csv(self._parse_column)
    4215        else:
    4216            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    4217
    4218        if not expressions:
    4219            self.raise_error("Failed to parse PIVOT's aggregation list")
    4220
    4221        if not self._match(TokenType.FOR):
    4222            self.raise_error("Expecting FOR")
    4223
    4224        field = self._parse_pivot_in()
    4225        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
    4226            self._parse_bitwise
    4227        )
    4228
    4229        self._match_r_paren()
    4230
    4231        pivot = self.expression(
    4232            exp.Pivot,
    4233            expressions=expressions,
    4234            field=field,
    4235            unpivot=unpivot,
    4236            include_nulls=include_nulls,
    4237            default_on_null=default_on_null,
    4238        )
    4239
    4240        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    4241            pivot.set("alias", self._parse_table_alias())
    4242
    4243        if not unpivot:
    4244            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    4245
    4246            columns: t.List[exp.Expression] = []
    4247            pivot_field_expressions = pivot.args["field"].expressions
    4248
    4249            # The `PivotAny` expression corresponds to `ANY ORDER BY <column>`; we can't infer in this case.
    4250            if not isinstance(seq_get(pivot_field_expressions, 0), exp.PivotAny):
    4251                for fld in pivot_field_expressions:
    4252                    field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    4253                    for name in names:
    4254                        if self.PREFIXED_PIVOT_COLUMNS:
    4255                            name = f"{name}_{field_name}" if name else field_name
    4256                        else:
    4257                            name = f"{field_name}_{name}" if name else field_name
    4258
    4259                        columns.append(exp.to_identifier(name))
    4260
    4261            pivot.set("columns", columns)
    4262
    4263        return pivot
    4264
    4265    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    4266        return [agg.alias for agg in aggregations]
    4267
    4268    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    4269        if not skip_where_token and not self._match(TokenType.PREWHERE):
    4270            return None
    4271
    4272        return self.expression(
    4273            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    4274        )
    4275
    4276    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    4277        if not skip_where_token and not self._match(TokenType.WHERE):
    4278            return None
    4279
    4280        return self.expression(
    4281            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    4282        )
    4283
    4284    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    4285        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    4286            return None
    4287
    4288        elements: t.Dict[str, t.Any] = defaultdict(list)
    4289
    4290        if self._match(TokenType.ALL):
    4291            elements["all"] = True
    4292        elif self._match(TokenType.DISTINCT):
    4293            elements["all"] = False
    4294
    4295        while True:
    4296            index = self._index
    4297
    4298            elements["expressions"].extend(
    4299                self._parse_csv(
    4300                    lambda: None
    4301                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
    4302                    else self._parse_assignment()
    4303                )
    4304            )
    4305
    4306            before_with_index = self._index
    4307            with_prefix = self._match(TokenType.WITH)
    4308
    4309            if self._match(TokenType.ROLLUP):
    4310                elements["rollup"].append(
    4311                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
    4312                )
    4313            elif self._match(TokenType.CUBE):
    4314                elements["cube"].append(
    4315                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
    4316                )
    4317            elif self._match(TokenType.GROUPING_SETS):
    4318                elements["grouping_sets"].append(
    4319                    self.expression(
    4320                        exp.GroupingSets,
    4321                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
    4322                    )
    4323                )
    4324            elif self._match_text_seq("TOTALS"):
    4325                elements["totals"] = True  # type: ignore
    4326
    4327            if before_with_index <= self._index <= before_with_index + 1:
    4328                self._retreat(before_with_index)
    4329                break
    4330
    4331            if index == self._index:
    4332                break
    4333
    4334        return self.expression(exp.Group, **elements)  # type: ignore
    4335
    4336    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
    4337        return self.expression(
    4338            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
    4339        )
    4340
    4341    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    4342        if self._match(TokenType.L_PAREN):
    4343            grouping_set = self._parse_csv(self._parse_column)
    4344            self._match_r_paren()
    4345            return self.expression(exp.Tuple, expressions=grouping_set)
    4346
    4347        return self._parse_column()
    4348
    4349    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    4350        if not skip_having_token and not self._match(TokenType.HAVING):
    4351            return None
    4352        return self.expression(exp.Having, this=self._parse_assignment())
    4353
    4354    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    4355        if not self._match(TokenType.QUALIFY):
    4356            return None
    4357        return self.expression(exp.Qualify, this=self._parse_assignment())
    4358
    4359    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    4360        if skip_start_token:
    4361            start = None
    4362        elif self._match(TokenType.START_WITH):
    4363            start = self._parse_assignment()
    4364        else:
    4365            return None
    4366
    4367        self._match(TokenType.CONNECT_BY)
    4368        nocycle = self._match_text_seq("NOCYCLE")
    4369        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    4370            exp.Prior, this=self._parse_bitwise()
    4371        )
    4372        connect = self._parse_assignment()
    4373        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    4374
    4375        if not start and self._match(TokenType.START_WITH):
    4376            start = self._parse_assignment()
    4377
    4378        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    4379
    4380    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
    4381        this = self._parse_id_var(any_token=True)
    4382        if self._match(TokenType.ALIAS):
    4383            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
    4384        return this
    4385
    4386    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    4387        if self._match_text_seq("INTERPOLATE"):
    4388            return self._parse_wrapped_csv(self._parse_name_as_expression)
    4389        return None
    4390
    4391    def _parse_order(
    4392        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    4393    ) -> t.Optional[exp.Expression]:
    4394        siblings = None
    4395        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    4396            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    4397                return this
    4398
    4399            siblings = True
    4400
    4401        return self.expression(
    4402            exp.Order,
    4403            this=this,
    4404            expressions=self._parse_csv(self._parse_ordered),
    4405            siblings=siblings,
    4406        )
    4407
    4408    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    4409        if not self._match(token):
    4410            return None
    4411        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    4412
    4413    def _parse_ordered(
    4414        self, parse_method: t.Optional[t.Callable] = None
    4415    ) -> t.Optional[exp.Ordered]:
    4416        this = parse_method() if parse_method else self._parse_assignment()
    4417        if not this:
    4418            return None
    4419
    4420        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
    4421            this = exp.var("ALL")
    4422
    4423        asc = self._match(TokenType.ASC)
    4424        desc = self._match(TokenType.DESC) or (asc and False)
    4425
    4426        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    4427        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    4428
    4429        nulls_first = is_nulls_first or False
    4430        explicitly_null_ordered = is_nulls_first or is_nulls_last
    4431
    4432        if (
    4433            not explicitly_null_ordered
    4434            and (
    4435                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    4436                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    4437            )
    4438            and self.dialect.NULL_ORDERING != "nulls_are_last"
    4439        ):
    4440            nulls_first = True
    4441
    4442        if self._match_text_seq("WITH", "FILL"):
    4443            with_fill = self.expression(
    4444                exp.WithFill,
    4445                **{  # type: ignore
    4446                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    4447                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    4448                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    4449                    "interpolate": self._parse_interpolate(),
    4450                },
    4451            )
    4452        else:
    4453            with_fill = None
    4454
    4455        return self.expression(
    4456            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    4457        )
    4458
    4459    def _parse_limit_options(self) -> exp.LimitOptions:
    4460        percent = self._match(TokenType.PERCENT)
    4461        rows = self._match_set((TokenType.ROW, TokenType.ROWS))
    4462        self._match_text_seq("ONLY")
    4463        with_ties = self._match_text_seq("WITH", "TIES")
    4464        return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
    4465
    4466    def _parse_limit(
    4467        self,
    4468        this: t.Optional[exp.Expression] = None,
    4469        top: bool = False,
    4470        skip_limit_token: bool = False,
    4471    ) -> t.Optional[exp.Expression]:
    4472        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    4473            comments = self._prev_comments
    4474            if top:
    4475                limit_paren = self._match(TokenType.L_PAREN)
    4476                expression = self._parse_term() if limit_paren else self._parse_number()
    4477
    4478                if limit_paren:
    4479                    self._match_r_paren()
    4480
    4481                limit_options = self._parse_limit_options()
    4482            else:
    4483                limit_options = None
    4484                expression = self._parse_term()
    4485
    4486            if self._match(TokenType.COMMA):
    4487                offset = expression
    4488                expression = self._parse_term()
    4489            else:
    4490                offset = None
    4491
    4492            limit_exp = self.expression(
    4493                exp.Limit,
    4494                this=this,
    4495                expression=expression,
    4496                offset=offset,
    4497                comments=comments,
    4498                limit_options=limit_options,
    4499                expressions=self._parse_limit_by(),
    4500            )
    4501
    4502            return limit_exp
    4503
    4504        if self._match(TokenType.FETCH):
    4505            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    4506            direction = self._prev.text.upper() if direction else "FIRST"
    4507
    4508            count = self._parse_field(tokens=self.FETCH_TOKENS)
    4509
    4510            return self.expression(
    4511                exp.Fetch,
    4512                direction=direction,
    4513                count=count,
    4514                limit_options=self._parse_limit_options(),
    4515            )
    4516
    4517        return this
    4518
    4519    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4520        if not self._match(TokenType.OFFSET):
    4521            return this
    4522
    4523        count = self._parse_term()
    4524        self._match_set((TokenType.ROW, TokenType.ROWS))
    4525
    4526        return self.expression(
    4527            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    4528        )
    4529
    4530    def _can_parse_limit_or_offset(self) -> bool:
    4531        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
    4532            return False
    4533
    4534        index = self._index
    4535        result = bool(
    4536            self._try_parse(self._parse_limit, retreat=True)
    4537            or self._try_parse(self._parse_offset, retreat=True)
    4538        )
    4539        self._retreat(index)
    4540        return result
    4541
    4542    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    4543        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    4544
    4545    def _parse_locks(self) -> t.List[exp.Lock]:
    4546        locks = []
    4547        while True:
    4548            if self._match_text_seq("FOR", "UPDATE"):
    4549                update = True
    4550            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    4551                "LOCK", "IN", "SHARE", "MODE"
    4552            ):
    4553                update = False
    4554            else:
    4555                break
    4556
    4557            expressions = None
    4558            if self._match_text_seq("OF"):
    4559                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    4560
    4561            wait: t.Optional[bool | exp.Expression] = None
    4562            if self._match_text_seq("NOWAIT"):
    4563                wait = True
    4564            elif self._match_text_seq("WAIT"):
    4565                wait = self._parse_primary()
    4566            elif self._match_text_seq("SKIP", "LOCKED"):
    4567                wait = False
    4568
    4569            locks.append(
    4570                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    4571            )
    4572
    4573        return locks
    4574
    4575    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4576        while this and self._match_set(self.SET_OPERATIONS):
    4577            token_type = self._prev.token_type
    4578
    4579            if token_type == TokenType.UNION:
    4580                operation: t.Type[exp.SetOperation] = exp.Union
    4581            elif token_type == TokenType.EXCEPT:
    4582                operation = exp.Except
    4583            else:
    4584                operation = exp.Intersect
    4585
    4586            comments = self._prev.comments
    4587
    4588            if self._match(TokenType.DISTINCT):
    4589                distinct: t.Optional[bool] = True
    4590            elif self._match(TokenType.ALL):
    4591                distinct = False
    4592            else:
    4593                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4594                if distinct is None:
    4595                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4596
    4597            by_name = self._match_text_seq("BY", "NAME")
    4598            expression = self._parse_select(nested=True, parse_set_operation=False)
    4599
    4600            this = self.expression(
    4601                operation,
    4602                comments=comments,
    4603                this=this,
    4604                distinct=distinct,
    4605                by_name=by_name,
    4606                expression=expression,
    4607            )
    4608
    4609        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
    4610            expression = this.expression
    4611
    4612            if expression:
    4613                for arg in self.SET_OP_MODIFIERS:
    4614                    expr = expression.args.get(arg)
    4615                    if expr:
    4616                        this.set(arg, expr.pop())
    4617
    4618        return this
    4619
    4620    def _parse_expression(self) -> t.Optional[exp.Expression]:
    4621        return self._parse_alias(self._parse_assignment())
    4622
    4623    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    4624        this = self._parse_disjunction()
    4625        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
    4626            # This allows us to parse <non-identifier token> := <expr>
    4627            this = exp.column(
    4628                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
    4629            )
    4630
    4631        while self._match_set(self.ASSIGNMENT):
    4632            if isinstance(this, exp.Column) and len(this.parts) == 1:
    4633                this = this.this
    4634
    4635            this = self.expression(
    4636                self.ASSIGNMENT[self._prev.token_type],
    4637                this=this,
    4638                comments=self._prev_comments,
    4639                expression=self._parse_assignment(),
    4640            )
    4641
    4642        return this
    4643
    4644    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4645        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4646
    4647    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4648        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4649
    4650    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4651        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4652
    4653    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4654        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4655
    4656    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4657        this = this or self._parse_bitwise()
    4658        negate = self._match(TokenType.NOT)
    4659
    4660        if self._match_set(self.RANGE_PARSERS):
    4661            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4662            if not expression:
    4663                return this
    4664
    4665            this = expression
    4666        elif self._match(TokenType.ISNULL):
    4667            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4668
    4669        # Postgres supports ISNULL and NOTNULL for conditions.
    4670        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4671        if self._match(TokenType.NOTNULL):
    4672            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4673            this = self.expression(exp.Not, this=this)
    4674
    4675        if negate:
    4676            this = self._negate_range(this)
    4677
    4678        if self._match(TokenType.IS):
    4679            this = self._parse_is(this)
    4680
    4681        return this
    4682
    4683    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4684        if not this:
    4685            return this
    4686
    4687        return self.expression(exp.Not, this=this)
    4688
    4689    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4690        index = self._index - 1
    4691        negate = self._match(TokenType.NOT)
    4692
    4693        if self._match_text_seq("DISTINCT", "FROM"):
    4694            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4695            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4696
    4697        if self._match(TokenType.JSON):
    4698            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
    4699
    4700            if self._match_text_seq("WITH"):
    4701                _with = True
    4702            elif self._match_text_seq("WITHOUT"):
    4703                _with = False
    4704            else:
    4705                _with = None
    4706
    4707            unique = self._match(TokenType.UNIQUE)
    4708            self._match_text_seq("KEYS")
    4709            expression: t.Optional[exp.Expression] = self.expression(
    4710                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
    4711            )
    4712        else:
    4713            expression = self._parse_primary() or self._parse_null()
    4714            if not expression:
    4715                self._retreat(index)
    4716                return None
    4717
    4718        this = self.expression(exp.Is, this=this, expression=expression)
    4719        return self.expression(exp.Not, this=this) if negate else this
    4720
    4721    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4722        unnest = self._parse_unnest(with_alias=False)
    4723        if unnest:
    4724            this = self.expression(exp.In, this=this, unnest=unnest)
    4725        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4726            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4727            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4728
    4729            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4730                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4731            else:
    4732                this = self.expression(exp.In, this=this, expressions=expressions)
    4733
    4734            if matched_l_paren:
    4735                self._match_r_paren(this)
    4736            elif not self._match(TokenType.R_BRACKET, expression=this):
    4737                self.raise_error("Expecting ]")
    4738        else:
    4739            this = self.expression(exp.In, this=this, field=self._parse_column())
    4740
    4741        return this
    4742
    4743    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4744        low = self._parse_bitwise()
    4745        self._match(TokenType.AND)
    4746        high = self._parse_bitwise()
    4747        return self.expression(exp.Between, this=this, low=low, high=high)
    4748
    4749    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4750        if not self._match(TokenType.ESCAPE):
    4751            return this
    4752        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4753
    4754    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4755        index = self._index
    4756
    4757        if not self._match(TokenType.INTERVAL) and match_interval:
    4758            return None
    4759
    4760        if self._match(TokenType.STRING, advance=False):
    4761            this = self._parse_primary()
    4762        else:
    4763            this = self._parse_term()
    4764
    4765        if not this or (
    4766            isinstance(this, exp.Column)
    4767            and not this.table
    4768            and not this.this.quoted
    4769            and this.name.upper() == "IS"
    4770        ):
    4771            self._retreat(index)
    4772            return None
    4773
    4774        unit = self._parse_function() or (
    4775            not self._match(TokenType.ALIAS, advance=False)
    4776            and self._parse_var(any_token=True, upper=True)
    4777        )
    4778
    4779        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4780        # each INTERVAL expression into this canonical form so it's easy to transpile
    4781        if this and this.is_number:
    4782            this = exp.Literal.string(this.to_py())
    4783        elif this and this.is_string:
    4784            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4785            if parts and unit:
    4786                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4787                unit = None
    4788                self._retreat(self._index - 1)
    4789
    4790            if len(parts) == 1:
    4791                this = exp.Literal.string(parts[0][0])
    4792                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4793        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4794            unit = self.expression(
    4795                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4796            )
    4797
    4798        interval = self.expression(exp.Interval, this=this, unit=unit)
    4799
    4800        index = self._index
    4801        self._match(TokenType.PLUS)
    4802
    4803        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4804        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4805            return self.expression(
    4806                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4807            )
    4808
    4809        self._retreat(index)
    4810        return interval
    4811
    4812    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4813        this = self._parse_term()
    4814
    4815        while True:
    4816            if self._match_set(self.BITWISE):
    4817                this = self.expression(
    4818                    self.BITWISE[self._prev.token_type],
    4819                    this=this,
    4820                    expression=self._parse_term(),
    4821                )
    4822            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4823                this = self.expression(
    4824                    exp.DPipe,
    4825                    this=this,
    4826                    expression=self._parse_term(),
    4827                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4828                )
    4829            elif self._match(TokenType.DQMARK):
    4830                this = self.expression(
    4831                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
    4832                )
    4833            elif self._match_pair(TokenType.LT, TokenType.LT):
    4834                this = self.expression(
    4835                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4836                )
    4837            elif self._match_pair(TokenType.GT, TokenType.GT):
    4838                this = self.expression(
    4839                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4840                )
    4841            else:
    4842                break
    4843
    4844        return this
    4845
    4846    def _parse_term(self) -> t.Optional[exp.Expression]:
    4847        this = self._parse_factor()
    4848
    4849        while self._match_set(self.TERM):
    4850            klass = self.TERM[self._prev.token_type]
    4851            comments = self._prev_comments
    4852            expression = self._parse_factor()
    4853
    4854            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4855
    4856            if isinstance(this, exp.Collate):
    4857                expr = this.expression
    4858
    4859                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
    4860                # fallback to Identifier / Var
    4861                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
    4862                    ident = expr.this
    4863                    if isinstance(ident, exp.Identifier):
    4864                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
    4865
    4866        return this
    4867
    4868    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4869        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4870        this = parse_method()
    4871
    4872        while self._match_set(self.FACTOR):
    4873            klass = self.FACTOR[self._prev.token_type]
    4874            comments = self._prev_comments
    4875            expression = parse_method()
    4876
    4877            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4878                self._retreat(self._index - 1)
    4879                return this
    4880
    4881            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4882
    4883            if isinstance(this, exp.Div):
    4884                this.args["typed"] = self.dialect.TYPED_DIVISION
    4885                this.args["safe"] = self.dialect.SAFE_DIVISION
    4886
    4887        return this
    4888
    4889    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    4890        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    4891
    4892    def _parse_unary(self) -> t.Optional[exp.Expression]:
    4893        if self._match_set(self.UNARY_PARSERS):
    4894            return self.UNARY_PARSERS[self._prev.token_type](self)
    4895        return self._parse_at_time_zone(self._parse_type())
    4896
    4897    def _parse_type(
    4898        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    4899    ) -> t.Optional[exp.Expression]:
    4900        interval = parse_interval and self._parse_interval()
    4901        if interval:
    4902            return interval
    4903
    4904        index = self._index
    4905        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    4906
    4907        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
    4908        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
    4909        if isinstance(data_type, exp.Cast):
    4910            # This constructor can contain ops directly after it, for instance struct unnesting:
    4911            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
    4912            return self._parse_column_ops(data_type)
    4913
    4914        if data_type:
    4915            index2 = self._index
    4916            this = self._parse_primary()
    4917
    4918            if isinstance(this, exp.Literal):
    4919                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    4920                if parser:
    4921                    return parser(self, this, data_type)
    4922
    4923                return self.expression(exp.Cast, this=this, to=data_type)
    4924
    4925            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    4926            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    4927            #
    4928            # If the index difference here is greater than 1, that means the parser itself must have
    4929            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    4930            #
    4931            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    4932            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    4933            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    4934            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    4935            #
    4936            # In these cases, we don't really want to return the converted type, but instead retreat
    4937            # and try to parse a Column or Identifier in the section below.
    4938            if data_type.expressions and index2 - index > 1:
    4939                self._retreat(index2)
    4940                return self._parse_column_ops(data_type)
    4941
    4942            self._retreat(index)
    4943
    4944        if fallback_to_identifier:
    4945            return self._parse_id_var()
    4946
    4947        this = self._parse_column()
    4948        return this and self._parse_column_ops(this)
    4949
    4950    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    4951        this = self._parse_type()
    4952        if not this:
    4953            return None
    4954
    4955        if isinstance(this, exp.Column) and not this.table:
    4956            this = exp.var(this.name.upper())
    4957
    4958        return self.expression(
    4959            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    4960        )
    4961
    4962    def _parse_types(
    4963        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    4964    ) -> t.Optional[exp.Expression]:
    4965        index = self._index
    4966
    4967        this: t.Optional[exp.Expression] = None
    4968        prefix = self._match_text_seq("SYSUDTLIB", ".")
    4969
    4970        if not self._match_set(self.TYPE_TOKENS):
    4971            identifier = allow_identifiers and self._parse_id_var(
    4972                any_token=False, tokens=(TokenType.VAR,)
    4973            )
    4974            if isinstance(identifier, exp.Identifier):
    4975                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
    4976
    4977                if len(tokens) != 1:
    4978                    self.raise_error("Unexpected identifier", self._prev)
    4979
    4980                if tokens[0].token_type in self.TYPE_TOKENS:
    4981                    self._prev = tokens[0]
    4982                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    4983                    type_name = identifier.name
    4984
    4985                    while self._match(TokenType.DOT):
    4986                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    4987
    4988                    this = exp.DataType.build(type_name, udt=True)
    4989                else:
    4990                    self._retreat(self._index - 1)
    4991                    return None
    4992            else:
    4993                return None
    4994
    4995        type_token = self._prev.token_type
    4996
    4997        if type_token == TokenType.PSEUDO_TYPE:
    4998            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    4999
    5000        if type_token == TokenType.OBJECT_IDENTIFIER:
    5001            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    5002
    5003        # https://materialize.com/docs/sql/types/map/
    5004        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    5005            key_type = self._parse_types(
    5006                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5007            )
    5008            if not self._match(TokenType.FARROW):
    5009                self._retreat(index)
    5010                return None
    5011
    5012            value_type = self._parse_types(
    5013                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5014            )
    5015            if not self._match(TokenType.R_BRACKET):
    5016                self._retreat(index)
    5017                return None
    5018
    5019            return exp.DataType(
    5020                this=exp.DataType.Type.MAP,
    5021                expressions=[key_type, value_type],
    5022                nested=True,
    5023                prefix=prefix,
    5024            )
    5025
    5026        nested = type_token in self.NESTED_TYPE_TOKENS
    5027        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    5028        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    5029        expressions = None
    5030        maybe_func = False
    5031
    5032        if self._match(TokenType.L_PAREN):
    5033            if is_struct:
    5034                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5035            elif nested:
    5036                expressions = self._parse_csv(
    5037                    lambda: self._parse_types(
    5038                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5039                    )
    5040                )
    5041                if type_token == TokenType.NULLABLE and len(expressions) == 1:
    5042                    this = expressions[0]
    5043                    this.set("nullable", True)
    5044                    self._match_r_paren()
    5045                    return this
    5046            elif type_token in self.ENUM_TYPE_TOKENS:
    5047                expressions = self._parse_csv(self._parse_equality)
    5048            elif is_aggregate:
    5049                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    5050                    any_token=False, tokens=(TokenType.VAR, TokenType.ANY)
    5051                )
    5052                if not func_or_ident:
    5053                    return None
    5054                expressions = [func_or_ident]
    5055                if self._match(TokenType.COMMA):
    5056                    expressions.extend(
    5057                        self._parse_csv(
    5058                            lambda: self._parse_types(
    5059                                check_func=check_func,
    5060                                schema=schema,
    5061                                allow_identifiers=allow_identifiers,
    5062                            )
    5063                        )
    5064                    )
    5065            else:
    5066                expressions = self._parse_csv(self._parse_type_size)
    5067
    5068                # https://docs.snowflake.com/en/sql-reference/data-types-vector
    5069                if type_token == TokenType.VECTOR and len(expressions) == 2:
    5070                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
    5071
    5072            if not expressions or not self._match(TokenType.R_PAREN):
    5073                self._retreat(index)
    5074                return None
    5075
    5076            maybe_func = True
    5077
    5078        values: t.Optional[t.List[exp.Expression]] = None
    5079
    5080        if nested and self._match(TokenType.LT):
    5081            if is_struct:
    5082                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5083            else:
    5084                expressions = self._parse_csv(
    5085                    lambda: self._parse_types(
    5086                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5087                    )
    5088                )
    5089
    5090            if not self._match(TokenType.GT):
    5091                self.raise_error("Expecting >")
    5092
    5093            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    5094                values = self._parse_csv(self._parse_assignment)
    5095                if not values and is_struct:
    5096                    values = None
    5097                    self._retreat(self._index - 1)
    5098                else:
    5099                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    5100
    5101        if type_token in self.TIMESTAMPS:
    5102            if self._match_text_seq("WITH", "TIME", "ZONE"):
    5103                maybe_func = False
    5104                tz_type = (
    5105                    exp.DataType.Type.TIMETZ
    5106                    if type_token in self.TIMES
    5107                    else exp.DataType.Type.TIMESTAMPTZ
    5108                )
    5109                this = exp.DataType(this=tz_type, expressions=expressions)
    5110            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    5111                maybe_func = False
    5112                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    5113            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    5114                maybe_func = False
    5115        elif type_token == TokenType.INTERVAL:
    5116            unit = self._parse_var(upper=True)
    5117            if unit:
    5118                if self._match_text_seq("TO"):
    5119                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    5120
    5121                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    5122            else:
    5123                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    5124
    5125        if maybe_func and check_func:
    5126            index2 = self._index
    5127            peek = self._parse_string()
    5128
    5129            if not peek:
    5130                self._retreat(index)
    5131                return None
    5132
    5133            self._retreat(index2)
    5134
    5135        if not this:
    5136            if self._match_text_seq("UNSIGNED"):
    5137                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    5138                if not unsigned_type_token:
    5139                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    5140
    5141                type_token = unsigned_type_token or type_token
    5142
    5143            this = exp.DataType(
    5144                this=exp.DataType.Type[type_token.value],
    5145                expressions=expressions,
    5146                nested=nested,
    5147                prefix=prefix,
    5148            )
    5149
    5150            # Empty arrays/structs are allowed
    5151            if values is not None:
    5152                cls = exp.Struct if is_struct else exp.Array
    5153                this = exp.cast(cls(expressions=values), this, copy=False)
    5154
    5155        elif expressions:
    5156            this.set("expressions", expressions)
    5157
    5158        # https://materialize.com/docs/sql/types/list/#type-name
    5159        while self._match(TokenType.LIST):
    5160            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    5161
    5162        index = self._index
    5163
    5164        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    5165        matched_array = self._match(TokenType.ARRAY)
    5166
    5167        while self._curr:
    5168            datatype_token = self._prev.token_type
    5169            matched_l_bracket = self._match(TokenType.L_BRACKET)
    5170
    5171            if (not matched_l_bracket and not matched_array) or (
    5172                datatype_token == TokenType.ARRAY and self._match(TokenType.R_BRACKET)
    5173            ):
    5174                # Postgres allows casting empty arrays such as ARRAY[]::INT[],
    5175                # not to be confused with the fixed size array parsing
    5176                break
    5177
    5178            matched_array = False
    5179            values = self._parse_csv(self._parse_assignment) or None
    5180            if (
    5181                values
    5182                and not schema
    5183                and (
    5184                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
    5185                )
    5186            ):
    5187                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
    5188                # ARRAY[1] should retreat and instead be parsed into exp.Array in contrast to INT[x][y] which denotes a fixed-size array data type
    5189                self._retreat(index)
    5190                break
    5191
    5192            this = exp.DataType(
    5193                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    5194            )
    5195            self._match(TokenType.R_BRACKET)
    5196
    5197        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
    5198            converter = self.TYPE_CONVERTERS.get(this.this)
    5199            if converter:
    5200                this = converter(t.cast(exp.DataType, this))
    5201
    5202        return this
    5203
    5204    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    5205        index = self._index
    5206
    5207        if (
    5208            self._curr
    5209            and self._next
    5210            and self._curr.token_type in self.TYPE_TOKENS
    5211            and self._next.token_type in self.TYPE_TOKENS
    5212        ):
    5213            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
    5214            # type token. Without this, the list will be parsed as a type and we'll eventually crash
    5215            this = self._parse_id_var()
    5216        else:
    5217            this = (
    5218                self._parse_type(parse_interval=False, fallback_to_identifier=True)
    5219                or self._parse_id_var()
    5220            )
    5221
    5222        self._match(TokenType.COLON)
    5223
    5224        if (
    5225            type_required
    5226            and not isinstance(this, exp.DataType)
    5227            and not self._match_set(self.TYPE_TOKENS, advance=False)
    5228        ):
    5229            self._retreat(index)
    5230            return self._parse_types()
    5231
    5232        return self._parse_column_def(this)
    5233
    5234    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5235        if not self._match_text_seq("AT", "TIME", "ZONE"):
    5236            return this
    5237        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    5238
    5239    def _parse_column(self) -> t.Optional[exp.Expression]:
    5240        this = self._parse_column_reference()
    5241        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
    5242
    5243        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
    5244            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
    5245
    5246        return column
    5247
    5248    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    5249        this = self._parse_field()
    5250        if (
    5251            not this
    5252            and self._match(TokenType.VALUES, advance=False)
    5253            and self.VALUES_FOLLOWED_BY_PAREN
    5254            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    5255        ):
    5256            this = self._parse_id_var()
    5257
    5258        if isinstance(this, exp.Identifier):
    5259            # We bubble up comments from the Identifier to the Column
    5260            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    5261
    5262        return this
    5263
    5264    def _parse_colon_as_variant_extract(
    5265        self, this: t.Optional[exp.Expression]
    5266    ) -> t.Optional[exp.Expression]:
    5267        casts = []
    5268        json_path = []
    5269        escape = None
    5270
    5271        while self._match(TokenType.COLON):
    5272            start_index = self._index
    5273
    5274            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
    5275            path = self._parse_column_ops(
    5276                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
    5277            )
    5278
    5279            # The cast :: operator has a lower precedence than the extraction operator :, so
    5280            # we rearrange the AST appropriately to avoid casting the JSON path
    5281            while isinstance(path, exp.Cast):
    5282                casts.append(path.to)
    5283                path = path.this
    5284
    5285            if casts:
    5286                dcolon_offset = next(
    5287                    i
    5288                    for i, t in enumerate(self._tokens[start_index:])
    5289                    if t.token_type == TokenType.DCOLON
    5290                )
    5291                end_token = self._tokens[start_index + dcolon_offset - 1]
    5292            else:
    5293                end_token = self._prev
    5294
    5295            if path:
    5296                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
    5297                # it'll roundtrip to a string literal in GET_PATH
    5298                if isinstance(path, exp.Identifier) and path.quoted:
    5299                    escape = True
    5300
    5301                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    5302
    5303        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
    5304        # Databricks transforms it back to the colon/dot notation
    5305        if json_path:
    5306            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
    5307
    5308            if json_path_expr:
    5309                json_path_expr.set("escape", escape)
    5310
    5311            this = self.expression(
    5312                exp.JSONExtract,
    5313                this=this,
    5314                expression=json_path_expr,
    5315                variant_extract=True,
    5316            )
    5317
    5318            while casts:
    5319                this = self.expression(exp.Cast, this=this, to=casts.pop())
    5320
    5321        return this
    5322
    5323    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
    5324        return self._parse_types()
    5325
    5326    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5327        this = self._parse_bracket(this)
    5328
    5329        while self._match_set(self.COLUMN_OPERATORS):
    5330            op_token = self._prev.token_type
    5331            op = self.COLUMN_OPERATORS.get(op_token)
    5332
    5333            if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
    5334                field = self._parse_dcolon()
    5335                if not field:
    5336                    self.raise_error("Expected type")
    5337            elif op and self._curr:
    5338                field = self._parse_column_reference() or self._parse_bracket()
    5339            else:
    5340                field = self._parse_field(any_token=True, anonymous_func=True)
    5341
    5342            if isinstance(field, (exp.Func, exp.Window)) and this:
    5343                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
    5344                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    5345                this = exp.replace_tree(
    5346                    this,
    5347                    lambda n: (
    5348                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    5349                        if n.table
    5350                        else n.this
    5351                    )
    5352                    if isinstance(n, exp.Column)
    5353                    else n,
    5354                )
    5355
    5356            if op:
    5357                this = op(self, this, field)
    5358            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    5359                this = self.expression(
    5360                    exp.Column,
    5361                    comments=this.comments,
    5362                    this=field,
    5363                    table=this.this,
    5364                    db=this.args.get("table"),
    5365                    catalog=this.args.get("db"),
    5366                )
    5367            elif isinstance(field, exp.Window):
    5368                # Move the exp.Dot's to the window's function
    5369                window_func = self.expression(exp.Dot, this=this, expression=field.this)
    5370                field.set("this", window_func)
    5371                this = field
    5372            else:
    5373                this = self.expression(exp.Dot, this=this, expression=field)
    5374
    5375            if field and field.comments:
    5376                t.cast(exp.Expression, this).add_comments(field.pop_comments())
    5377
    5378            this = self._parse_bracket(this)
    5379
    5380        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
    5381
    5382    def _parse_primary(self) -> t.Optional[exp.Expression]:
    5383        if self._match_set(self.PRIMARY_PARSERS):
    5384            token_type = self._prev.token_type
    5385            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    5386
    5387            if token_type == TokenType.STRING:
    5388                expressions = [primary]
    5389                while self._match(TokenType.STRING):
    5390                    expressions.append(exp.Literal.string(self._prev.text))
    5391
    5392                if len(expressions) > 1:
    5393                    return self.expression(exp.Concat, expressions=expressions)
    5394
    5395            return primary
    5396
    5397        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    5398            return exp.Literal.number(f"0.{self._prev.text}")
    5399
    5400        if self._match(TokenType.L_PAREN):
    5401            comments = self._prev_comments
    5402            query = self._parse_select()
    5403
    5404            if query:
    5405                expressions = [query]
    5406            else:
    5407                expressions = self._parse_expressions()
    5408
    5409            this = self._parse_query_modifiers(seq_get(expressions, 0))
    5410
    5411            if not this and self._match(TokenType.R_PAREN, advance=False):
    5412                this = self.expression(exp.Tuple)
    5413            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    5414                this = self._parse_subquery(this=this, parse_alias=False)
    5415            elif isinstance(this, exp.Subquery):
    5416                this = self._parse_subquery(
    5417                    this=self._parse_set_operations(this), parse_alias=False
    5418                )
    5419            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    5420                this = self.expression(exp.Tuple, expressions=expressions)
    5421            else:
    5422                this = self.expression(exp.Paren, this=this)
    5423
    5424            if this:
    5425                this.add_comments(comments)
    5426
    5427            self._match_r_paren(expression=this)
    5428            return this
    5429
    5430        return None
    5431
    5432    def _parse_field(
    5433        self,
    5434        any_token: bool = False,
    5435        tokens: t.Optional[t.Collection[TokenType]] = None,
    5436        anonymous_func: bool = False,
    5437    ) -> t.Optional[exp.Expression]:
    5438        if anonymous_func:
    5439            field = (
    5440                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    5441                or self._parse_primary()
    5442            )
    5443        else:
    5444            field = self._parse_primary() or self._parse_function(
    5445                anonymous=anonymous_func, any_token=any_token
    5446            )
    5447        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    5448
    5449    def _parse_function(
    5450        self,
    5451        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5452        anonymous: bool = False,
    5453        optional_parens: bool = True,
    5454        any_token: bool = False,
    5455    ) -> t.Optional[exp.Expression]:
    5456        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    5457        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    5458        fn_syntax = False
    5459        if (
    5460            self._match(TokenType.L_BRACE, advance=False)
    5461            and self._next
    5462            and self._next.text.upper() == "FN"
    5463        ):
    5464            self._advance(2)
    5465            fn_syntax = True
    5466
    5467        func = self._parse_function_call(
    5468            functions=functions,
    5469            anonymous=anonymous,
    5470            optional_parens=optional_parens,
    5471            any_token=any_token,
    5472        )
    5473
    5474        if fn_syntax:
    5475            self._match(TokenType.R_BRACE)
    5476
    5477        return func
    5478
    5479    def _parse_function_call(
    5480        self,
    5481        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5482        anonymous: bool = False,
    5483        optional_parens: bool = True,
    5484        any_token: bool = False,
    5485    ) -> t.Optional[exp.Expression]:
    5486        if not self._curr:
    5487            return None
    5488
    5489        comments = self._curr.comments
    5490        token_type = self._curr.token_type
    5491        this = self._curr.text
    5492        upper = this.upper()
    5493
    5494        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    5495        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    5496            self._advance()
    5497            return self._parse_window(parser(self))
    5498
    5499        if not self._next or self._next.token_type != TokenType.L_PAREN:
    5500            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    5501                self._advance()
    5502                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    5503
    5504            return None
    5505
    5506        if any_token:
    5507            if token_type in self.RESERVED_TOKENS:
    5508                return None
    5509        elif token_type not in self.FUNC_TOKENS:
    5510            return None
    5511
    5512        self._advance(2)
    5513
    5514        parser = self.FUNCTION_PARSERS.get(upper)
    5515        if parser and not anonymous:
    5516            this = parser(self)
    5517        else:
    5518            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    5519
    5520            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    5521                this = self.expression(
    5522                    subquery_predicate, comments=comments, this=self._parse_select()
    5523                )
    5524                self._match_r_paren()
    5525                return this
    5526
    5527            if functions is None:
    5528                functions = self.FUNCTIONS
    5529
    5530            function = functions.get(upper)
    5531            known_function = function and not anonymous
    5532
    5533            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    5534            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    5535
    5536            post_func_comments = self._curr and self._curr.comments
    5537            if known_function and post_func_comments:
    5538                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
    5539                # call we'll construct it as exp.Anonymous, even if it's "known"
    5540                if any(
    5541                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
    5542                    for comment in post_func_comments
    5543                ):
    5544                    known_function = False
    5545
    5546            if alias and known_function:
    5547                args = self._kv_to_prop_eq(args)
    5548
    5549            if known_function:
    5550                func_builder = t.cast(t.Callable, function)
    5551
    5552                if "dialect" in func_builder.__code__.co_varnames:
    5553                    func = func_builder(args, dialect=self.dialect)
    5554                else:
    5555                    func = func_builder(args)
    5556
    5557                func = self.validate_expression(func, args)
    5558                if self.dialect.PRESERVE_ORIGINAL_NAMES:
    5559                    func.meta["name"] = this
    5560
    5561                this = func
    5562            else:
    5563                if token_type == TokenType.IDENTIFIER:
    5564                    this = exp.Identifier(this=this, quoted=True)
    5565                this = self.expression(exp.Anonymous, this=this, expressions=args)
    5566
    5567        if isinstance(this, exp.Expression):
    5568            this.add_comments(comments)
    5569
    5570        self._match_r_paren(this)
    5571        return self._parse_window(this)
    5572
    5573    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
    5574        return expression
    5575
    5576    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    5577        transformed = []
    5578
    5579        for index, e in enumerate(expressions):
    5580            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    5581                if isinstance(e, exp.Alias):
    5582                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    5583
    5584                if not isinstance(e, exp.PropertyEQ):
    5585                    e = self.expression(
    5586                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    5587                    )
    5588
    5589                if isinstance(e.this, exp.Column):
    5590                    e.this.replace(e.this.this)
    5591            else:
    5592                e = self._to_prop_eq(e, index)
    5593
    5594            transformed.append(e)
    5595
    5596        return transformed
    5597
    5598    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
    5599        return self._parse_statement()
    5600
    5601    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    5602        return self._parse_column_def(this=self._parse_id_var(), computed_column=False)
    5603
    5604    def _parse_user_defined_function(
    5605        self, kind: t.Optional[TokenType] = None
    5606    ) -> t.Optional[exp.Expression]:
    5607        this = self._parse_id_var()
    5608
    5609        while self._match(TokenType.DOT):
    5610            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    5611
    5612        if not self._match(TokenType.L_PAREN):
    5613            return this
    5614
    5615        expressions = self._parse_csv(self._parse_function_parameter)
    5616        self._match_r_paren()
    5617        return self.expression(
    5618            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    5619        )
    5620
    5621    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    5622        literal = self._parse_primary()
    5623        if literal:
    5624            return self.expression(exp.Introducer, this=token.text, expression=literal)
    5625
    5626        return self.expression(exp.Identifier, this=token.text)
    5627
    5628    def _parse_session_parameter(self) -> exp.SessionParameter:
    5629        kind = None
    5630        this = self._parse_id_var() or self._parse_primary()
    5631
    5632        if this and self._match(TokenType.DOT):
    5633            kind = this.name
    5634            this = self._parse_var() or self._parse_primary()
    5635
    5636        return self.expression(exp.SessionParameter, this=this, kind=kind)
    5637
    5638    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    5639        return self._parse_id_var()
    5640
    5641    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5642        index = self._index
    5643
    5644        if self._match(TokenType.L_PAREN):
    5645            expressions = t.cast(
    5646                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    5647            )
    5648
    5649            if not self._match(TokenType.R_PAREN):
    5650                self._retreat(index)
    5651        else:
    5652            expressions = [self._parse_lambda_arg()]
    5653
    5654        if self._match_set(self.LAMBDAS):
    5655            return self.LAMBDAS[self._prev.token_type](self, expressions)
    5656
    5657        self._retreat(index)
    5658
    5659        this: t.Optional[exp.Expression]
    5660
    5661        if self._match(TokenType.DISTINCT):
    5662            this = self.expression(
    5663                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    5664            )
    5665        else:
    5666            this = self._parse_select_or_expression(alias=alias)
    5667
    5668        return self._parse_limit(
    5669            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    5670        )
    5671
    5672    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5673        index = self._index
    5674        if not self._match(TokenType.L_PAREN):
    5675            return this
    5676
    5677        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    5678        # expr can be of both types
    5679        if self._match_set(self.SELECT_START_TOKENS):
    5680            self._retreat(index)
    5681            return this
    5682        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    5683        self._match_r_paren()
    5684        return self.expression(exp.Schema, this=this, expressions=args)
    5685
    5686    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    5687        return self._parse_column_def(self._parse_field(any_token=True))
    5688
    5689    def _parse_column_def(
    5690        self, this: t.Optional[exp.Expression], computed_column: bool = True
    5691    ) -> t.Optional[exp.Expression]:
    5692        # column defs are not really columns, they're identifiers
    5693        if isinstance(this, exp.Column):
    5694            this = this.this
    5695
    5696        if not computed_column:
    5697            self._match(TokenType.ALIAS)
    5698
    5699        kind = self._parse_types(schema=True)
    5700
    5701        if self._match_text_seq("FOR", "ORDINALITY"):
    5702            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    5703
    5704        constraints: t.List[exp.Expression] = []
    5705
    5706        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    5707            ("ALIAS", "MATERIALIZED")
    5708        ):
    5709            persisted = self._prev.text.upper() == "MATERIALIZED"
    5710            constraint_kind = exp.ComputedColumnConstraint(
    5711                this=self._parse_assignment(),
    5712                persisted=persisted or self._match_text_seq("PERSISTED"),
    5713                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    5714            )
    5715            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
    5716        elif (
    5717            kind
    5718            and self._match(TokenType.ALIAS, advance=False)
    5719            and (
    5720                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
    5721                or (self._next and self._next.token_type == TokenType.L_PAREN)
    5722            )
    5723        ):
    5724            self._advance()
    5725            constraints.append(
    5726                self.expression(
    5727                    exp.ColumnConstraint,
    5728                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
    5729                )
    5730            )
    5731
    5732        while True:
    5733            constraint = self._parse_column_constraint()
    5734            if not constraint:
    5735                break
    5736            constraints.append(constraint)
    5737
    5738        if not kind and not constraints:
    5739            return this
    5740
    5741        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    5742
    5743    def _parse_auto_increment(
    5744        self,
    5745    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    5746        start = None
    5747        increment = None
    5748
    5749        if self._match(TokenType.L_PAREN, advance=False):
    5750            args = self._parse_wrapped_csv(self._parse_bitwise)
    5751            start = seq_get(args, 0)
    5752            increment = seq_get(args, 1)
    5753        elif self._match_text_seq("START"):
    5754            start = self._parse_bitwise()
    5755            self._match_text_seq("INCREMENT")
    5756            increment = self._parse_bitwise()
    5757
    5758        if start and increment:
    5759            return exp.GeneratedAsIdentityColumnConstraint(
    5760                start=start, increment=increment, this=False
    5761            )
    5762
    5763        return exp.AutoIncrementColumnConstraint()
    5764
    5765    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    5766        if not self._match_text_seq("REFRESH"):
    5767            self._retreat(self._index - 1)
    5768            return None
    5769        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    5770
    5771    def _parse_compress(self) -> exp.CompressColumnConstraint:
    5772        if self._match(TokenType.L_PAREN, advance=False):
    5773            return self.expression(
    5774                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    5775            )
    5776
    5777        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    5778
    5779    def _parse_generated_as_identity(
    5780        self,
    5781    ) -> (
    5782        exp.GeneratedAsIdentityColumnConstraint
    5783        | exp.ComputedColumnConstraint
    5784        | exp.GeneratedAsRowColumnConstraint
    5785    ):
    5786        if self._match_text_seq("BY", "DEFAULT"):
    5787            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    5788            this = self.expression(
    5789                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    5790            )
    5791        else:
    5792            self._match_text_seq("ALWAYS")
    5793            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    5794
    5795        self._match(TokenType.ALIAS)
    5796
    5797        if self._match_text_seq("ROW"):
    5798            start = self._match_text_seq("START")
    5799            if not start:
    5800                self._match(TokenType.END)
    5801            hidden = self._match_text_seq("HIDDEN")
    5802            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    5803
    5804        identity = self._match_text_seq("IDENTITY")
    5805
    5806        if self._match(TokenType.L_PAREN):
    5807            if self._match(TokenType.START_WITH):
    5808                this.set("start", self._parse_bitwise())
    5809            if self._match_text_seq("INCREMENT", "BY"):
    5810                this.set("increment", self._parse_bitwise())
    5811            if self._match_text_seq("MINVALUE"):
    5812                this.set("minvalue", self._parse_bitwise())
    5813            if self._match_text_seq("MAXVALUE"):
    5814                this.set("maxvalue", self._parse_bitwise())
    5815
    5816            if self._match_text_seq("CYCLE"):
    5817                this.set("cycle", True)
    5818            elif self._match_text_seq("NO", "CYCLE"):
    5819                this.set("cycle", False)
    5820
    5821            if not identity:
    5822                this.set("expression", self._parse_range())
    5823            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5824                args = self._parse_csv(self._parse_bitwise)
    5825                this.set("start", seq_get(args, 0))
    5826                this.set("increment", seq_get(args, 1))
    5827
    5828            self._match_r_paren()
    5829
    5830        return this
    5831
    5832    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5833        self._match_text_seq("LENGTH")
    5834        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5835
    5836    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5837        if self._match_text_seq("NULL"):
    5838            return self.expression(exp.NotNullColumnConstraint)
    5839        if self._match_text_seq("CASESPECIFIC"):
    5840            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5841        if self._match_text_seq("FOR", "REPLICATION"):
    5842            return self.expression(exp.NotForReplicationColumnConstraint)
    5843
    5844        # Unconsume the `NOT` token
    5845        self._retreat(self._index - 1)
    5846        return None
    5847
    5848    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5849        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
    5850
    5851        procedure_option_follows = (
    5852            self._match(TokenType.WITH, advance=False)
    5853            and self._next
    5854            and self._next.text.upper() in self.PROCEDURE_OPTIONS
    5855        )
    5856
    5857        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
    5858            return self.expression(
    5859                exp.ColumnConstraint,
    5860                this=this,
    5861                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5862            )
    5863
    5864        return this
    5865
    5866    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5867        if not self._match(TokenType.CONSTRAINT):
    5868            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5869
    5870        return self.expression(
    5871            exp.Constraint,
    5872            this=self._parse_id_var(),
    5873            expressions=self._parse_unnamed_constraints(),
    5874        )
    5875
    5876    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5877        constraints = []
    5878        while True:
    5879            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5880            if not constraint:
    5881                break
    5882            constraints.append(constraint)
    5883
    5884        return constraints
    5885
    5886    def _parse_unnamed_constraint(
    5887        self, constraints: t.Optional[t.Collection[str]] = None
    5888    ) -> t.Optional[exp.Expression]:
    5889        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    5890            constraints or self.CONSTRAINT_PARSERS
    5891        ):
    5892            return None
    5893
    5894        constraint = self._prev.text.upper()
    5895        if constraint not in self.CONSTRAINT_PARSERS:
    5896            self.raise_error(f"No parser found for schema constraint {constraint}.")
    5897
    5898        return self.CONSTRAINT_PARSERS[constraint](self)
    5899
    5900    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
    5901        return self._parse_id_var(any_token=False)
    5902
    5903    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    5904        self._match_text_seq("KEY")
    5905        return self.expression(
    5906            exp.UniqueColumnConstraint,
    5907            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
    5908            this=self._parse_schema(self._parse_unique_key()),
    5909            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    5910            on_conflict=self._parse_on_conflict(),
    5911        )
    5912
    5913    def _parse_key_constraint_options(self) -> t.List[str]:
    5914        options = []
    5915        while True:
    5916            if not self._curr:
    5917                break
    5918
    5919            if self._match(TokenType.ON):
    5920                action = None
    5921                on = self._advance_any() and self._prev.text
    5922
    5923                if self._match_text_seq("NO", "ACTION"):
    5924                    action = "NO ACTION"
    5925                elif self._match_text_seq("CASCADE"):
    5926                    action = "CASCADE"
    5927                elif self._match_text_seq("RESTRICT"):
    5928                    action = "RESTRICT"
    5929                elif self._match_pair(TokenType.SET, TokenType.NULL):
    5930                    action = "SET NULL"
    5931                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5932                    action = "SET DEFAULT"
    5933                else:
    5934                    self.raise_error("Invalid key constraint")
    5935
    5936                options.append(f"ON {on} {action}")
    5937            else:
    5938                var = self._parse_var_from_options(
    5939                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
    5940                )
    5941                if not var:
    5942                    break
    5943                options.append(var.name)
    5944
    5945        return options
    5946
    5947    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    5948        if match and not self._match(TokenType.REFERENCES):
    5949            return None
    5950
    5951        expressions = None
    5952        this = self._parse_table(schema=True)
    5953        options = self._parse_key_constraint_options()
    5954        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    5955
    5956    def _parse_foreign_key(self) -> exp.ForeignKey:
    5957        expressions = self._parse_wrapped_id_vars()
    5958        reference = self._parse_references()
    5959        options = {}
    5960
    5961        while self._match(TokenType.ON):
    5962            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    5963                self.raise_error("Expected DELETE or UPDATE")
    5964
    5965            kind = self._prev.text.lower()
    5966
    5967            if self._match_text_seq("NO", "ACTION"):
    5968                action = "NO ACTION"
    5969            elif self._match(TokenType.SET):
    5970                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    5971                action = "SET " + self._prev.text.upper()
    5972            else:
    5973                self._advance()
    5974                action = self._prev.text.upper()
    5975
    5976            options[kind] = action
    5977
    5978        return self.expression(
    5979            exp.ForeignKey,
    5980            expressions=expressions,
    5981            reference=reference,
    5982            **options,  # type: ignore
    5983        )
    5984
    5985    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    5986        return self._parse_ordered() or self._parse_field()
    5987
    5988    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    5989        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    5990            self._retreat(self._index - 1)
    5991            return None
    5992
    5993        id_vars = self._parse_wrapped_id_vars()
    5994        return self.expression(
    5995            exp.PeriodForSystemTimeConstraint,
    5996            this=seq_get(id_vars, 0),
    5997            expression=seq_get(id_vars, 1),
    5998        )
    5999
    6000    def _parse_primary_key(
    6001        self, wrapped_optional: bool = False, in_props: bool = False
    6002    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    6003        desc = (
    6004            self._match_set((TokenType.ASC, TokenType.DESC))
    6005            and self._prev.token_type == TokenType.DESC
    6006        )
    6007
    6008        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    6009            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    6010
    6011        expressions = self._parse_wrapped_csv(
    6012            self._parse_primary_key_part, optional=wrapped_optional
    6013        )
    6014        options = self._parse_key_constraint_options()
    6015        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    6016
    6017    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    6018        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    6019
    6020    def _parse_odbc_datetime_literal(self) -> exp.Expression:
    6021        """
    6022        Parses a datetime column in ODBC format. We parse the column into the corresponding
    6023        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
    6024        same as we did for `DATE('yyyy-mm-dd')`.
    6025
    6026        Reference:
    6027        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
    6028        """
    6029        self._match(TokenType.VAR)
    6030        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
    6031        expression = self.expression(exp_class=exp_class, this=self._parse_string())
    6032        if not self._match(TokenType.R_BRACE):
    6033            self.raise_error("Expected }")
    6034        return expression
    6035
    6036    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    6037        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    6038            return this
    6039
    6040        bracket_kind = self._prev.token_type
    6041        if (
    6042            bracket_kind == TokenType.L_BRACE
    6043            and self._curr
    6044            and self._curr.token_type == TokenType.VAR
    6045            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
    6046        ):
    6047            return self._parse_odbc_datetime_literal()
    6048
    6049        expressions = self._parse_csv(
    6050            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    6051        )
    6052
    6053        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    6054            self.raise_error("Expected ]")
    6055        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    6056            self.raise_error("Expected }")
    6057
    6058        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    6059        if bracket_kind == TokenType.L_BRACE:
    6060            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    6061        elif not this:
    6062            this = build_array_constructor(
    6063                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
    6064            )
    6065        else:
    6066            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    6067            if constructor_type:
    6068                return build_array_constructor(
    6069                    constructor_type,
    6070                    args=expressions,
    6071                    bracket_kind=bracket_kind,
    6072                    dialect=self.dialect,
    6073                )
    6074
    6075            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    6076            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    6077
    6078        self._add_comments(this)
    6079        return self._parse_bracket(this)
    6080
    6081    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6082        if self._match(TokenType.COLON):
    6083            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    6084        return this
    6085
    6086    def _parse_case(self) -> t.Optional[exp.Expression]:
    6087        ifs = []
    6088        default = None
    6089
    6090        comments = self._prev_comments
    6091        expression = self._parse_assignment()
    6092
    6093        while self._match(TokenType.WHEN):
    6094            this = self._parse_assignment()
    6095            self._match(TokenType.THEN)
    6096            then = self._parse_assignment()
    6097            ifs.append(self.expression(exp.If, this=this, true=then))
    6098
    6099        if self._match(TokenType.ELSE):
    6100            default = self._parse_assignment()
    6101
    6102        if not self._match(TokenType.END):
    6103            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    6104                default = exp.column("interval")
    6105            else:
    6106                self.raise_error("Expected END after CASE", self._prev)
    6107
    6108        return self.expression(
    6109            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    6110        )
    6111
    6112    def _parse_if(self) -> t.Optional[exp.Expression]:
    6113        if self._match(TokenType.L_PAREN):
    6114            args = self._parse_csv(self._parse_assignment)
    6115            this = self.validate_expression(exp.If.from_arg_list(args), args)
    6116            self._match_r_paren()
    6117        else:
    6118            index = self._index - 1
    6119
    6120            if self.NO_PAREN_IF_COMMANDS and index == 0:
    6121                return self._parse_as_command(self._prev)
    6122
    6123            condition = self._parse_assignment()
    6124
    6125            if not condition:
    6126                self._retreat(index)
    6127                return None
    6128
    6129            self._match(TokenType.THEN)
    6130            true = self._parse_assignment()
    6131            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    6132            self._match(TokenType.END)
    6133            this = self.expression(exp.If, this=condition, true=true, false=false)
    6134
    6135        return this
    6136
    6137    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    6138        if not self._match_text_seq("VALUE", "FOR"):
    6139            self._retreat(self._index - 1)
    6140            return None
    6141
    6142        return self.expression(
    6143            exp.NextValueFor,
    6144            this=self._parse_column(),
    6145            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    6146        )
    6147
    6148    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
    6149        this = self._parse_function() or self._parse_var_or_string(upper=True)
    6150
    6151        if self._match(TokenType.FROM):
    6152            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6153
    6154        if not self._match(TokenType.COMMA):
    6155            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    6156
    6157        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6158
    6159    def _parse_gap_fill(self) -> exp.GapFill:
    6160        self._match(TokenType.TABLE)
    6161        this = self._parse_table()
    6162
    6163        self._match(TokenType.COMMA)
    6164        args = [this, *self._parse_csv(self._parse_lambda)]
    6165
    6166        gap_fill = exp.GapFill.from_arg_list(args)
    6167        return self.validate_expression(gap_fill, args)
    6168
    6169    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    6170        this = self._parse_assignment()
    6171
    6172        if not self._match(TokenType.ALIAS):
    6173            if self._match(TokenType.COMMA):
    6174                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    6175
    6176            self.raise_error("Expected AS after CAST")
    6177
    6178        fmt = None
    6179        to = self._parse_types()
    6180
    6181        default = self._match(TokenType.DEFAULT)
    6182        if default:
    6183            default = self._parse_bitwise()
    6184            self._match_text_seq("ON", "CONVERSION", "ERROR")
    6185
    6186        if self._match_set((TokenType.FORMAT, TokenType.COMMA)):
    6187            fmt_string = self._parse_string()
    6188            fmt = self._parse_at_time_zone(fmt_string)
    6189
    6190            if not to:
    6191                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    6192            if to.this in exp.DataType.TEMPORAL_TYPES:
    6193                this = self.expression(
    6194                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    6195                    this=this,
    6196                    format=exp.Literal.string(
    6197                        format_time(
    6198                            fmt_string.this if fmt_string else "",
    6199                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    6200                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    6201                        )
    6202                    ),
    6203                    safe=safe,
    6204                )
    6205
    6206                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    6207                    this.set("zone", fmt.args["zone"])
    6208                return this
    6209        elif not to:
    6210            self.raise_error("Expected TYPE after CAST")
    6211        elif isinstance(to, exp.Identifier):
    6212            to = exp.DataType.build(to.name, udt=True)
    6213        elif to.this == exp.DataType.Type.CHAR:
    6214            if self._match(TokenType.CHARACTER_SET):
    6215                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    6216
    6217        return self.expression(
    6218            exp.Cast if strict else exp.TryCast,
    6219            this=this,
    6220            to=to,
    6221            format=fmt,
    6222            safe=safe,
    6223            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    6224            default=default,
    6225        )
    6226
    6227    def _parse_string_agg(self) -> exp.GroupConcat:
    6228        if self._match(TokenType.DISTINCT):
    6229            args: t.List[t.Optional[exp.Expression]] = [
    6230                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    6231            ]
    6232            if self._match(TokenType.COMMA):
    6233                args.extend(self._parse_csv(self._parse_assignment))
    6234        else:
    6235            args = self._parse_csv(self._parse_assignment)  # type: ignore
    6236
    6237        if self._match_text_seq("ON", "OVERFLOW"):
    6238            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
    6239            if self._match_text_seq("ERROR"):
    6240                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
    6241            else:
    6242                self._match_text_seq("TRUNCATE")
    6243                on_overflow = self.expression(
    6244                    exp.OverflowTruncateBehavior,
    6245                    this=self._parse_string(),
    6246                    with_count=(
    6247                        self._match_text_seq("WITH", "COUNT")
    6248                        or not self._match_text_seq("WITHOUT", "COUNT")
    6249                    ),
    6250                )
    6251        else:
    6252            on_overflow = None
    6253
    6254        index = self._index
    6255        if not self._match(TokenType.R_PAREN) and args:
    6256            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    6257            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    6258            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    6259            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    6260
    6261        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    6262        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    6263        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    6264        if not self._match_text_seq("WITHIN", "GROUP"):
    6265            self._retreat(index)
    6266            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    6267
    6268        # The corresponding match_r_paren will be called in parse_function (caller)
    6269        self._match_l_paren()
    6270
    6271        return self.expression(
    6272            exp.GroupConcat,
    6273            this=self._parse_order(this=seq_get(args, 0)),
    6274            separator=seq_get(args, 1),
    6275            on_overflow=on_overflow,
    6276        )
    6277
    6278    def _parse_convert(
    6279        self, strict: bool, safe: t.Optional[bool] = None
    6280    ) -> t.Optional[exp.Expression]:
    6281        this = self._parse_bitwise()
    6282
    6283        if self._match(TokenType.USING):
    6284            to: t.Optional[exp.Expression] = self.expression(
    6285                exp.CharacterSet, this=self._parse_var()
    6286            )
    6287        elif self._match(TokenType.COMMA):
    6288            to = self._parse_types()
    6289        else:
    6290            to = None
    6291
    6292        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    6293
    6294    def _parse_xml_table(self) -> exp.XMLTable:
    6295        namespaces = None
    6296        passing = None
    6297        columns = None
    6298
    6299        if self._match_text_seq("XMLNAMESPACES", "("):
    6300            namespaces = self._parse_xml_namespace()
    6301            self._match_text_seq(")", ",")
    6302
    6303        this = self._parse_string()
    6304
    6305        if self._match_text_seq("PASSING"):
    6306            # The BY VALUE keywords are optional and are provided for semantic clarity
    6307            self._match_text_seq("BY", "VALUE")
    6308            passing = self._parse_csv(self._parse_column)
    6309
    6310        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
    6311
    6312        if self._match_text_seq("COLUMNS"):
    6313            columns = self._parse_csv(self._parse_field_def)
    6314
    6315        return self.expression(
    6316            exp.XMLTable,
    6317            this=this,
    6318            namespaces=namespaces,
    6319            passing=passing,
    6320            columns=columns,
    6321            by_ref=by_ref,
    6322        )
    6323
    6324    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
    6325        namespaces = []
    6326
    6327        while True:
    6328            if self._match(TokenType.DEFAULT):
    6329                uri = self._parse_string()
    6330            else:
    6331                uri = self._parse_alias(self._parse_string())
    6332            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
    6333            if not self._match(TokenType.COMMA):
    6334                break
    6335
    6336        return namespaces
    6337
    6338    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    6339        """
    6340        There are generally two variants of the DECODE function:
    6341
    6342        - DECODE(bin, charset)
    6343        - DECODE(expression, search, result [, search, result] ... [, default])
    6344
    6345        The second variant will always be parsed into a CASE expression. Note that NULL
    6346        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    6347        instead of relying on pattern matching.
    6348        """
    6349        args = self._parse_csv(self._parse_assignment)
    6350
    6351        if len(args) < 3:
    6352            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    6353
    6354        expression, *expressions = args
    6355        if not expression:
    6356            return None
    6357
    6358        ifs = []
    6359        for search, result in zip(expressions[::2], expressions[1::2]):
    6360            if not search or not result:
    6361                return None
    6362
    6363            if isinstance(search, exp.Literal):
    6364                ifs.append(
    6365                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    6366                )
    6367            elif isinstance(search, exp.Null):
    6368                ifs.append(
    6369                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    6370                )
    6371            else:
    6372                cond = exp.or_(
    6373                    exp.EQ(this=expression.copy(), expression=search),
    6374                    exp.and_(
    6375                        exp.Is(this=expression.copy(), expression=exp.Null()),
    6376                        exp.Is(this=search.copy(), expression=exp.Null()),
    6377                        copy=False,
    6378                    ),
    6379                    copy=False,
    6380                )
    6381                ifs.append(exp.If(this=cond, true=result))
    6382
    6383        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    6384
    6385    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    6386        self._match_text_seq("KEY")
    6387        key = self._parse_column()
    6388        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    6389        self._match_text_seq("VALUE")
    6390        value = self._parse_bitwise()
    6391
    6392        if not key and not value:
    6393            return None
    6394        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    6395
    6396    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6397        if not this or not self._match_text_seq("FORMAT", "JSON"):
    6398            return this
    6399
    6400        return self.expression(exp.FormatJson, this=this)
    6401
    6402    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
    6403        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
    6404        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
    6405            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6406            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6407        else:
    6408            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6409            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6410
    6411        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
    6412
    6413        if not empty and not error and not null:
    6414            return None
    6415
    6416        return self.expression(
    6417            exp.OnCondition,
    6418            empty=empty,
    6419            error=error,
    6420            null=null,
    6421        )
    6422
    6423    def _parse_on_handling(
    6424        self, on: str, *values: str
    6425    ) -> t.Optional[str] | t.Optional[exp.Expression]:
    6426        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
    6427        for value in values:
    6428            if self._match_text_seq(value, "ON", on):
    6429                return f"{value} ON {on}"
    6430
    6431        index = self._index
    6432        if self._match(TokenType.DEFAULT):
    6433            default_value = self._parse_bitwise()
    6434            if self._match_text_seq("ON", on):
    6435                return default_value
    6436
    6437            self._retreat(index)
    6438
    6439        return None
    6440
    6441    @t.overload
    6442    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    6443
    6444    @t.overload
    6445    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    6446
    6447    def _parse_json_object(self, agg=False):
    6448        star = self._parse_star()
    6449        expressions = (
    6450            [star]
    6451            if star
    6452            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    6453        )
    6454        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    6455
    6456        unique_keys = None
    6457        if self._match_text_seq("WITH", "UNIQUE"):
    6458            unique_keys = True
    6459        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    6460            unique_keys = False
    6461
    6462        self._match_text_seq("KEYS")
    6463
    6464        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    6465            self._parse_type()
    6466        )
    6467        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    6468
    6469        return self.expression(
    6470            exp.JSONObjectAgg if agg else exp.JSONObject,
    6471            expressions=expressions,
    6472            null_handling=null_handling,
    6473            unique_keys=unique_keys,
    6474            return_type=return_type,
    6475            encoding=encoding,
    6476        )
    6477
    6478    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    6479    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    6480        if not self._match_text_seq("NESTED"):
    6481            this = self._parse_id_var()
    6482            kind = self._parse_types(allow_identifiers=False)
    6483            nested = None
    6484        else:
    6485            this = None
    6486            kind = None
    6487            nested = True
    6488
    6489        path = self._match_text_seq("PATH") and self._parse_string()
    6490        nested_schema = nested and self._parse_json_schema()
    6491
    6492        return self.expression(
    6493            exp.JSONColumnDef,
    6494            this=this,
    6495            kind=kind,
    6496            path=path,
    6497            nested_schema=nested_schema,
    6498        )
    6499
    6500    def _parse_json_schema(self) -> exp.JSONSchema:
    6501        self._match_text_seq("COLUMNS")
    6502        return self.expression(
    6503            exp.JSONSchema,
    6504            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    6505        )
    6506
    6507    def _parse_json_table(self) -> exp.JSONTable:
    6508        this = self._parse_format_json(self._parse_bitwise())
    6509        path = self._match(TokenType.COMMA) and self._parse_string()
    6510        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    6511        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    6512        schema = self._parse_json_schema()
    6513
    6514        return exp.JSONTable(
    6515            this=this,
    6516            schema=schema,
    6517            path=path,
    6518            error_handling=error_handling,
    6519            empty_handling=empty_handling,
    6520        )
    6521
    6522    def _parse_match_against(self) -> exp.MatchAgainst:
    6523        expressions = self._parse_csv(self._parse_column)
    6524
    6525        self._match_text_seq(")", "AGAINST", "(")
    6526
    6527        this = self._parse_string()
    6528
    6529        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    6530            modifier = "IN NATURAL LANGUAGE MODE"
    6531            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6532                modifier = f"{modifier} WITH QUERY EXPANSION"
    6533        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    6534            modifier = "IN BOOLEAN MODE"
    6535        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6536            modifier = "WITH QUERY EXPANSION"
    6537        else:
    6538            modifier = None
    6539
    6540        return self.expression(
    6541            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    6542        )
    6543
    6544    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    6545    def _parse_open_json(self) -> exp.OpenJSON:
    6546        this = self._parse_bitwise()
    6547        path = self._match(TokenType.COMMA) and self._parse_string()
    6548
    6549        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    6550            this = self._parse_field(any_token=True)
    6551            kind = self._parse_types()
    6552            path = self._parse_string()
    6553            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    6554
    6555            return self.expression(
    6556                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    6557            )
    6558
    6559        expressions = None
    6560        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    6561            self._match_l_paren()
    6562            expressions = self._parse_csv(_parse_open_json_column_def)
    6563
    6564        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    6565
    6566    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    6567        args = self._parse_csv(self._parse_bitwise)
    6568
    6569        if self._match(TokenType.IN):
    6570            return self.expression(
    6571                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    6572            )
    6573
    6574        if haystack_first:
    6575            haystack = seq_get(args, 0)
    6576            needle = seq_get(args, 1)
    6577        else:
    6578            haystack = seq_get(args, 1)
    6579            needle = seq_get(args, 0)
    6580
    6581        return self.expression(
    6582            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    6583        )
    6584
    6585    def _parse_predict(self) -> exp.Predict:
    6586        self._match_text_seq("MODEL")
    6587        this = self._parse_table()
    6588
    6589        self._match(TokenType.COMMA)
    6590        self._match_text_seq("TABLE")
    6591
    6592        return self.expression(
    6593            exp.Predict,
    6594            this=this,
    6595            expression=self._parse_table(),
    6596            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    6597        )
    6598
    6599    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    6600        args = self._parse_csv(self._parse_table)
    6601        return exp.JoinHint(this=func_name.upper(), expressions=args)
    6602
    6603    def _parse_substring(self) -> exp.Substring:
    6604        # Postgres supports the form: substring(string [from int] [for int])
    6605        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    6606
    6607        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    6608
    6609        if self._match(TokenType.FROM):
    6610            args.append(self._parse_bitwise())
    6611        if self._match(TokenType.FOR):
    6612            if len(args) == 1:
    6613                args.append(exp.Literal.number(1))
    6614            args.append(self._parse_bitwise())
    6615
    6616        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    6617
    6618    def _parse_trim(self) -> exp.Trim:
    6619        # https://www.w3resource.com/sql/character-functions/trim.php
    6620        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    6621
    6622        position = None
    6623        collation = None
    6624        expression = None
    6625
    6626        if self._match_texts(self.TRIM_TYPES):
    6627            position = self._prev.text.upper()
    6628
    6629        this = self._parse_bitwise()
    6630        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    6631            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    6632            expression = self._parse_bitwise()
    6633
    6634            if invert_order:
    6635                this, expression = expression, this
    6636
    6637        if self._match(TokenType.COLLATE):
    6638            collation = self._parse_bitwise()
    6639
    6640        return self.expression(
    6641            exp.Trim, this=this, position=position, expression=expression, collation=collation
    6642        )
    6643
    6644    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    6645        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    6646
    6647    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    6648        return self._parse_window(self._parse_id_var(), alias=True)
    6649
    6650    def _parse_respect_or_ignore_nulls(
    6651        self, this: t.Optional[exp.Expression]
    6652    ) -> t.Optional[exp.Expression]:
    6653        if self._match_text_seq("IGNORE", "NULLS"):
    6654            return self.expression(exp.IgnoreNulls, this=this)
    6655        if self._match_text_seq("RESPECT", "NULLS"):
    6656            return self.expression(exp.RespectNulls, this=this)
    6657        return this
    6658
    6659    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6660        if self._match(TokenType.HAVING):
    6661            self._match_texts(("MAX", "MIN"))
    6662            max = self._prev.text.upper() != "MIN"
    6663            return self.expression(
    6664                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    6665            )
    6666
    6667        return this
    6668
    6669    def _parse_window(
    6670        self, this: t.Optional[exp.Expression], alias: bool = False
    6671    ) -> t.Optional[exp.Expression]:
    6672        func = this
    6673        comments = func.comments if isinstance(func, exp.Expression) else None
    6674
    6675        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    6676        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    6677        if self._match_text_seq("WITHIN", "GROUP"):
    6678            order = self._parse_wrapped(self._parse_order)
    6679            this = self.expression(exp.WithinGroup, this=this, expression=order)
    6680
    6681        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    6682            self._match(TokenType.WHERE)
    6683            this = self.expression(
    6684                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    6685            )
    6686            self._match_r_paren()
    6687
    6688        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    6689        # Some dialects choose to implement and some do not.
    6690        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    6691
    6692        # There is some code above in _parse_lambda that handles
    6693        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    6694
    6695        # The below changes handle
    6696        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    6697
    6698        # Oracle allows both formats
    6699        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    6700        #   and Snowflake chose to do the same for familiarity
    6701        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    6702        if isinstance(this, exp.AggFunc):
    6703            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    6704
    6705            if ignore_respect and ignore_respect is not this:
    6706                ignore_respect.replace(ignore_respect.this)
    6707                this = self.expression(ignore_respect.__class__, this=this)
    6708
    6709        this = self._parse_respect_or_ignore_nulls(this)
    6710
    6711        # bigquery select from window x AS (partition by ...)
    6712        if alias:
    6713            over = None
    6714            self._match(TokenType.ALIAS)
    6715        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    6716            return this
    6717        else:
    6718            over = self._prev.text.upper()
    6719
    6720        if comments and isinstance(func, exp.Expression):
    6721            func.pop_comments()
    6722
    6723        if not self._match(TokenType.L_PAREN):
    6724            return self.expression(
    6725                exp.Window,
    6726                comments=comments,
    6727                this=this,
    6728                alias=self._parse_id_var(False),
    6729                over=over,
    6730            )
    6731
    6732        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    6733
    6734        first = self._match(TokenType.FIRST)
    6735        if self._match_text_seq("LAST"):
    6736            first = False
    6737
    6738        partition, order = self._parse_partition_and_order()
    6739        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    6740
    6741        if kind:
    6742            self._match(TokenType.BETWEEN)
    6743            start = self._parse_window_spec()
    6744            self._match(TokenType.AND)
    6745            end = self._parse_window_spec()
    6746
    6747            spec = self.expression(
    6748                exp.WindowSpec,
    6749                kind=kind,
    6750                start=start["value"],
    6751                start_side=start["side"],
    6752                end=end["value"],
    6753                end_side=end["side"],
    6754            )
    6755        else:
    6756            spec = None
    6757
    6758        self._match_r_paren()
    6759
    6760        window = self.expression(
    6761            exp.Window,
    6762            comments=comments,
    6763            this=this,
    6764            partition_by=partition,
    6765            order=order,
    6766            spec=spec,
    6767            alias=window_alias,
    6768            over=over,
    6769            first=first,
    6770        )
    6771
    6772        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    6773        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    6774            return self._parse_window(window, alias=alias)
    6775
    6776        return window
    6777
    6778    def _parse_partition_and_order(
    6779        self,
    6780    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    6781        return self._parse_partition_by(), self._parse_order()
    6782
    6783    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    6784        self._match(TokenType.BETWEEN)
    6785
    6786        return {
    6787            "value": (
    6788                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    6789                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    6790                or self._parse_bitwise()
    6791            ),
    6792            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    6793        }
    6794
    6795    def _parse_alias(
    6796        self, this: t.Optional[exp.Expression], explicit: bool = False
    6797    ) -> t.Optional[exp.Expression]:
    6798        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    6799        # so this section tries to parse the clause version and if it fails, it treats the token
    6800        # as an identifier (alias)
    6801        if self._can_parse_limit_or_offset():
    6802            return this
    6803
    6804        any_token = self._match(TokenType.ALIAS)
    6805        comments = self._prev_comments or []
    6806
    6807        if explicit and not any_token:
    6808            return this
    6809
    6810        if self._match(TokenType.L_PAREN):
    6811            aliases = self.expression(
    6812                exp.Aliases,
    6813                comments=comments,
    6814                this=this,
    6815                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    6816            )
    6817            self._match_r_paren(aliases)
    6818            return aliases
    6819
    6820        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    6821            self.STRING_ALIASES and self._parse_string_as_identifier()
    6822        )
    6823
    6824        if alias:
    6825            comments.extend(alias.pop_comments())
    6826            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    6827            column = this.this
    6828
    6829            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    6830            if not this.comments and column and column.comments:
    6831                this.comments = column.pop_comments()
    6832
    6833        return this
    6834
    6835    def _parse_id_var(
    6836        self,
    6837        any_token: bool = True,
    6838        tokens: t.Optional[t.Collection[TokenType]] = None,
    6839    ) -> t.Optional[exp.Expression]:
    6840        expression = self._parse_identifier()
    6841        if not expression and (
    6842            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    6843        ):
    6844            quoted = self._prev.token_type == TokenType.STRING
    6845            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    6846
    6847        return expression
    6848
    6849    def _parse_string(self) -> t.Optional[exp.Expression]:
    6850        if self._match_set(self.STRING_PARSERS):
    6851            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    6852        return self._parse_placeholder()
    6853
    6854    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    6855        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    6856
    6857    def _parse_number(self) -> t.Optional[exp.Expression]:
    6858        if self._match_set(self.NUMERIC_PARSERS):
    6859            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    6860        return self._parse_placeholder()
    6861
    6862    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    6863        if self._match(TokenType.IDENTIFIER):
    6864            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    6865        return self._parse_placeholder()
    6866
    6867    def _parse_var(
    6868        self,
    6869        any_token: bool = False,
    6870        tokens: t.Optional[t.Collection[TokenType]] = None,
    6871        upper: bool = False,
    6872    ) -> t.Optional[exp.Expression]:
    6873        if (
    6874            (any_token and self._advance_any())
    6875            or self._match(TokenType.VAR)
    6876            or (self._match_set(tokens) if tokens else False)
    6877        ):
    6878            return self.expression(
    6879                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    6880            )
    6881        return self._parse_placeholder()
    6882
    6883    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    6884        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    6885            self._advance()
    6886            return self._prev
    6887        return None
    6888
    6889    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
    6890        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
    6891
    6892    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    6893        return self._parse_primary() or self._parse_var(any_token=True)
    6894
    6895    def _parse_null(self) -> t.Optional[exp.Expression]:
    6896        if self._match_set(self.NULL_TOKENS):
    6897            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    6898        return self._parse_placeholder()
    6899
    6900    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    6901        if self._match(TokenType.TRUE):
    6902            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    6903        if self._match(TokenType.FALSE):
    6904            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    6905        return self._parse_placeholder()
    6906
    6907    def _parse_star(self) -> t.Optional[exp.Expression]:
    6908        if self._match(TokenType.STAR):
    6909            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    6910        return self._parse_placeholder()
    6911
    6912    def _parse_parameter(self) -> exp.Parameter:
    6913        this = self._parse_identifier() or self._parse_primary_or_var()
    6914        return self.expression(exp.Parameter, this=this)
    6915
    6916    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    6917        if self._match_set(self.PLACEHOLDER_PARSERS):
    6918            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    6919            if placeholder:
    6920                return placeholder
    6921            self._advance(-1)
    6922        return None
    6923
    6924    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    6925        if not self._match_texts(keywords):
    6926            return None
    6927        if self._match(TokenType.L_PAREN, advance=False):
    6928            return self._parse_wrapped_csv(self._parse_expression)
    6929
    6930        expression = self._parse_expression()
    6931        return [expression] if expression else None
    6932
    6933    def _parse_csv(
    6934        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    6935    ) -> t.List[exp.Expression]:
    6936        parse_result = parse_method()
    6937        items = [parse_result] if parse_result is not None else []
    6938
    6939        while self._match(sep):
    6940            self._add_comments(parse_result)
    6941            parse_result = parse_method()
    6942            if parse_result is not None:
    6943                items.append(parse_result)
    6944
    6945        return items
    6946
    6947    def _parse_tokens(
    6948        self, parse_method: t.Callable, expressions: t.Dict
    6949    ) -> t.Optional[exp.Expression]:
    6950        this = parse_method()
    6951
    6952        while self._match_set(expressions):
    6953            this = self.expression(
    6954                expressions[self._prev.token_type],
    6955                this=this,
    6956                comments=self._prev_comments,
    6957                expression=parse_method(),
    6958            )
    6959
    6960        return this
    6961
    6962    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    6963        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    6964
    6965    def _parse_wrapped_csv(
    6966        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    6967    ) -> t.List[exp.Expression]:
    6968        return self._parse_wrapped(
    6969            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    6970        )
    6971
    6972    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    6973        wrapped = self._match(TokenType.L_PAREN)
    6974        if not wrapped and not optional:
    6975            self.raise_error("Expecting (")
    6976        parse_result = parse_method()
    6977        if wrapped:
    6978            self._match_r_paren()
    6979        return parse_result
    6980
    6981    def _parse_expressions(self) -> t.List[exp.Expression]:
    6982        return self._parse_csv(self._parse_expression)
    6983
    6984    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    6985        return self._parse_select() or self._parse_set_operations(
    6986            self._parse_alias(self._parse_assignment(), explicit=True)
    6987            if alias
    6988            else self._parse_assignment()
    6989        )
    6990
    6991    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    6992        return self._parse_query_modifiers(
    6993            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    6994        )
    6995
    6996    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    6997        this = None
    6998        if self._match_texts(self.TRANSACTION_KIND):
    6999            this = self._prev.text
    7000
    7001        self._match_texts(("TRANSACTION", "WORK"))
    7002
    7003        modes = []
    7004        while True:
    7005            mode = []
    7006            while self._match(TokenType.VAR):
    7007                mode.append(self._prev.text)
    7008
    7009            if mode:
    7010                modes.append(" ".join(mode))
    7011            if not self._match(TokenType.COMMA):
    7012                break
    7013
    7014        return self.expression(exp.Transaction, this=this, modes=modes)
    7015
    7016    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    7017        chain = None
    7018        savepoint = None
    7019        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    7020
    7021        self._match_texts(("TRANSACTION", "WORK"))
    7022
    7023        if self._match_text_seq("TO"):
    7024            self._match_text_seq("SAVEPOINT")
    7025            savepoint = self._parse_id_var()
    7026
    7027        if self._match(TokenType.AND):
    7028            chain = not self._match_text_seq("NO")
    7029            self._match_text_seq("CHAIN")
    7030
    7031        if is_rollback:
    7032            return self.expression(exp.Rollback, savepoint=savepoint)
    7033
    7034        return self.expression(exp.Commit, chain=chain)
    7035
    7036    def _parse_refresh(self) -> exp.Refresh:
    7037        self._match(TokenType.TABLE)
    7038        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    7039
    7040    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    7041        if not self._match_text_seq("ADD"):
    7042            return None
    7043
    7044        self._match(TokenType.COLUMN)
    7045        exists_column = self._parse_exists(not_=True)
    7046        expression = self._parse_field_def()
    7047
    7048        if expression:
    7049            expression.set("exists", exists_column)
    7050
    7051            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    7052            if self._match_texts(("FIRST", "AFTER")):
    7053                position = self._prev.text
    7054                column_position = self.expression(
    7055                    exp.ColumnPosition, this=self._parse_column(), position=position
    7056                )
    7057                expression.set("position", column_position)
    7058
    7059        return expression
    7060
    7061    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    7062        drop = self._match(TokenType.DROP) and self._parse_drop()
    7063        if drop and not isinstance(drop, exp.Command):
    7064            drop.set("kind", drop.args.get("kind", "COLUMN"))
    7065        return drop
    7066
    7067    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    7068    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    7069        return self.expression(
    7070            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    7071        )
    7072
    7073    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    7074        index = self._index - 1
    7075
    7076        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    7077            return self._parse_csv(
    7078                lambda: self.expression(
    7079                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    7080                )
    7081            )
    7082
    7083        self._retreat(index)
    7084        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    7085            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    7086
    7087        if self._match_text_seq("ADD", "COLUMNS"):
    7088            schema = self._parse_schema()
    7089            if schema:
    7090                return [schema]
    7091            return []
    7092
    7093        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    7094
    7095    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    7096        if self._match_texts(self.ALTER_ALTER_PARSERS):
    7097            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    7098
    7099        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    7100        # keyword after ALTER we default to parsing this statement
    7101        self._match(TokenType.COLUMN)
    7102        column = self._parse_field(any_token=True)
    7103
    7104        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    7105            return self.expression(exp.AlterColumn, this=column, drop=True)
    7106        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    7107            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    7108        if self._match(TokenType.COMMENT):
    7109            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    7110        if self._match_text_seq("DROP", "NOT", "NULL"):
    7111            return self.expression(
    7112                exp.AlterColumn,
    7113                this=column,
    7114                drop=True,
    7115                allow_null=True,
    7116            )
    7117        if self._match_text_seq("SET", "NOT", "NULL"):
    7118            return self.expression(
    7119                exp.AlterColumn,
    7120                this=column,
    7121                allow_null=False,
    7122            )
    7123
    7124        if self._match_text_seq("SET", "VISIBLE"):
    7125            return self.expression(exp.AlterColumn, this=column, visible="VISIBLE")
    7126        if self._match_text_seq("SET", "INVISIBLE"):
    7127            return self.expression(exp.AlterColumn, this=column, visible="INVISIBLE")
    7128
    7129        self._match_text_seq("SET", "DATA")
    7130        self._match_text_seq("TYPE")
    7131        return self.expression(
    7132            exp.AlterColumn,
    7133            this=column,
    7134            dtype=self._parse_types(),
    7135            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    7136            using=self._match(TokenType.USING) and self._parse_assignment(),
    7137        )
    7138
    7139    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    7140        if self._match_texts(("ALL", "EVEN", "AUTO")):
    7141            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    7142
    7143        self._match_text_seq("KEY", "DISTKEY")
    7144        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    7145
    7146    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    7147        if compound:
    7148            self._match_text_seq("SORTKEY")
    7149
    7150        if self._match(TokenType.L_PAREN, advance=False):
    7151            return self.expression(
    7152                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    7153            )
    7154
    7155        self._match_texts(("AUTO", "NONE"))
    7156        return self.expression(
    7157            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    7158        )
    7159
    7160    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    7161        index = self._index - 1
    7162
    7163        partition_exists = self._parse_exists()
    7164        if self._match(TokenType.PARTITION, advance=False):
    7165            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    7166
    7167        self._retreat(index)
    7168        return self._parse_csv(self._parse_drop_column)
    7169
    7170    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
    7171        if self._match(TokenType.COLUMN):
    7172            exists = self._parse_exists()
    7173            old_column = self._parse_column()
    7174            to = self._match_text_seq("TO")
    7175            new_column = self._parse_column()
    7176
    7177            if old_column is None or to is None or new_column is None:
    7178                return None
    7179
    7180            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    7181
    7182        self._match_text_seq("TO")
    7183        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
    7184
    7185    def _parse_alter_table_set(self) -> exp.AlterSet:
    7186        alter_set = self.expression(exp.AlterSet)
    7187
    7188        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    7189            "TABLE", "PROPERTIES"
    7190        ):
    7191            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    7192        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    7193            alter_set.set("expressions", [self._parse_assignment()])
    7194        elif self._match_texts(("LOGGED", "UNLOGGED")):
    7195            alter_set.set("option", exp.var(self._prev.text.upper()))
    7196        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    7197            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    7198        elif self._match_text_seq("LOCATION"):
    7199            alter_set.set("location", self._parse_field())
    7200        elif self._match_text_seq("ACCESS", "METHOD"):
    7201            alter_set.set("access_method", self._parse_field())
    7202        elif self._match_text_seq("TABLESPACE"):
    7203            alter_set.set("tablespace", self._parse_field())
    7204        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    7205            alter_set.set("file_format", [self._parse_field()])
    7206        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    7207            alter_set.set("file_format", self._parse_wrapped_options())
    7208        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    7209            alter_set.set("copy_options", self._parse_wrapped_options())
    7210        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    7211            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    7212        else:
    7213            if self._match_text_seq("SERDE"):
    7214                alter_set.set("serde", self._parse_field())
    7215
    7216            alter_set.set("expressions", [self._parse_properties()])
    7217
    7218        return alter_set
    7219
    7220    def _parse_alter(self) -> exp.Alter | exp.Command:
    7221        start = self._prev
    7222
    7223        alter_token = self._match_set(self.ALTERABLES) and self._prev
    7224        if not alter_token:
    7225            return self._parse_as_command(start)
    7226
    7227        exists = self._parse_exists()
    7228        only = self._match_text_seq("ONLY")
    7229        this = self._parse_table(schema=True)
    7230        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7231
    7232        if self._next:
    7233            self._advance()
    7234
    7235        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    7236        if parser:
    7237            actions = ensure_list(parser(self))
    7238            not_valid = self._match_text_seq("NOT", "VALID")
    7239            options = self._parse_csv(self._parse_property)
    7240
    7241            if not self._curr and actions:
    7242                return self.expression(
    7243                    exp.Alter,
    7244                    this=this,
    7245                    kind=alter_token.text.upper(),
    7246                    exists=exists,
    7247                    actions=actions,
    7248                    only=only,
    7249                    options=options,
    7250                    cluster=cluster,
    7251                    not_valid=not_valid,
    7252                )
    7253
    7254        return self._parse_as_command(start)
    7255
    7256    def _parse_analyze(self) -> exp.Analyze | exp.Command:
    7257        start = self._prev
    7258        # https://duckdb.org/docs/sql/statements/analyze
    7259        if not self._curr:
    7260            return self.expression(exp.Analyze)
    7261
    7262        options = []
    7263        while self._match_texts(self.ANALYZE_STYLES):
    7264            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
    7265                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
    7266            else:
    7267                options.append(self._prev.text.upper())
    7268
    7269        this: t.Optional[exp.Expression] = None
    7270        inner_expression: t.Optional[exp.Expression] = None
    7271
    7272        kind = self._curr and self._curr.text.upper()
    7273
    7274        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
    7275            this = self._parse_table_parts()
    7276        elif self._match_text_seq("TABLES"):
    7277            if self._match_set((TokenType.FROM, TokenType.IN)):
    7278                kind = f"{kind} {self._prev.text.upper()}"
    7279                this = self._parse_table(schema=True, is_db_reference=True)
    7280        elif self._match_text_seq("DATABASE"):
    7281            this = self._parse_table(schema=True, is_db_reference=True)
    7282        elif self._match_text_seq("CLUSTER"):
    7283            this = self._parse_table()
    7284        # Try matching inner expr keywords before fallback to parse table.
    7285        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7286            kind = None
    7287            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7288        else:
    7289            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
    7290            kind = None
    7291            this = self._parse_table_parts()
    7292
    7293        partition = self._try_parse(self._parse_partition)
    7294        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
    7295            return self._parse_as_command(start)
    7296
    7297        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7298        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
    7299            "WITH", "ASYNC", "MODE"
    7300        ):
    7301            mode = f"WITH {self._tokens[self._index-2].text.upper()} MODE"
    7302        else:
    7303            mode = None
    7304
    7305        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7306            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7307
    7308        properties = self._parse_properties()
    7309        return self.expression(
    7310            exp.Analyze,
    7311            kind=kind,
    7312            this=this,
    7313            mode=mode,
    7314            partition=partition,
    7315            properties=properties,
    7316            expression=inner_expression,
    7317            options=options,
    7318        )
    7319
    7320    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
    7321    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
    7322        this = None
    7323        kind = self._prev.text.upper()
    7324        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
    7325        expressions = []
    7326
    7327        if not self._match_text_seq("STATISTICS"):
    7328            self.raise_error("Expecting token STATISTICS")
    7329
    7330        if self._match_text_seq("NOSCAN"):
    7331            this = "NOSCAN"
    7332        elif self._match(TokenType.FOR):
    7333            if self._match_text_seq("ALL", "COLUMNS"):
    7334                this = "FOR ALL COLUMNS"
    7335            if self._match_texts("COLUMNS"):
    7336                this = "FOR COLUMNS"
    7337                expressions = self._parse_csv(self._parse_column_reference)
    7338        elif self._match_text_seq("SAMPLE"):
    7339            sample = self._parse_number()
    7340            expressions = [
    7341                self.expression(
    7342                    exp.AnalyzeSample,
    7343                    sample=sample,
    7344                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
    7345                )
    7346            ]
    7347
    7348        return self.expression(
    7349            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
    7350        )
    7351
    7352    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
    7353    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
    7354        kind = None
    7355        this = None
    7356        expression: t.Optional[exp.Expression] = None
    7357        if self._match_text_seq("REF", "UPDATE"):
    7358            kind = "REF"
    7359            this = "UPDATE"
    7360            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
    7361                this = "UPDATE SET DANGLING TO NULL"
    7362        elif self._match_text_seq("STRUCTURE"):
    7363            kind = "STRUCTURE"
    7364            if self._match_text_seq("CASCADE", "FAST"):
    7365                this = "CASCADE FAST"
    7366            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
    7367                ("ONLINE", "OFFLINE")
    7368            ):
    7369                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
    7370                expression = self._parse_into()
    7371
    7372        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
    7373
    7374    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
    7375        this = self._prev.text.upper()
    7376        if self._match_text_seq("COLUMNS"):
    7377            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
    7378        return None
    7379
    7380    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
    7381        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
    7382        if self._match_text_seq("STATISTICS"):
    7383            return self.expression(exp.AnalyzeDelete, kind=kind)
    7384        return None
    7385
    7386    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
    7387        if self._match_text_seq("CHAINED", "ROWS"):
    7388            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
    7389        return None
    7390
    7391    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
    7392    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
    7393        this = self._prev.text.upper()
    7394        expression: t.Optional[exp.Expression] = None
    7395        expressions = []
    7396        update_options = None
    7397
    7398        if self._match_text_seq("HISTOGRAM", "ON"):
    7399            expressions = self._parse_csv(self._parse_column_reference)
    7400            with_expressions = []
    7401            while self._match(TokenType.WITH):
    7402                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7403                if self._match_texts(("SYNC", "ASYNC")):
    7404                    if self._match_text_seq("MODE", advance=False):
    7405                        with_expressions.append(f"{self._prev.text.upper()} MODE")
    7406                        self._advance()
    7407                else:
    7408                    buckets = self._parse_number()
    7409                    if self._match_text_seq("BUCKETS"):
    7410                        with_expressions.append(f"{buckets} BUCKETS")
    7411            if with_expressions:
    7412                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
    7413
    7414            if self._match_texts(("MANUAL", "AUTO")) and self._match(
    7415                TokenType.UPDATE, advance=False
    7416            ):
    7417                update_options = self._prev.text.upper()
    7418                self._advance()
    7419            elif self._match_text_seq("USING", "DATA"):
    7420                expression = self.expression(exp.UsingData, this=self._parse_string())
    7421
    7422        return self.expression(
    7423            exp.AnalyzeHistogram,
    7424            this=this,
    7425            expressions=expressions,
    7426            expression=expression,
    7427            update_options=update_options,
    7428        )
    7429
    7430    def _parse_merge(self) -> exp.Merge:
    7431        self._match(TokenType.INTO)
    7432        target = self._parse_table()
    7433
    7434        if target and self._match(TokenType.ALIAS, advance=False):
    7435            target.set("alias", self._parse_table_alias())
    7436
    7437        self._match(TokenType.USING)
    7438        using = self._parse_table()
    7439
    7440        self._match(TokenType.ON)
    7441        on = self._parse_assignment()
    7442
    7443        return self.expression(
    7444            exp.Merge,
    7445            this=target,
    7446            using=using,
    7447            on=on,
    7448            whens=self._parse_when_matched(),
    7449            returning=self._parse_returning(),
    7450        )
    7451
    7452    def _parse_when_matched(self) -> exp.Whens:
    7453        whens = []
    7454
    7455        while self._match(TokenType.WHEN):
    7456            matched = not self._match(TokenType.NOT)
    7457            self._match_text_seq("MATCHED")
    7458            source = (
    7459                False
    7460                if self._match_text_seq("BY", "TARGET")
    7461                else self._match_text_seq("BY", "SOURCE")
    7462            )
    7463            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    7464
    7465            self._match(TokenType.THEN)
    7466
    7467            if self._match(TokenType.INSERT):
    7468                this = self._parse_star()
    7469                if this:
    7470                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
    7471                else:
    7472                    then = self.expression(
    7473                        exp.Insert,
    7474                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
    7475                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    7476                    )
    7477            elif self._match(TokenType.UPDATE):
    7478                expressions = self._parse_star()
    7479                if expressions:
    7480                    then = self.expression(exp.Update, expressions=expressions)
    7481                else:
    7482                    then = self.expression(
    7483                        exp.Update,
    7484                        expressions=self._match(TokenType.SET)
    7485                        and self._parse_csv(self._parse_equality),
    7486                    )
    7487            elif self._match(TokenType.DELETE):
    7488                then = self.expression(exp.Var, this=self._prev.text)
    7489            else:
    7490                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    7491
    7492            whens.append(
    7493                self.expression(
    7494                    exp.When,
    7495                    matched=matched,
    7496                    source=source,
    7497                    condition=condition,
    7498                    then=then,
    7499                )
    7500            )
    7501        return self.expression(exp.Whens, expressions=whens)
    7502
    7503    def _parse_show(self) -> t.Optional[exp.Expression]:
    7504        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    7505        if parser:
    7506            return parser(self)
    7507        return self._parse_as_command(self._prev)
    7508
    7509    def _parse_set_item_assignment(
    7510        self, kind: t.Optional[str] = None
    7511    ) -> t.Optional[exp.Expression]:
    7512        index = self._index
    7513
    7514        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    7515            return self._parse_set_transaction(global_=kind == "GLOBAL")
    7516
    7517        left = self._parse_primary() or self._parse_column()
    7518        assignment_delimiter = self._match_texts(("=", "TO"))
    7519
    7520        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    7521            self._retreat(index)
    7522            return None
    7523
    7524        right = self._parse_statement() or self._parse_id_var()
    7525        if isinstance(right, (exp.Column, exp.Identifier)):
    7526            right = exp.var(right.name)
    7527
    7528        this = self.expression(exp.EQ, this=left, expression=right)
    7529        return self.expression(exp.SetItem, this=this, kind=kind)
    7530
    7531    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    7532        self._match_text_seq("TRANSACTION")
    7533        characteristics = self._parse_csv(
    7534            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    7535        )
    7536        return self.expression(
    7537            exp.SetItem,
    7538            expressions=characteristics,
    7539            kind="TRANSACTION",
    7540            **{"global": global_},  # type: ignore
    7541        )
    7542
    7543    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    7544        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    7545        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    7546
    7547    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    7548        index = self._index
    7549        set_ = self.expression(
    7550            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    7551        )
    7552
    7553        if self._curr:
    7554            self._retreat(index)
    7555            return self._parse_as_command(self._prev)
    7556
    7557        return set_
    7558
    7559    def _parse_var_from_options(
    7560        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    7561    ) -> t.Optional[exp.Var]:
    7562        start = self._curr
    7563        if not start:
    7564            return None
    7565
    7566        option = start.text.upper()
    7567        continuations = options.get(option)
    7568
    7569        index = self._index
    7570        self._advance()
    7571        for keywords in continuations or []:
    7572            if isinstance(keywords, str):
    7573                keywords = (keywords,)
    7574
    7575            if self._match_text_seq(*keywords):
    7576                option = f"{option} {' '.join(keywords)}"
    7577                break
    7578        else:
    7579            if continuations or continuations is None:
    7580                if raise_unmatched:
    7581                    self.raise_error(f"Unknown option {option}")
    7582
    7583                self._retreat(index)
    7584                return None
    7585
    7586        return exp.var(option)
    7587
    7588    def _parse_as_command(self, start: Token) -> exp.Command:
    7589        while self._curr:
    7590            self._advance()
    7591        text = self._find_sql(start, self._prev)
    7592        size = len(start.text)
    7593        self._warn_unsupported()
    7594        return exp.Command(this=text[:size], expression=text[size:])
    7595
    7596    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    7597        settings = []
    7598
    7599        self._match_l_paren()
    7600        kind = self._parse_id_var()
    7601
    7602        if self._match(TokenType.L_PAREN):
    7603            while True:
    7604                key = self._parse_id_var()
    7605                value = self._parse_primary()
    7606                if not key and value is None:
    7607                    break
    7608                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    7609            self._match(TokenType.R_PAREN)
    7610
    7611        self._match_r_paren()
    7612
    7613        return self.expression(
    7614            exp.DictProperty,
    7615            this=this,
    7616            kind=kind.this if kind else None,
    7617            settings=settings,
    7618        )
    7619
    7620    def _parse_dict_range(self, this: str) -> exp.DictRange:
    7621        self._match_l_paren()
    7622        has_min = self._match_text_seq("MIN")
    7623        if has_min:
    7624            min = self._parse_var() or self._parse_primary()
    7625            self._match_text_seq("MAX")
    7626            max = self._parse_var() or self._parse_primary()
    7627        else:
    7628            max = self._parse_var() or self._parse_primary()
    7629            min = exp.Literal.number(0)
    7630        self._match_r_paren()
    7631        return self.expression(exp.DictRange, this=this, min=min, max=max)
    7632
    7633    def _parse_comprehension(
    7634        self, this: t.Optional[exp.Expression]
    7635    ) -> t.Optional[exp.Comprehension]:
    7636        index = self._index
    7637        expression = self._parse_column()
    7638        if not self._match(TokenType.IN):
    7639            self._retreat(index - 1)
    7640            return None
    7641        iterator = self._parse_column()
    7642        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    7643        return self.expression(
    7644            exp.Comprehension,
    7645            this=this,
    7646            expression=expression,
    7647            iterator=iterator,
    7648            condition=condition,
    7649        )
    7650
    7651    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    7652        if self._match(TokenType.HEREDOC_STRING):
    7653            return self.expression(exp.Heredoc, this=self._prev.text)
    7654
    7655        if not self._match_text_seq("$"):
    7656            return None
    7657
    7658        tags = ["$"]
    7659        tag_text = None
    7660
    7661        if self._is_connected():
    7662            self._advance()
    7663            tags.append(self._prev.text.upper())
    7664        else:
    7665            self.raise_error("No closing $ found")
    7666
    7667        if tags[-1] != "$":
    7668            if self._is_connected() and self._match_text_seq("$"):
    7669                tag_text = tags[-1]
    7670                tags.append("$")
    7671            else:
    7672                self.raise_error("No closing $ found")
    7673
    7674        heredoc_start = self._curr
    7675
    7676        while self._curr:
    7677            if self._match_text_seq(*tags, advance=False):
    7678                this = self._find_sql(heredoc_start, self._prev)
    7679                self._advance(len(tags))
    7680                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    7681
    7682            self._advance()
    7683
    7684        self.raise_error(f"No closing {''.join(tags)} found")
    7685        return None
    7686
    7687    def _find_parser(
    7688        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    7689    ) -> t.Optional[t.Callable]:
    7690        if not self._curr:
    7691            return None
    7692
    7693        index = self._index
    7694        this = []
    7695        while True:
    7696            # The current token might be multiple words
    7697            curr = self._curr.text.upper()
    7698            key = curr.split(" ")
    7699            this.append(curr)
    7700
    7701            self._advance()
    7702            result, trie = in_trie(trie, key)
    7703            if result == TrieResult.FAILED:
    7704                break
    7705
    7706            if result == TrieResult.EXISTS:
    7707                subparser = parsers[" ".join(this)]
    7708                return subparser
    7709
    7710        self._retreat(index)
    7711        return None
    7712
    7713    def _match(self, token_type, advance=True, expression=None):
    7714        if not self._curr:
    7715            return None
    7716
    7717        if self._curr.token_type == token_type:
    7718            if advance:
    7719                self._advance()
    7720            self._add_comments(expression)
    7721            return True
    7722
    7723        return None
    7724
    7725    def _match_set(self, types, advance=True):
    7726        if not self._curr:
    7727            return None
    7728
    7729        if self._curr.token_type in types:
    7730            if advance:
    7731                self._advance()
    7732            return True
    7733
    7734        return None
    7735
    7736    def _match_pair(self, token_type_a, token_type_b, advance=True):
    7737        if not self._curr or not self._next:
    7738            return None
    7739
    7740        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    7741            if advance:
    7742                self._advance(2)
    7743            return True
    7744
    7745        return None
    7746
    7747    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7748        if not self._match(TokenType.L_PAREN, expression=expression):
    7749            self.raise_error("Expecting (")
    7750
    7751    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7752        if not self._match(TokenType.R_PAREN, expression=expression):
    7753            self.raise_error("Expecting )")
    7754
    7755    def _match_texts(self, texts, advance=True):
    7756        if (
    7757            self._curr
    7758            and self._curr.token_type != TokenType.STRING
    7759            and self._curr.text.upper() in texts
    7760        ):
    7761            if advance:
    7762                self._advance()
    7763            return True
    7764        return None
    7765
    7766    def _match_text_seq(self, *texts, advance=True):
    7767        index = self._index
    7768        for text in texts:
    7769            if (
    7770                self._curr
    7771                and self._curr.token_type != TokenType.STRING
    7772                and self._curr.text.upper() == text
    7773            ):
    7774                self._advance()
    7775            else:
    7776                self._retreat(index)
    7777                return None
    7778
    7779        if not advance:
    7780            self._retreat(index)
    7781
    7782        return True
    7783
    7784    def _replace_lambda(
    7785        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    7786    ) -> t.Optional[exp.Expression]:
    7787        if not node:
    7788            return node
    7789
    7790        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    7791
    7792        for column in node.find_all(exp.Column):
    7793            typ = lambda_types.get(column.parts[0].name)
    7794            if typ is not None:
    7795                dot_or_id = column.to_dot() if column.table else column.this
    7796
    7797                if typ:
    7798                    dot_or_id = self.expression(
    7799                        exp.Cast,
    7800                        this=dot_or_id,
    7801                        to=typ,
    7802                    )
    7803
    7804                parent = column.parent
    7805
    7806                while isinstance(parent, exp.Dot):
    7807                    if not isinstance(parent.parent, exp.Dot):
    7808                        parent.replace(dot_or_id)
    7809                        break
    7810                    parent = parent.parent
    7811                else:
    7812                    if column is node:
    7813                        node = dot_or_id
    7814                    else:
    7815                        column.replace(dot_or_id)
    7816        return node
    7817
    7818    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    7819        start = self._prev
    7820
    7821        # Not to be confused with TRUNCATE(number, decimals) function call
    7822        if self._match(TokenType.L_PAREN):
    7823            self._retreat(self._index - 2)
    7824            return self._parse_function()
    7825
    7826        # Clickhouse supports TRUNCATE DATABASE as well
    7827        is_database = self._match(TokenType.DATABASE)
    7828
    7829        self._match(TokenType.TABLE)
    7830
    7831        exists = self._parse_exists(not_=False)
    7832
    7833        expressions = self._parse_csv(
    7834            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    7835        )
    7836
    7837        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7838
    7839        if self._match_text_seq("RESTART", "IDENTITY"):
    7840            identity = "RESTART"
    7841        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    7842            identity = "CONTINUE"
    7843        else:
    7844            identity = None
    7845
    7846        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    7847            option = self._prev.text
    7848        else:
    7849            option = None
    7850
    7851        partition = self._parse_partition()
    7852
    7853        # Fallback case
    7854        if self._curr:
    7855            return self._parse_as_command(start)
    7856
    7857        return self.expression(
    7858            exp.TruncateTable,
    7859            expressions=expressions,
    7860            is_database=is_database,
    7861            exists=exists,
    7862            cluster=cluster,
    7863            identity=identity,
    7864            option=option,
    7865            partition=partition,
    7866        )
    7867
    7868    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    7869        this = self._parse_ordered(self._parse_opclass)
    7870
    7871        if not self._match(TokenType.WITH):
    7872            return this
    7873
    7874        op = self._parse_var(any_token=True)
    7875
    7876        return self.expression(exp.WithOperator, this=this, op=op)
    7877
    7878    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    7879        self._match(TokenType.EQ)
    7880        self._match(TokenType.L_PAREN)
    7881
    7882        opts: t.List[t.Optional[exp.Expression]] = []
    7883        while self._curr and not self._match(TokenType.R_PAREN):
    7884            if self._match_text_seq("FORMAT_NAME", "="):
    7885                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
    7886                # so we parse it separately to use _parse_field()
    7887                prop = self.expression(
    7888                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
    7889                )
    7890                opts.append(prop)
    7891            else:
    7892                opts.append(self._parse_property())
    7893
    7894            self._match(TokenType.COMMA)
    7895
    7896        return opts
    7897
    7898    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    7899        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    7900
    7901        options = []
    7902        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    7903            option = self._parse_var(any_token=True)
    7904            prev = self._prev.text.upper()
    7905
    7906            # Different dialects might separate options and values by white space, "=" and "AS"
    7907            self._match(TokenType.EQ)
    7908            self._match(TokenType.ALIAS)
    7909
    7910            param = self.expression(exp.CopyParameter, this=option)
    7911
    7912            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    7913                TokenType.L_PAREN, advance=False
    7914            ):
    7915                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    7916                param.set("expressions", self._parse_wrapped_options())
    7917            elif prev == "FILE_FORMAT":
    7918                # T-SQL's external file format case
    7919                param.set("expression", self._parse_field())
    7920            else:
    7921                param.set("expression", self._parse_unquoted_field())
    7922
    7923            options.append(param)
    7924            self._match(sep)
    7925
    7926        return options
    7927
    7928    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    7929        expr = self.expression(exp.Credentials)
    7930
    7931        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    7932            expr.set("storage", self._parse_field())
    7933        if self._match_text_seq("CREDENTIALS"):
    7934            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    7935            creds = (
    7936                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    7937            )
    7938            expr.set("credentials", creds)
    7939        if self._match_text_seq("ENCRYPTION"):
    7940            expr.set("encryption", self._parse_wrapped_options())
    7941        if self._match_text_seq("IAM_ROLE"):
    7942            expr.set("iam_role", self._parse_field())
    7943        if self._match_text_seq("REGION"):
    7944            expr.set("region", self._parse_field())
    7945
    7946        return expr
    7947
    7948    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    7949        return self._parse_field()
    7950
    7951    def _parse_copy(self) -> exp.Copy | exp.Command:
    7952        start = self._prev
    7953
    7954        self._match(TokenType.INTO)
    7955
    7956        this = (
    7957            self._parse_select(nested=True, parse_subquery_alias=False)
    7958            if self._match(TokenType.L_PAREN, advance=False)
    7959            else self._parse_table(schema=True)
    7960        )
    7961
    7962        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    7963
    7964        files = self._parse_csv(self._parse_file_location)
    7965        credentials = self._parse_credentials()
    7966
    7967        self._match_text_seq("WITH")
    7968
    7969        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    7970
    7971        # Fallback case
    7972        if self._curr:
    7973            return self._parse_as_command(start)
    7974
    7975        return self.expression(
    7976            exp.Copy,
    7977            this=this,
    7978            kind=kind,
    7979            credentials=credentials,
    7980            files=files,
    7981            params=params,
    7982        )
    7983
    7984    def _parse_normalize(self) -> exp.Normalize:
    7985        return self.expression(
    7986            exp.Normalize,
    7987            this=self._parse_bitwise(),
    7988            form=self._match(TokenType.COMMA) and self._parse_var(),
    7989        )
    7990
    7991    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
    7992        args = self._parse_csv(lambda: self._parse_lambda())
    7993
    7994        this = seq_get(args, 0)
    7995        decimals = seq_get(args, 1)
    7996
    7997        return expr_type(
    7998            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
    7999        )
    8000
    8001    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
    8002        if self._match_text_seq("COLUMNS", "(", advance=False):
    8003            this = self._parse_function()
    8004            if isinstance(this, exp.Columns):
    8005                this.set("unpack", True)
    8006            return this
    8007
    8008        return self.expression(
    8009            exp.Star,
    8010            **{  # type: ignore
    8011                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
    8012                "replace": self._parse_star_op("REPLACE"),
    8013                "rename": self._parse_star_op("RENAME"),
    8014            },
    8015        )
    8016
    8017    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
    8018        privilege_parts = []
    8019
    8020        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
    8021        # (end of privilege list) or L_PAREN (start of column list) are met
    8022        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
    8023            privilege_parts.append(self._curr.text.upper())
    8024            self._advance()
    8025
    8026        this = exp.var(" ".join(privilege_parts))
    8027        expressions = (
    8028            self._parse_wrapped_csv(self._parse_column)
    8029            if self._match(TokenType.L_PAREN, advance=False)
    8030            else None
    8031        )
    8032
    8033        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
    8034
    8035    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
    8036        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
    8037        principal = self._parse_id_var()
    8038
    8039        if not principal:
    8040            return None
    8041
    8042        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
    8043
    8044    def _parse_grant(self) -> exp.Grant | exp.Command:
    8045        start = self._prev
    8046
    8047        privileges = self._parse_csv(self._parse_grant_privilege)
    8048
    8049        self._match(TokenType.ON)
    8050        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    8051
    8052        # Attempt to parse the securable e.g. MySQL allows names
    8053        # such as "foo.*", "*.*" which are not easily parseable yet
    8054        securable = self._try_parse(self._parse_table_parts)
    8055
    8056        if not securable or not self._match_text_seq("TO"):
    8057            return self._parse_as_command(start)
    8058
    8059        principals = self._parse_csv(self._parse_grant_principal)
    8060
    8061        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
    8062
    8063        if self._curr:
    8064            return self._parse_as_command(start)
    8065
    8066        return self.expression(
    8067            exp.Grant,
    8068            privileges=privileges,
    8069            kind=kind,
    8070            securable=securable,
    8071            principals=principals,
    8072            grant_option=grant_option,
    8073        )
    8074
    8075    def _parse_overlay(self) -> exp.Overlay:
    8076        return self.expression(
    8077            exp.Overlay,
    8078            **{  # type: ignore
    8079                "this": self._parse_bitwise(),
    8080                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
    8081                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
    8082                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
    8083            },
    8084        )

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, Type[sqlglot.dialects.Dialect], NoneType] = None) View Source

    1460    def __init__(
    1461        self,
    1462        error_level: t.Optional[ErrorLevel] = None,
    1463        error_message_context: int = 100,
    1464        max_errors: int = 3,
    1465        dialect: DialectType = None,
    1466    ):
    1467        from sqlglot.dialects import Dialect
    1468
    1469        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1470        self.error_message_context = error_message_context
    1471        self.max_errors = max_errors
    1472        self.dialect = Dialect.get_or_raise(dialect)
    1473        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'>>, 'AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.And'>>, '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'>>, 'APPLY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Apply'>>, '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': <function Parser.<lambda>>, 'ARRAY_AGG': <function Parser.<lambda>>, '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': <function Parser.<lambda>>, 'CHAR': <function Parser.<lambda>>, 'COALESCE': <function build_coalesce>, 'IFNULL': <function build_coalesce>, 'NVL': <function build_coalesce>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Columns'>>, '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'>>, 'CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Contains'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, '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_SCHEMA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentSchema'>>, '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'>>, 'DATE_BIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateBin'>>, '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'>>, 'DAYOFWEEK_ISO': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'ISODOW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, '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'>>, 'EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exists'>>, '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'>>, 'EXPLODING_GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodingGenerateSeries'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FEATURES_AT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FeaturesAtTime'>>, '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'>>, 'FROM_ISO8601_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromISO8601Timestamp'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <function Parser.<lambda>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GENERATE_TIMESTAMP_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateTimestampArray'>>, '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'>>, 'INLINE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Inline'>>, 'INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Int64'>>, 'IS_ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsAscii'>>, '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_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExists'>>, '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'>>, 'J_S_O_N_B_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBObjectAgg'>>, 'J_S_O_N_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONCast'>>, 'J_S_O_N_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractArray'>>, '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'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, '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'>>, 'CHAR_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHARACTER_LENGTH': <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'>>, 'MAKE_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MakeInterval'>>, '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'>>, 'MEDIAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Median'>>, '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'>>, 'NORMALIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Normalize'>>, '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'>>, 'OBJECT_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ObjectInsert'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Or'>>, 'OVERLAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Overlay'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, '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_EXTRACT_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtractAll'>>, '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'>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, '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'>>, 'STDEV': <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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, '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'>>, 'SUBSTR': <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_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, '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_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDatetime'>>, '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'>>, 'UNICODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unicode'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_SECONDS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixSeconds'>>, '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'>>, 'UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GEN_RANDOM_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GENERATE_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'UUID_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, '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'>>, 'XMLELEMENT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLElement'>>, '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'>>, 'ARRAYAGG': <function Parser.<lambda>>, '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>>, 'LPAD': <function Parser.<lambda>>, 'LEFTPAD': <function Parser.<lambda>>, 'LTRIM': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'RIGHTPAD': <function Parser.<lambda>>, 'RPAD': <function Parser.<lambda>>, 'RTRIM': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'STRPOS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'CHARINDEX': <function Parser.<lambda>>, 'INSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'LOCATE': <function Parser.<lambda>>, '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.UNION: 'UNION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>}
NESTED_TYPE_TOKENS = {<TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LIST: 'LIST'>, <TokenType.UNION: 'UNION'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DYNAMIC: 'DYNAMIC'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.YEAR: 'YEAR'>, <TokenType.BIT: 'BIT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TIME: 'TIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DATE: 'DATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UUID: 'UUID'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
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'>, <TokenType.DOUBLE: 'DOUBLE'>: <TokenType.UDOUBLE: 'UDOUBLE'>}
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.DOT: 'DOT'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.LT: 'LT'>, <TokenType.HASH: 'HASH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.PIPE: 'PIPE'>, <TokenType.MOD: 'MOD'>, <TokenType.GT: 'GT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PLUS: 'PLUS'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.AMP: 'AMP'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.NOT: 'NOT'>, <TokenType.STAR: 'STAR'>, <TokenType.CARET: 'CARET'>, <TokenType.DASH: 'DASH'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.COLON: 'COLON'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.EQ: 'EQ'>, <TokenType.SLASH: 'SLASH'>}
DB_CREATABLES = {<TokenType.SINK: 'SINK'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TAG: 'TAG'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VIEW: 'VIEW'>}
CREATABLES = {<TokenType.SINK: 'SINK'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>}
ALTERABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FULL: 'FULL'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
TABLE_ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FULL: 'FULL'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
TRIM_TYPES = {'TRAILING', 'BOTH', 'LEADING'}
FUNC_TOKENS = {<TokenType.YEAR: 'YEAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BIT: 'BIT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.INDEX: 'INDEX'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TIME: 'TIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RING: 'RING'>, <TokenType.DATE: 'DATE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.INSERT: 'INSERT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UUID: 'UUID'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.XOR: 'XOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIKE: 'LIKE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.GLOB: 'GLOB'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.VAR: 'VAR'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
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'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.INNER: 'INNER'>}
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.DOTCOLON: 'DOTCOLON'>: <function Parser.<lambda>>, <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.Hint'>: <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.Select'>: <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.Tuple'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Whens'>: <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.ANALYZE: 'ANALYZE'>: <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.GRANT: 'GRANT'>: <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.UNPIVOT: 'UNPIVOT'>: <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.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <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.LT_AT: 'LT_AT'>: <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>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <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>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <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>>, 'WATERMARK': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'AS': <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>>, 'SWAP': <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 = {'CHECK', 'UNIQUE', 'PERIOD', 'PRIMARY KEY', 'LIKE', 'EXCLUDE', 'FOREIGN KEY', 'WATERMARK'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <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>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <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>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <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>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <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>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
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': (), 'CATALOG': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
SCHEMA_BINDING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'TYPE': ('EVOLUTION',), 'BINDING': (), 'COMPENSATION': (), 'EVOLUTION': ()}
PROCEDURE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {}
EXECUTE_AS_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'CALLER': (), 'SELF': (), 'OWNER': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'ROLLBACK', 'FAIL', 'IGNORE', 'REPLACE', 'ABORT'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_PREFIX = {'BEFORE', 'END', 'AT'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'STATEMENT', 'STREAM', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'WITH', '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 = {'SCHEMABINDING', 'ENCRYPTION', 'VIEW_METADATA'}
WINDOW_ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FULL: 'FULL'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.IS: 'IS'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FULL: 'FULL'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.KEY: 'KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.SINK: 'SINK'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BIT: 'BIT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COPY: 'COPY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UINT: 'UINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FULL: 'FULL'>, <TokenType.CASE: 'CASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IS: 'IS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SOME: 'SOME'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TOP: 'TOP'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TIME: 'TIME'>, <TokenType.USE: 'USE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NESTED: 'NESTED'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT128: 'INT128'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DATE: 'DATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LIST: 'LIST'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.MAP: 'MAP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.RENAME: 'RENAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ASC: 'ASC'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.INET: 'INET'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.POINT: 'POINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DESC: 'DESC'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TAG: 'TAG'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NAME: 'NAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SET: 'SET'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSON: 'JSON'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT256: 'INT256'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROW: 'ROW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.VAR: 'VAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.CUBE: 'CUBE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DETACH: 'DETACH'>, <TokenType.END: 'END'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
SELECT_START_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'CREDENTIAL', 'FORMAT_OPTIONS', 'COPY_OPTIONS'}
IS_JSON_PREDICATE_KIND = {'VALUE', 'SCALAR', 'ARRAY', 'OBJECT'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'NULL', 'ERROR', 'EMPTY', 'FALSE', 'TRUE'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.ON: 'ON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>}
DESCRIBE_STYLES = {'HISTORY', 'ANALYZE', 'EXTENDED', 'FORMATTED'}
ANALYZE_STYLES = {'FULL', 'SAMPLE', 'LOCAL', 'BUFFER_USAGE_LIMIT', 'NO_WRITE_TO_BINLOG', 'VERBOSE', 'SKIP_LOCKED'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'PARTITION', 'SUBPARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {'CYCLE', 'BREADTH', 'DEPTH'}
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 = {'offset', 'limit', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = True
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): View Source

    1475    def reset(self):
    1476        self.sql = ""
    1477        self.errors = []
    1478        self._tokens = []
    1479        self._index = 0
    1480        self._curr = None
    1481        self._next = None
    1482        self._prev = None
    1483        self._prev_comments = None

def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]: View Source

    1485    def parse(
    1486        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1487    ) -> t.List[t.Optional[exp.Expression]]:
    1488        """
    1489        Parses a list of tokens and returns a list of syntax trees, one tree
    1490        per parsed SQL statement.
    1491
    1492        Args:
    1493            raw_tokens: The list of tokens.
    1494            sql: The original SQL string, used to produce helpful debug messages.
    1495
    1496        Returns:
    1497            The list of the produced syntax trees.
    1498        """
    1499        return self._parse(
    1500            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1501        )

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]]: View Source

    1503    def parse_into(
    1504        self,
    1505        expression_types: exp.IntoType,
    1506        raw_tokens: t.List[Token],
    1507        sql: t.Optional[str] = None,
    1508    ) -> t.List[t.Optional[exp.Expression]]:
    1509        """
    1510        Parses a list of tokens into a given Expression type. If a collection of Expression
    1511        types is given instead, this method will try to parse the token list into each one
    1512        of them, stopping at the first for which the parsing succeeds.
    1513
    1514        Args:
    1515            expression_types: The expression type(s) to try and parse the token list into.
    1516            raw_tokens: The list of tokens.
    1517            sql: The original SQL string, used to produce helpful debug messages.
    1518
    1519        Returns:
    1520            The target Expression.
    1521        """
    1522        errors = []
    1523        for expression_type in ensure_list(expression_types):
    1524            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1525            if not parser:
    1526                raise TypeError(f"No parser registered for {expression_type}")
    1527
    1528            try:
    1529                return self._parse(parser, raw_tokens, sql)
    1530            except ParseError as e:
    1531                e.errors[0]["into_expression"] = expression_type
    1532                errors.append(e)
    1533
    1534        raise ParseError(
    1535            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1536            errors=merge_errors(errors),
    1537        ) 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: View Source

    1577    def check_errors(self) -> None:
    1578        """Logs or raises any found errors, depending on the chosen error level setting."""
    1579        if self.error_level == ErrorLevel.WARN:
    1580            for error in self.errors:
    1581                logger.error(str(error))
    1582        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1583            raise ParseError(
    1584                concat_messages(self.errors, self.max_errors),
    1585                errors=merge_errors(self.errors),
    1586            )

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: View Source

    1588    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1589        """
    1590        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1591        error level setting.
    1592        """
    1593        token = token or self._curr or self._prev or Token.string("")
    1594        start = token.start
    1595        end = token.end + 1
    1596        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1597        highlight = self.sql[start:end]
    1598        end_context = self.sql[end : end + self.error_message_context]
    1599
    1600        error = ParseError.new(
    1601            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1602            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1603            description=message,
    1604            line=token.line,
    1605            col=token.col,
    1606            start_context=start_context,
    1607            highlight=highlight,
    1608            end_context=end_context,
    1609        )
    1610
    1611        if self.error_level == ErrorLevel.IMMEDIATE:
    1612            raise error
    1613
    1614        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: View Source

    1616    def expression(
    1617        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1618    ) -> E:
    1619        """
    1620        Creates a new, validated Expression.
    1621
    1622        Args:
    1623            exp_class: The expression class to instantiate.
    1624            comments: An optional list of comments to attach to the expression.
    1625            kwargs: The arguments to set for the expression along with their respective values.
    1626
    1627        Returns:
    1628            The target expression.
    1629        """
    1630        instance = exp_class(**kwargs)
    1631        instance.add_comments(comments) if comments else self._add_comments(instance)
    1632        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: View Source

    1639    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1640        """
    1641        Validates an Expression, making sure that all its mandatory arguments are set.
    1642
    1643        Args:
    1644            expression: The expression to validate.
    1645            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1646
    1647        Returns:
    1648            The validated expression.
    1649        """
    1650        if self.error_level != ErrorLevel.IGNORE:
    1651            for error_message in expression.error_messages(args):
    1652                self.raise_error(error_message)
    1653
    1654        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