sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

class Parser: View Source

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

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

    1438    def __init__(
    1439        self,
    1440        error_level: t.Optional[ErrorLevel] = None,
    1441        error_message_context: int = 100,
    1442        max_errors: int = 3,
    1443        dialect: DialectType = None,
    1444    ):
    1445        from sqlglot.dialects import Dialect
    1446
    1447        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1448        self.error_message_context = error_message_context
    1449        self.max_errors = max_errors
    1450        self.dialect = Dialect.get_or_raise(dialect)
    1451        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'>>, 'COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Columns'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Contains'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_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'>>, 'EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exists'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXPLODING_GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodingGenerateSeries'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FEATURES_AT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FeaturesAtTime'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'FROM_ISO8601_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromISO8601Timestamp'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <function Parser.<lambda>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GENERATE_TIMESTAMP_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateTimestampArray'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <function build_hex>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'INLINE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Inline'>>, 'INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Int64'>>, 'IS_ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsAscii'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExists'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'J_S_O_N_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractArray'>>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHAR_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHARACTER_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAKE_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MakeInterval'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MEDIAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Median'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NORMALIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Normalize'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OBJECT_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ObjectInsert'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'OVERLAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Overlay'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_EXTRACT_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtractAll'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUBSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDatetime'>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNICODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unicode'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_SECONDS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixSeconds'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GEN_RANDOM_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GENERATE_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'UUID_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'VAR_MAP': <function build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'XMLELEMENT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLElement'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'ARRAYAGG': <function Parser.<lambda>>, 'GLOB': <function Parser.<lambda>>, 'INSTR': <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.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UNION: 'UNION'>}
