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

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

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

    37def build_like(args: t.List) -> exp.Escape | exp.Like:
    38    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    39    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]) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]: View Source

    42def binary_range_parser(
    43    expr_type: t.Type[exp.Expression],
    44) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
    45    return lambda self, this: self._parse_escape(
    46        self.expression(expr_type, this=this, expression=self._parse_bitwise())
    47    )

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

    50def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    51    # Default argument order is base, expression
    52    this = seq_get(args, 0)
    53    expression = seq_get(args, 1)
    54
    55    if expression:
    56        if not dialect.LOG_BASE_FIRST:
    57            this, expression = expression, this
    58        return exp.Log(this=this, expression=expression)
    59
    60    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)

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

    63def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
    64    def _builder(args: t.List, dialect: Dialect) -> E:
    65        expression = expr_type(
    66            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
    67        )
    68        if len(args) > 2 and expr_type is exp.JSONExtract:
    69            expression.set("expressions", args[2:])
    70
    71        return expression
    72
    73    return _builder

class Parser: View Source

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

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

    1107    def __init__(
    1108        self,
    1109        error_level: t.Optional[ErrorLevel] = None,
    1110        error_message_context: int = 100,
    1111        max_errors: int = 3,
    1112        dialect: DialectType = None,
    1113    ):
    1114        from sqlglot.dialects import Dialect
    1115
    1116        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1117        self.error_message_context = error_message_context
    1118        self.max_errors = max_errors
    1119        self.dialect = Dialect.get_or_raise(dialect)
    1120        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_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, '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'>>, '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'>>, '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_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'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.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_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'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, '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'>>, '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_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_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_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'>>, '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'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.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>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.ARRAY: 'ARRAY'>, <TokenType.MAP: 'MAP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIME: 'TIME'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UINT: 'UINT'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>}
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.COLON: 'COLON'>, <TokenType.DASH: 'DASH'>, <TokenType.CARET: 'CARET'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.STAR: 'STAR'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.HASH: 'HASH'>, <TokenType.PLUS: 'PLUS'>, <TokenType.NOT: 'NOT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.AMP: 'AMP'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.EQ: 'EQ'>, <TokenType.GT: 'GT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.DOT: 'DOT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.MOD: 'MOD'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.LT: 'LT'>}
DB_CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>}
CREATABLES = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.INDEX: 'INDEX'>}
ID_VAR_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>}
INTERVAL_VARS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>}
TABLE_ALIAS_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.USE: 'USE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.USE: 'USE'>}
TRIM_TYPES = {'BOTH', 'LEADING', 'TRAILING'}
FUNC_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XOR: 'XOR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NAME: 'NAME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.GLOB: 'GLOB'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.UINT: 'UINT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LIKE: 'LIKE'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <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.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.CROSS: 'CROSS'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <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.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <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>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'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>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, '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>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <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>>, '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>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'UNIQUE', 'EXCLUDE', 'LIKE', 'PERIOD', 'PRIMARY KEY', 'CHECK', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
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': ()}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
INSERT_ALTERNATIVES = {'ABORT', 'IGNORE', 'ROLLBACK', 'FAIL', 'REPLACE'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'STREAM', 'OFFSET', 'STATEMENT'}
OPCLASS_FOLLOW_KEYWORDS = {'NULLS', 'ASC', 'DESC', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>}
FETCH_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.COMMIT: 'COMMIT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPV6: 'IPV6'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ASC: 'ASC'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SET: 'SET'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DESC: 'DESC'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.FALSE: 'FALSE'>, <TokenType.INET: 'INET'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DATE32: 'DATE32'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USE: 'USE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.NAME: 'NAME'>, <TokenType.UUID: 'UUID'>, <TokenType.TOP: 'TOP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.INT256: 'INT256'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CASE: 'CASE'>, <TokenType.UINT: 'UINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATE: 'DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROW: 'ROW'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>}
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
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'offset', 'limit', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = 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

    1122    def reset(self):
    1123        self.sql = ""
    1124        self.errors = []
    1125        self._tokens = []
    1126        self._index = 0
    1127        self._curr = None
    1128        self._next = None
    1129        self._prev = None
    1130        self._prev_comments = None

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

    1132    def parse(
    1133        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1134    ) -> t.List[t.Optional[exp.Expression]]:
    1135        """
    1136        Parses a list of tokens and returns a list of syntax trees, one tree
    1137        per parsed SQL statement.
    1138
    1139        Args:
    1140            raw_tokens: The list of tokens.
    1141            sql: The original SQL string, used to produce helpful debug messages.
    1142
    1143        Returns:
    1144            The list of the produced syntax trees.
    1145        """
    1146        return self._parse(
    1147            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1148        )

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

    1150    def parse_into(
    1151        self,
    1152        expression_types: exp.IntoType,
    1153        raw_tokens: t.List[Token],
    1154        sql: t.Optional[str] = None,
    1155    ) -> t.List[t.Optional[exp.Expression]]:
    1156        """
    1157        Parses a list of tokens into a given Expression type. If a collection of Expression
    1158        types is given instead, this method will try to parse the token list into each one
    1159        of them, stopping at the first for which the parsing succeeds.
    1160
    1161        Args:
    1162            expression_types: The expression type(s) to try and parse the token list into.
    1163            raw_tokens: The list of tokens.
    1164            sql: The original SQL string, used to produce helpful debug messages.
    1165
    1166        Returns:
    1167            The target Expression.
    1168        """
    1169        errors = []
    1170        for expression_type in ensure_list(expression_types):
    1171            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1172            if not parser:
    1173                raise TypeError(f"No parser registered for {expression_type}")
    1174
    1175            try:
    1176                return self._parse(parser, raw_tokens, sql)
    1177            except ParseError as e:
    1178                e.errors[0]["into_expression"] = expression_type
    1179                errors.append(e)
    1180
    1181        raise ParseError(
    1182            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1183            errors=merge_errors(errors),
    1184        ) 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

    1221    def check_errors(self) -> None:
    1222        """Logs or raises any found errors, depending on the chosen error level setting."""
    1223        if self.error_level == ErrorLevel.WARN:
    1224            for error in self.errors:
    1225                logger.error(str(error))
    1226        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1227            raise ParseError(
    1228                concat_messages(self.errors, self.max_errors),
    1229                errors=merge_errors(self.errors),
    1230            )

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

    1232    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1233        """
    1234        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1235        error level setting.
    1236        """
    1237        token = token or self._curr or self._prev or Token.string("")
    1238        start = token.start
    1239        end = token.end + 1
    1240        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1241        highlight = self.sql[start:end]
    1242        end_context = self.sql[end : end + self.error_message_context]
    1243
    1244        error = ParseError.new(
    1245            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1246            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1247            description=message,
    1248            line=token.line,
    1249            col=token.col,
    1250            start_context=start_context,
    1251            highlight=highlight,
    1252            end_context=end_context,
    1253        )
    1254
    1255        if self.error_level == ErrorLevel.IMMEDIATE:
    1256            raise error
    1257
    1258        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

    1260    def expression(
    1261        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1262    ) -> E:
    1263        """
    1264        Creates a new, validated Expression.
    1265
    1266        Args:
    1267            exp_class: The expression class to instantiate.
    1268            comments: An optional list of comments to attach to the expression.
    1269            kwargs: The arguments to set for the expression along with their respective values.
    1270
    1271        Returns:
    1272            The target expression.
    1273        """
    1274        instance = exp_class(**kwargs)
    1275        instance.add_comments(comments) if comments else self._add_comments(instance)
    1276        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

    1283    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1284        """
    1285        Validates an Expression, making sure that all its mandatory arguments are set.
    1286
    1287        Args:
    1288            expression: The expression to validate.
    1289            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1290
    1291        Returns:
    1292            The validated expression.
    1293        """
    1294        if self.error_level != ErrorLevel.IGNORE:
    1295            for error_message in expression.error_messages(args):
    1296                self.raise_error(error_message)
    1297
    1298        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