sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

class Parser: View Source

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

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

    1262    def __init__(
    1263        self,
    1264        error_level: t.Optional[ErrorLevel] = None,
    1265        error_message_context: int = 100,
    1266        max_errors: int = 3,
    1267        dialect: DialectType = None,
    1268    ):
    1269        from sqlglot.dialects import Dialect
    1270
    1271        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1272        self.error_message_context = error_message_context
    1273        self.max_errors = max_errors
    1274        self.dialect = Dialect.get_or_raise(dialect)
    1275        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONSTRUCT_COMPACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConstructCompact'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_HAS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_CONTAINS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'ARRAY_HAS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Datetime'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <function build_hex>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'LPAD': <function Parser.<lambda>>, 'LEFTPAD': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'RPAD': <function Parser.<lambda>>, 'RIGHTPAD': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.LIST: 'LIST'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UUID: 'UUID'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IPV4: 'IPV4'>}
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.STAR: 'STAR'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.SLASH: 'SLASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.LT: 'LT'>, <TokenType.DOT: 'DOT'>, <TokenType.HASH: 'HASH'>, <TokenType.CARET: 'CARET'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PLUS: 'PLUS'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.DASH: 'DASH'>, <TokenType.EQ: 'EQ'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.MOD: 'MOD'>, <TokenType.AMP: 'AMP'>, <TokenType.GT: 'GT'>, <TokenType.COLON: 'COLON'>, <TokenType.NOT: 'NOT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.PARAMETER: 'PARAMETER'>}
DB_CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TAG: 'TAG'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.MODEL: 'MODEL'>}
CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TAG: 'TAG'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VIEW: 'VIEW'>}
ID_VAR_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
INTERVAL_VARS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
TABLE_ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
UPDATE_ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.XOR: 'XOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GLOB: 'GLOB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NULL: 'NULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.VAR: 'VAR'>, <TokenType.NAME: 'NAME'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INSERT: 'INSERT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>}
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.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>, <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.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.CROSS: 'CROSS'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.OUTER: 'OUTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.INNER: 'INNER'>, <TokenType.SEMI: 'SEMI'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Select'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PERIOD', 'CHECK', 'UNIQUE', 'LIKE', 'EXCLUDE', 'PRIMARY KEY', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'DEFERRED', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
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': ()}
INSERT_ALTERNATIVES = {'ABORT', 'IGNORE', 'ROLLBACK', 'REPLACE', 'FAIL'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'END', 'BEFORE', 'AT'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'OFFSET', 'STREAM', 'STATEMENT'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'NULLS', 'WITH', 'ASC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>}
FETCH_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.KEY: 'KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNIQUE: 'UNIQUE'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIME: 'TIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.END: 'END'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DESC: 'DESC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UUID: 'UUID'>, <TokenType.SOME: 'SOME'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INET: 'INET'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LIST: 'LIST'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.USE: 'USE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.SET: 'SET'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FULL: 'FULL'>, <TokenType.MODEL: 'MODEL'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COPY: 'COPY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.JSON: 'JSON'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NEXT: 'NEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.KILL: 'KILL'>, <TokenType.CASE: 'CASE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.NULL: 'NULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TOP: 'TOP'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TEXT: 'TEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.KEEP: 'KEEP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VAR: 'VAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.JSONB: 'JSONB'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TAG: 'TAG'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IS: 'IS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.REFERENCES: 'REFERENCES'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'FORMAT_OPTIONS', 'CREDENTIAL', 'COPY_OPTIONS'}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'limit', 'offset', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self): View Source

    1277    def reset(self):
    1278        self.sql = ""
    1279        self.errors = []
    1280        self._tokens = []
    1281        self._index = 0
    1282        self._curr = None
    1283        self._next = None
    1284        self._prev = None
    1285        self._prev_comments = None

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

    1287    def parse(
    1288        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1289    ) -> t.List[t.Optional[exp.Expression]]:
    1290        """
    1291        Parses a list of tokens and returns a list of syntax trees, one tree
    1292        per parsed SQL statement.
    1293
    1294        Args:
    1295            raw_tokens: The list of tokens.
    1296            sql: The original SQL string, used to produce helpful debug messages.
    1297
    1298        Returns:
    1299            The list of the produced syntax trees.
    1300        """
    1301        return self._parse(
    1302            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1303        )

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

    1305    def parse_into(
    1306        self,
    1307        expression_types: exp.IntoType,
    1308        raw_tokens: t.List[Token],
    1309        sql: t.Optional[str] = None,
    1310    ) -> t.List[t.Optional[exp.Expression]]:
    1311        """
    1312        Parses a list of tokens into a given Expression type. If a collection of Expression
    1313        types is given instead, this method will try to parse the token list into each one
    1314        of them, stopping at the first for which the parsing succeeds.
    1315
    1316        Args:
    1317            expression_types: The expression type(s) to try and parse the token list into.
    1318            raw_tokens: The list of tokens.
    1319            sql: The original SQL string, used to produce helpful debug messages.
    1320
    1321        Returns:
    1322            The target Expression.
    1323        """
    1324        errors = []
    1325        for expression_type in ensure_list(expression_types):
    1326            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1327            if not parser:
    1328                raise TypeError(f"No parser registered for {expression_type}")
    1329
    1330            try:
    1331                return self._parse(parser, raw_tokens, sql)
    1332            except ParseError as e:
    1333                e.errors[0]["into_expression"] = expression_type
    1334                errors.append(e)
    1335
    1336        raise ParseError(
    1337            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1338            errors=merge_errors(errors),
    1339        ) 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

    1379    def check_errors(self) -> None:
    1380        """Logs or raises any found errors, depending on the chosen error level setting."""
    1381        if self.error_level == ErrorLevel.WARN:
    1382            for error in self.errors:
    1383                logger.error(str(error))
    1384        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1385            raise ParseError(
    1386                concat_messages(self.errors, self.max_errors),
    1387                errors=merge_errors(self.errors),
    1388            )

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

    1390    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1391        """
    1392        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1393        error level setting.
    1394        """
    1395        token = token or self._curr or self._prev or Token.string("")
    1396        start = token.start
    1397        end = token.end + 1
    1398        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1399        highlight = self.sql[start:end]
    1400        end_context = self.sql[end : end + self.error_message_context]
    1401
    1402        error = ParseError.new(
    1403            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1404            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1405            description=message,
    1406            line=token.line,
    1407            col=token.col,
    1408            start_context=start_context,
    1409            highlight=highlight,
    1410            end_context=end_context,
    1411        )
    1412
    1413        if self.error_level == ErrorLevel.IMMEDIATE:
    1414            raise error
    1415
    1416        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

    1418    def expression(
    1419        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1420    ) -> E:
    1421        """
    1422        Creates a new, validated Expression.
    1423
    1424        Args:
    1425            exp_class: The expression class to instantiate.
    1426            comments: An optional list of comments to attach to the expression.
    1427            kwargs: The arguments to set for the expression along with their respective values.
    1428
    1429        Returns:
    1430            The target expression.
    1431        """
    1432        instance = exp_class(**kwargs)
    1433        instance.add_comments(comments) if comments else self._add_comments(instance)
    1434        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

    1441    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1442        """
    1443        Validates an Expression, making sure that all its mandatory arguments are set.
    1444
    1445        Args:
    1446            expression: The expression to validate.
    1447            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1448
    1449        Returns:
    1450            The validated expression.
    1451        """
    1452        if self.error_level != ErrorLevel.IGNORE:
    1453            for error_message in expression.error_messages(args):
    1454                self.raise_error(error_message)
    1455
    1456        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