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

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

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

    1048    def __init__(
    1049        self,
    1050        error_level: t.Optional[ErrorLevel] = None,
    1051        error_message_context: int = 100,
    1052        max_errors: int = 3,
    1053        dialect: DialectType = None,
    1054    ):
    1055        from sqlglot.dialects import Dialect
    1056
    1057        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1058        self.error_message_context = error_message_context
    1059        self.max_errors = max_errors
    1060        self.dialect = Dialect.get_or_raise(dialect)
    1061        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_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, '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_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'>>, '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.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.MAP: 'MAP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ARRAY: 'ARRAY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UINT: 'UINT'>, <TokenType.INT256: 'INT256'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.MAP: 'MAP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>}
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.TILDA: 'TILDA'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.HASH: 'HASH'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PIPE: 'PIPE'>, <TokenType.LT: 'LT'>, <TokenType.MOD: 'MOD'>, <TokenType.GT: 'GT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.SELECT: 'SELECT'>, <TokenType.EQ: 'EQ'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.DASH: 'DASH'>, <TokenType.STAR: 'STAR'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.COMMA: 'COMMA'>, <TokenType.NOT: 'NOT'>, <TokenType.DOT: 'DOT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.AMP: 'AMP'>, <TokenType.SLASH: 'SLASH'>, <TokenType.CARET: 'CARET'>, <TokenType.COLON: 'COLON'>}
DB_CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATABASE: 'DATABASE'>}
CREATABLES = {<TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DATABASE: 'DATABASE'>}
ID_VAR_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
INTERVAL_VARS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
TABLE_ALIAS_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.DEFAULT: 'DEFAULT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.DEFAULT: 'DEFAULT'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UINT: 'UINT'>, <TokenType.XOR: 'XOR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.GLOB: 'GLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.INSERT: 'INSERT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.LIKE: 'LIKE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>}
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.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INNER: 'INNER'>, <TokenType.OUTER: 'OUTER'>, <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>>}
PRIMARY_PARSERS = {<TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <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>>, '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>>, '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>>, '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>>, '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>>, '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 = {'FOREIGN KEY', 'UNIQUE', 'PRIMARY KEY', 'PERIOD', 'CHECK', 'LIKE'}
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.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'DEFERRED', 'EXCLUSIVE', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
INSERT_ALTERNATIVES = {'IGNORE', 'ROLLBACK', 'REPLACE', 'FAIL', 'ABORT'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'STREAM', 'TIMESTAMP', 'STATEMENT', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'NULLS', 'DESC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.VAR: 'VAR'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UINT: 'UINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT256: 'INT256'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ANTI: 'ANTI'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROW: 'ROW'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IS: 'IS'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ASC: 'ASC'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.KILL: 'KILL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SET: 'SET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BIT: 'BIT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UINT256: 'UINT256'>, <TokenType.SOME: 'SOME'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.JSON: 'JSON'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DESC: 'DESC'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DIV: 'DIV'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATE: 'DATE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.MAP: 'MAP'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.END: 'END'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DEFAULT: 'DEFAULT'>}
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

    1063    def reset(self):
    1064        self.sql = ""
    1065        self.errors = []
    1066        self._tokens = []
    1067        self._index = 0
    1068        self._curr = None
    1069        self._next = None
    1070        self._prev = None
    1071        self._prev_comments = None

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

    1073    def parse(
    1074        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1075    ) -> t.List[t.Optional[exp.Expression]]:
    1076        """
    1077        Parses a list of tokens and returns a list of syntax trees, one tree
    1078        per parsed SQL statement.
    1079
    1080        Args:
    1081            raw_tokens: The list of tokens.
    1082            sql: The original SQL string, used to produce helpful debug messages.
    1083
    1084        Returns:
    1085            The list of the produced syntax trees.
    1086        """
    1087        return self._parse(
    1088            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1089        )

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

    1091    def parse_into(
    1092        self,
    1093        expression_types: exp.IntoType,
    1094        raw_tokens: t.List[Token],
    1095        sql: t.Optional[str] = None,
    1096    ) -> t.List[t.Optional[exp.Expression]]:
    1097        """
    1098        Parses a list of tokens into a given Expression type. If a collection of Expression
    1099        types is given instead, this method will try to parse the token list into each one
    1100        of them, stopping at the first for which the parsing succeeds.
    1101
    1102        Args:
    1103            expression_types: The expression type(s) to try and parse the token list into.
    1104            raw_tokens: The list of tokens.
    1105            sql: The original SQL string, used to produce helpful debug messages.
    1106
    1107        Returns:
    1108            The target Expression.
    1109        """
    1110        errors = []
    1111        for expression_type in ensure_list(expression_types):
    1112            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1113            if not parser:
    1114                raise TypeError(f"No parser registered for {expression_type}")
    1115
    1116            try:
    1117                return self._parse(parser, raw_tokens, sql)
    1118            except ParseError as e:
    1119                e.errors[0]["into_expression"] = expression_type
    1120                errors.append(e)
    1121
    1122        raise ParseError(
    1123            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1124            errors=merge_errors(errors),
    1125        ) 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

    1162    def check_errors(self) -> None:
    1163        """Logs or raises any found errors, depending on the chosen error level setting."""
    1164        if self.error_level == ErrorLevel.WARN:
    1165            for error in self.errors:
    1166                logger.error(str(error))
    1167        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1168            raise ParseError(
    1169                concat_messages(self.errors, self.max_errors),
    1170                errors=merge_errors(self.errors),
    1171            )

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

    1173    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1174        """
    1175        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1176        error level setting.
    1177        """
    1178        token = token or self._curr or self._prev or Token.string("")
    1179        start = token.start
    1180        end = token.end + 1
    1181        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1182        highlight = self.sql[start:end]
    1183        end_context = self.sql[end : end + self.error_message_context]
    1184
    1185        error = ParseError.new(
    1186            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1187            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1188            description=message,
    1189            line=token.line,
    1190            col=token.col,
    1191            start_context=start_context,
    1192            highlight=highlight,
    1193            end_context=end_context,
    1194        )
    1195
    1196        if self.error_level == ErrorLevel.IMMEDIATE:
    1197            raise error
    1198
    1199        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

    1201    def expression(
    1202        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1203    ) -> E:
    1204        """
    1205        Creates a new, validated Expression.
    1206
    1207        Args:
    1208            exp_class: The expression class to instantiate.
    1209            comments: An optional list of comments to attach to the expression.
    1210            kwargs: The arguments to set for the expression along with their respective values.
    1211
    1212        Returns:
    1213            The target expression.
    1214        """
    1215        instance = exp_class(**kwargs)
    1216        instance.add_comments(comments) if comments else self._add_comments(instance)
    1217        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

    1224    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1225        """
    1226        Validates an Expression, making sure that all its mandatory arguments are set.
    1227
    1228        Args:
    1229            expression: The expression to validate.
    1230            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1231
    1232        Returns:
    1233            The validated expression.
    1234        """
    1235        if self.error_level != ErrorLevel.IGNORE:
    1236            for error_message in expression.error_messages(args):
    1237                self.raise_error(error_message)
    1238
    1239        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