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

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

    26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    27    if len(args) == 1 and args[0].is_star:
    28        return exp.StarMap(this=args[0])
    29
    30    keys = []
    31    values = []
    32    for i in range(0, len(args), 2):
    33        keys.append(args[i])
    34        values.append(args[i + 1])
    35
    36    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))

def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like: View Source

    39def build_like(args: t.List) -> exp.Escape | exp.Like:
    40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    41    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like

def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]: View Source

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

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

    58def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    59    # Default argument order is base, expression
    60    this = seq_get(args, 0)
    61    expression = seq_get(args, 1)
    62
    63    if expression:
    64        if not dialect.LOG_BASE_FIRST:
    65            this, expression = expression, this
    66        return exp.Log(this=this, expression=expression)
    67
    68    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)

def build_hex( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex: View Source

    71def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
    72    arg = seq_get(args, 0)
    73    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)

def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex: View Source

    76def build_lower(args: t.List) -> exp.Lower | exp.Hex:
    77    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
    78    arg = seq_get(args, 0)
    79    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)

def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex: View Source

    82def build_upper(args: t.List) -> exp.Upper | exp.Hex:
    83    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
    84    arg = seq_get(args, 0)
    85    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)

def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]: View Source

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

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

    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)

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

    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    )

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

    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

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

    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)

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

    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    )

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

    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)

class Parser: View Source

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

Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.

###### Arguments:

- error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
- error_message_context: The amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
- max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3

Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) View Source

    1356    def __init__(
    1357        self,
    1358        error_level: t.Optional[ErrorLevel] = None,
    1359        error_message_context: int = 100,
    1360        max_errors: int = 3,
    1361        dialect: DialectType = None,
    1362    ):
    1363        from sqlglot.dialects import Dialect
    1364
    1365        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1366        self.error_message_context = error_message_context
    1367        self.max_errors = max_errors
    1368        self.dialect = Dialect.get_or_raise(dialect)
    1369        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, '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'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, '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_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Datetime'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, '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'>>, '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'>>, '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'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, '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_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, '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'>>, '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_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, '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_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_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UNPACK_COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnpackColumns'>>, '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'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, '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>>, '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.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UNION: 'UNION'>}
