sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

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

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

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

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

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

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

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

    52def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    53    # Default argument order is base, expression
    54    this = seq_get(args, 0)
    55    expression = seq_get(args, 1)
    56
    57    if expression:
    58        if not dialect.LOG_BASE_FIRST:
    59            this, expression = expression, this
    60        return exp.Log(this=this, expression=expression)
    61
    62    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

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

class Parser: View Source

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

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

    1139    def __init__(
    1140        self,
    1141        error_level: t.Optional[ErrorLevel] = None,
    1142        error_message_context: int = 100,
    1143        max_errors: int = 3,
    1144        dialect: DialectType = None,
    1145    ):
    1146        from sqlglot.dialects import Dialect
    1147
    1148        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1149        self.error_message_context = error_message_context
    1150        self.max_errors = max_errors
    1151        self.dialect = Dialect.get_or_raise(dialect)
    1152        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME_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_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <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>, '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'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, '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>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'MOD': <function Parser.<lambda>>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ARRAY: 'ARRAY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DATE: 'DATE'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.STAR: 'STAR'>, <TokenType.DASH: 'DASH'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SLASH: 'SLASH'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>, <TokenType.GT: 'GT'>, <TokenType.CARET: 'CARET'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.NOT: 'NOT'>, <TokenType.EQ: 'EQ'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.LT: 'LT'>, <TokenType.MOD: 'MOD'>, <TokenType.PIPE: 'PIPE'>, <TokenType.AMP: 'AMP'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.DOT: 'DOT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.HASH: 'HASH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.COLON: 'COLON'>}
DB_CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>}
CREATABLES = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FUNCTION: 'FUNCTION'>}
ID_VAR_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
INTERVAL_VARS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
TABLE_ALIAS_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SOME: 'SOME'>}
ALIAS_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SOME: 'SOME'>}
UPDATE_ALIAS_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SOME: 'SOME'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT128: 'INT128'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ANY: 'ANY'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DATE: 'DATE'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.XOR: 'XOR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.GLOB: 'GLOB'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
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.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'FOREIGN KEY', 'PERIOD', 'CHECK', 'LIKE', 'PRIMARY KEY', 'EXCLUDE', 'UNIQUE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
INSERT_ALTERNATIVES = {'FAIL', 'IGNORE', 'REPLACE', 'ROLLBACK', 'ABORT'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'OFFSET', 'TIMESTAMP', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'WITH', 'NULLS', 'DESC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'ENCRYPTION', 'VIEW_METADATA'}
WINDOW_ALIAS_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
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.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.USE: 'USE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.COPY: 'COPY'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UUID: 'UUID'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.XML: 'XML'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IS: 'IS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DIV: 'DIV'>, <TokenType.FINAL: 'FINAL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT128: 'INT128'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TRUE: 'TRUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ANY: 'ANY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT: 'INT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ALL: 'ALL'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CASE: 'CASE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NAME: 'NAME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.DATE: 'DATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UINT: 'UINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INET: 'INET'>, <TokenType.END: 'END'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.VIEW: 'VIEW'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TIME: 'TIME'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULL: 'NULL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.KILL: 'KILL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SOME: 'SOME'>}
SELECT_START_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
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', 'order', 'limit'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self): View Source

    1154    def reset(self):
    1155        self.sql = ""
    1156        self.errors = []
    1157        self._tokens = []
    1158        self._index = 0
    1159        self._curr = None
    1160        self._next = None
    1161        self._prev = None
    1162        self._prev_comments = None

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

    1164    def parse(
    1165        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1166    ) -> t.List[t.Optional[exp.Expression]]:
    1167        """
    1168        Parses a list of tokens and returns a list of syntax trees, one tree
    1169        per parsed SQL statement.
    1170
    1171        Args:
    1172            raw_tokens: The list of tokens.
    1173            sql: The original SQL string, used to produce helpful debug messages.
    1174
    1175        Returns:
    1176            The list of the produced syntax trees.
    1177        """
    1178        return self._parse(
    1179            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1180        )

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

    1182    def parse_into(
    1183        self,
    1184        expression_types: exp.IntoType,
    1185        raw_tokens: t.List[Token],
    1186        sql: t.Optional[str] = None,
    1187    ) -> t.List[t.Optional[exp.Expression]]:
    1188        """
    1189        Parses a list of tokens into a given Expression type. If a collection of Expression
    1190        types is given instead, this method will try to parse the token list into each one
    1191        of them, stopping at the first for which the parsing succeeds.
    1192
    1193        Args:
    1194            expression_types: The expression type(s) to try and parse the token list into.
    1195            raw_tokens: The list of tokens.
    1196            sql: The original SQL string, used to produce helpful debug messages.
    1197
    1198        Returns:
    1199            The target Expression.
    1200        """
    1201        errors = []
    1202        for expression_type in ensure_list(expression_types):
    1203            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1204            if not parser:
    1205                raise TypeError(f"No parser registered for {expression_type}")
    1206
    1207            try:
    1208                return self._parse(parser, raw_tokens, sql)
    1209            except ParseError as e:
    1210                e.errors[0]["into_expression"] = expression_type
    1211                errors.append(e)
    1212
    1213        raise ParseError(
    1214            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1215            errors=merge_errors(errors),
    1216        ) 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

    1253    def check_errors(self) -> None:
    1254        """Logs or raises any found errors, depending on the chosen error level setting."""
    1255        if self.error_level == ErrorLevel.WARN:
    1256            for error in self.errors:
    1257                logger.error(str(error))
    1258        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1259            raise ParseError(
    1260                concat_messages(self.errors, self.max_errors),
    1261                errors=merge_errors(self.errors),
    1262            )

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

    1264    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1265        """
    1266        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1267        error level setting.
    1268        """
    1269        token = token or self._curr or self._prev or Token.string("")
    1270        start = token.start
    1271        end = token.end + 1
    1272        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1273        highlight = self.sql[start:end]
    1274        end_context = self.sql[end : end + self.error_message_context]
    1275
    1276        error = ParseError.new(
    1277            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1278            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1279            description=message,
    1280            line=token.line,
    1281            col=token.col,
    1282            start_context=start_context,
    1283            highlight=highlight,
    1284            end_context=end_context,
    1285        )
    1286
    1287        if self.error_level == ErrorLevel.IMMEDIATE:
    1288            raise error
    1289
    1290        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

    1292    def expression(
    1293        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1294    ) -> E:
    1295        """
    1296        Creates a new, validated Expression.
    1297
    1298        Args:
    1299            exp_class: The expression class to instantiate.
    1300            comments: An optional list of comments to attach to the expression.
    1301            kwargs: The arguments to set for the expression along with their respective values.
    1302
    1303        Returns:
    1304            The target expression.
    1305        """
    1306        instance = exp_class(**kwargs)
    1307        instance.add_comments(comments) if comments else self._add_comments(instance)
    1308        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

    1315    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1316        """
    1317        Validates an Expression, making sure that all its mandatory arguments are set.
    1318
    1319        Args:
    1320            expression: The expression to validate.
    1321            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1322
    1323        Returns:
    1324            The validated expression.
    1325        """
    1326        if self.error_level != ErrorLevel.IGNORE:
    1327            for error_message in expression.error_messages(args):
    1328                self.raise_error(error_message)
    1329
    1330        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