NESTED_TYPE_TOKENS = {<TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UNION: 'UNION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RANGE: 'RANGE'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UNION: 'UNION'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.JSON: 'JSON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.UINT: 'UINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
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.LT: 'LT'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.TILDA: 'TILDA'>, <TokenType.GT: 'GT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.STAR: 'STAR'>, <TokenType.HASH: 'HASH'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.DASH: 'DASH'>, <TokenType.DOT: 'DOT'>, <TokenType.AMP: 'AMP'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.COLON: 'COLON'>, <TokenType.NOT: 'NOT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.CARET: 'CARET'>, <TokenType.EQ: 'EQ'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.MOD: 'MOD'>}
DB_CREATABLES = {<TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SINK: 'SINK'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TAG: 'TAG'>, <TokenType.TABLE: 'TABLE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SOURCE: 'SOURCE'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SINK: 'SINK'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>}
ALTERABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
INTERVAL_VARS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
TABLE_ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.ILIKE: 'ILIKE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.XOR: 'XOR'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UNION: 'UNION'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.LIKE: 'LIKE'>, <TokenType.BIT: 'BIT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.GLOB: 'GLOB'>, <TokenType.INSERT: 'INSERT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FIRST: 'FIRST'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
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.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.ANTI: 'ANTI'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Hint'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Select'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Tuple'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Whens'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.ANALYZE: 'ANALYZE'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.GRANT: 'GRANT'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UNPIVOT: 'UNPIVOT'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.LT_AT: 'LT_AT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WATERMARK': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'AS': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SWAP': <function Parser.<lambda>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'LIKE', 'WATERMARK', 'PERIOD', 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE', 'EXCLUDE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.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>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'IMMEDIATE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': (), 'CATALOG': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
SCHEMA_BINDING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'TYPE': ('EVOLUTION',), 'BINDING': (), 'COMPENSATION': (), 'EVOLUTION': ()}
PROCEDURE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {}
EXECUTE_AS_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'CALLER': (), 'SELF': (), 'OWNER': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'FAIL', 'IGNORE', 'ROLLBACK', 'REPLACE', 'ABORT'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'AT', 'BEFORE', 'END'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'OFFSET', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'WITH', 'DESC', 'NULLS'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>, <TokenType.IGNORE: 'IGNORE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COLON: 'COLON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.IS: 'IS'>}
FETCH_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.KEY: 'KEY'>, <TokenType.UNIQUE: 'UNIQUE'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.CUBE: 'CUBE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DETACH: 'DETACH'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT128: 'INT128'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CASE: 'CASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIT: 'BIT'>, <TokenType.RING: 'RING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.SOME: 'SOME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TOP: 'TOP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ROW: 'ROW'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESC: 'DESC'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ALL: 'ALL'>, <TokenType.ANY: 'ANY'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.KILL: 'KILL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SHOW: 'SHOW'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.INT: 'INT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LIST: 'LIST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.END: 'END'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.COPY: 'COPY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.DIV: 'DIV'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ASC: 'ASC'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ASOF: 'ASOF'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FULL: 'FULL'>, <TokenType.VAR: 'VAR'>, <TokenType.JSON: 'JSON'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.INDEX: 'INDEX'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NAME: 'NAME'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TABLE: 'TABLE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>}
COPY_INTO_VARLEN_OPTIONS = {'COPY_OPTIONS', 'FORMAT_OPTIONS', 'FILE_FORMAT', 'CREDENTIAL'}
IS_JSON_PREDICATE_KIND = {'ARRAY', 'VALUE', 'SCALAR', 'OBJECT'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'NULL', 'FALSE', 'EMPTY', 'ERROR', 'TRUE'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.ON: 'ON'>, <TokenType.COMMA: 'COMMA'>}
DESCRIBE_STYLES = {'HISTORY', 'ANALYZE', 'EXTENDED', 'FORMATTED'}
ANALYZE_STYLES = {'VERBOSE', 'SAMPLE', 'SKIP_LOCKED', 'NO_WRITE_TO_BINLOG', 'BUFFER_USAGE_LIMIT', 'FULL', 'LOCAL'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'PARTITION', 'SUBPARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
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
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = 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

    1453    def reset(self):
    1454        self.sql = ""
    1455        self.errors = []
    1456        self._tokens = []
    1457        self._index = 0
    1458        self._curr = None
    1459        self._next = None
    1460        self._prev = None
    1461        self._prev_comments = None

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

    1463    def parse(
    1464        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1465    ) -> t.List[t.Optional[exp.Expression]]:
    1466        """
    1467        Parses a list of tokens and returns a list of syntax trees, one tree
    1468        per parsed SQL statement.
    1469
    1470        Args:
    1471            raw_tokens: The list of tokens.
    1472            sql: The original SQL string, used to produce helpful debug messages.
    1473
    1474        Returns:
    1475            The list of the produced syntax trees.
    1476        """
    1477        return self._parse(
    1478            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1479        )

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

    1481    def parse_into(
    1482        self,
    1483        expression_types: exp.IntoType,
    1484        raw_tokens: t.List[Token],
    1485        sql: t.Optional[str] = None,
    1486    ) -> t.List[t.Optional[exp.Expression]]:
    1487        """
    1488        Parses a list of tokens into a given Expression type. If a collection of Expression
    1489        types is given instead, this method will try to parse the token list into each one
    1490        of them, stopping at the first for which the parsing succeeds.
    1491
    1492        Args:
    1493            expression_types: The expression type(s) to try and parse the token list into.
    1494            raw_tokens: The list of tokens.
    1495            sql: The original SQL string, used to produce helpful debug messages.
    1496
    1497        Returns:
    1498            The target Expression.
    1499        """
    1500        errors = []
    1501        for expression_type in ensure_list(expression_types):
    1502            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1503            if not parser:
    1504                raise TypeError(f"No parser registered for {expression_type}")
    1505
    1506            try:
    1507                return self._parse(parser, raw_tokens, sql)
    1508            except ParseError as e:
    1509                e.errors[0]["into_expression"] = expression_type
    1510                errors.append(e)
    1511
    1512        raise ParseError(
    1513            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1514            errors=merge_errors(errors),
    1515        ) 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

    1555    def check_errors(self) -> None:
    1556        """Logs or raises any found errors, depending on the chosen error level setting."""
    1557        if self.error_level == ErrorLevel.WARN:
    1558            for error in self.errors:
    1559                logger.error(str(error))
    1560        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1561            raise ParseError(
    1562                concat_messages(self.errors, self.max_errors),
    1563                errors=merge_errors(self.errors),
    1564            )

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

    1566    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1567        """
    1568        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1569        error level setting.
    1570        """
    1571        token = token or self._curr or self._prev or Token.string("")
    1572        start = token.start
    1573        end = token.end + 1
    1574        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1575        highlight = self.sql[start:end]
    1576        end_context = self.sql[end : end + self.error_message_context]
    1577
    1578        error = ParseError.new(
    1579            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1580            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1581            description=message,
    1582            line=token.line,
    1583            col=token.col,
    1584            start_context=start_context,
    1585            highlight=highlight,
    1586            end_context=end_context,
    1587        )
    1588
    1589        if self.error_level == ErrorLevel.IMMEDIATE:
    1590            raise error
    1591
    1592        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

    1594    def expression(
    1595        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1596    ) -> E:
    1597        """
    1598        Creates a new, validated Expression.
    1599
    1600        Args:
    1601            exp_class: The expression class to instantiate.
    1602            comments: An optional list of comments to attach to the expression.
    1603            kwargs: The arguments to set for the expression along with their respective values.
    1604
    1605        Returns:
    1606            The target expression.
    1607        """
    1608        instance = exp_class(**kwargs)
    1609        instance.add_comments(comments) if comments else self._add_comments(instance)
    1610        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

    1617    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1618        """
    1619        Validates an Expression, making sure that all its mandatory arguments are set.
    1620
    1621        Args:
    1622            expression: The expression to validate.
    1623            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1624
    1625        Returns:
    1626            The validated expression.
    1627        """
    1628        if self.error_level != ErrorLevel.IGNORE:
    1629            for error_message in expression.error_messages(args):
    1630                self.raise_error(error_message)
    1631
    1632        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