NESTED_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.LIST: 'LIST'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UNION: 'UNION'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNION: 'UNION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.XML: 'XML'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.SLASH: 'SLASH'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.NOT: 'NOT'>, <TokenType.STAR: 'STAR'>, <TokenType.CARET: 'CARET'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.DASH: 'DASH'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.LT: 'LT'>, <TokenType.COLON: 'COLON'>, <TokenType.EQ: 'EQ'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.HASH: 'HASH'>, <TokenType.MOD: 'MOD'>, <TokenType.AMP: 'AMP'>, <TokenType.GT: 'GT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PIPE: 'PIPE'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.DOT: 'DOT'>, <TokenType.L_BRACE: 'L_BRACE'>}
DB_CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TAG: 'TAG'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.STREAMLIT: 'STREAMLIT'>}
CREATABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TAG: 'TAG'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ALTERABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>}
ID_VAR_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
INTERVAL_VARS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
TABLE_ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.ISNULL: 'ISNULL'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNION: 'UNION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.ROW: 'ROW'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GLOB: 'GLOB'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.XOR: 'XOR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.INSERT: 'INSERT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>}
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.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.OUTER: 'OUTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CROSS: 'CROSS'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.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.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.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.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, '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>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'AS': <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', 'PERIOD', 'PRIMARY KEY', 'UNIQUE', 'LIKE', 'FOREIGN KEY', 'EXCLUDE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
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': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'ABORT', 'REPLACE', 'IGNORE', 'FAIL', 'ROLLBACK'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'BEFORE', 'END', 'AT'}
HISTORICAL_DATA_KIND = {'STREAM', 'TIMESTAMP', 'OFFSET', 'STATEMENT'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'NULLS', 'DESC', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
VIEW_ATTRIBUTES = {'VIEW_METADATA', 'SCHEMABINDING', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
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.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.INDEX: 'INDEX'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.KEY: 'KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.COLUMN: 'COLUMN'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.USE: 'USE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DESC: 'DESC'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UINT: 'UINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CUBE: 'CUBE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.LIST: 'LIST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COPY: 'COPY'>, <TokenType.IS: 'IS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DIV: 'DIV'>, <TokenType.KILL: 'KILL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.INT256: 'INT256'>, <TokenType.JSON: 'JSON'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UUID: 'UUID'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TIME: 'TIME'>, <TokenType.INT: 'INT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TRUE: 'TRUE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TOP: 'TOP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CACHE: 'CACHE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SET: 'SET'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.MAP: 'MAP'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FALSE: 'FALSE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RENAME: 'RENAME'>, <TokenType.FULL: 'FULL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NAME: 'NAME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DELETE: 'DELETE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TAG: 'TAG'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
SELECT_START_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'CREDENTIAL', 'COPY_OPTIONS', 'FORMAT_OPTIONS'}
IS_JSON_PREDICATE_KIND = {'VALUE', 'ARRAY', 'SCALAR', 'OBJECT'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'TRUE', 'EMPTY', 'NULL', 'ERROR', 'FALSE'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.ON: 'ON'>}
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 = {'order', 'limit', 'offset'}
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
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

    1371    def reset(self):
    1372        self.sql = ""
    1373        self.errors = []
    1374        self._tokens = []
    1375        self._index = 0
    1376        self._curr = None
    1377        self._next = None
    1378        self._prev = None
    1379        self._prev_comments = None

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

    1381    def parse(
    1382        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1383    ) -> t.List[t.Optional[exp.Expression]]:
    1384        """
    1385        Parses a list of tokens and returns a list of syntax trees, one tree
    1386        per parsed SQL statement.
    1387
    1388        Args:
    1389            raw_tokens: The list of tokens.
    1390            sql: The original SQL string, used to produce helpful debug messages.
    1391
    1392        Returns:
    1393            The list of the produced syntax trees.
    1394        """
    1395        return self._parse(
    1396            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1397        )

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

    1399    def parse_into(
    1400        self,
    1401        expression_types: exp.IntoType,
    1402        raw_tokens: t.List[Token],
    1403        sql: t.Optional[str] = None,
    1404    ) -> t.List[t.Optional[exp.Expression]]:
    1405        """
    1406        Parses a list of tokens into a given Expression type. If a collection of Expression
    1407        types is given instead, this method will try to parse the token list into each one
    1408        of them, stopping at the first for which the parsing succeeds.
    1409
    1410        Args:
    1411            expression_types: The expression type(s) to try and parse the token list into.
    1412            raw_tokens: The list of tokens.
    1413            sql: The original SQL string, used to produce helpful debug messages.
    1414
    1415        Returns:
    1416            The target Expression.
    1417        """
    1418        errors = []
    1419        for expression_type in ensure_list(expression_types):
    1420            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1421            if not parser:
    1422                raise TypeError(f"No parser registered for {expression_type}")
    1423
    1424            try:
    1425                return self._parse(parser, raw_tokens, sql)
    1426            except ParseError as e:
    1427                e.errors[0]["into_expression"] = expression_type
    1428                errors.append(e)
    1429
    1430        raise ParseError(
    1431            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1432            errors=merge_errors(errors),
    1433        ) 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

    1473    def check_errors(self) -> None:
    1474        """Logs or raises any found errors, depending on the chosen error level setting."""
    1475        if self.error_level == ErrorLevel.WARN:
    1476            for error in self.errors:
    1477                logger.error(str(error))
    1478        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1479            raise ParseError(
    1480                concat_messages(self.errors, self.max_errors),
    1481                errors=merge_errors(self.errors),
    1482            )

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

    1484    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1485        """
    1486        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1487        error level setting.
    1488        """
    1489        token = token or self._curr or self._prev or Token.string("")
    1490        start = token.start
    1491        end = token.end + 1
    1492        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1493        highlight = self.sql[start:end]
    1494        end_context = self.sql[end : end + self.error_message_context]
    1495
    1496        error = ParseError.new(
    1497            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1498            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1499            description=message,
    1500            line=token.line,
    1501            col=token.col,
    1502            start_context=start_context,
    1503            highlight=highlight,
    1504            end_context=end_context,
    1505        )
    1506
    1507        if self.error_level == ErrorLevel.IMMEDIATE:
    1508            raise error
    1509
    1510        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

    1512    def expression(
    1513        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1514    ) -> E:
    1515        """
    1516        Creates a new, validated Expression.
    1517
    1518        Args:
    1519            exp_class: The expression class to instantiate.
    1520            comments: An optional list of comments to attach to the expression.
    1521            kwargs: The arguments to set for the expression along with their respective values.
    1522
    1523        Returns:
    1524            The target expression.
    1525        """
    1526        instance = exp_class(**kwargs)
    1527        instance.add_comments(comments) if comments else self._add_comments(instance)
    1528        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

    1535    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1536        """
    1537        Validates an Expression, making sure that all its mandatory arguments are set.
    1538
    1539        Args:
    1540            expression: The expression to validate.
    1541            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1542
    1543        Returns:
    1544            The validated expression.
    1545        """
    1546        if self.error_level != ErrorLevel.IGNORE:
    1547            for error_message in expression.error_messages(args):
    1548                self.raise_error(error_message)
    1549
    1550        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