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 isinstance(this, exp.UNWRAPPED_QUERIES):
    4327                this = self._parse_set_operations(
    4328                    self._parse_subquery(this=this, parse_alias=False)
    4329                )
    4330            elif isinstance(this, exp.Subquery):
    4331                this = self._parse_subquery(
    4332                    this=self._parse_set_operations(this), parse_alias=False
    4333                )
    4334            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    4335                this = self.expression(exp.Tuple, expressions=expressions)
    4336            else:
    4337                this = self.expression(exp.Paren, this=this)
    4338
    4339            if this:
    4340                this.add_comments(comments)
    4341
    4342            self._match_r_paren(expression=this)
    4343            return this
    4344
    4345        return None
    4346
    4347    def _parse_field(
    4348        self,
    4349        any_token: bool = False,
    4350        tokens: t.Optional[t.Collection[TokenType]] = None,
    4351        anonymous_func: bool = False,
    4352    ) -> t.Optional[exp.Expression]:
    4353        if anonymous_func:
    4354            field = (
    4355                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    4356                or self._parse_primary()
    4357            )
    4358        else:
    4359            field = self._parse_primary() or self._parse_function(
    4360                anonymous=anonymous_func, any_token=any_token
    4361            )
    4362        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    4363
    4364    def _parse_function(
    4365        self,
    4366        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4367        anonymous: bool = False,
    4368        optional_parens: bool = True,
    4369        any_token: bool = False,
    4370    ) -> t.Optional[exp.Expression]:
    4371        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    4372        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    4373        fn_syntax = False
    4374        if (
    4375            self._match(TokenType.L_BRACE, advance=False)
    4376            and self._next
    4377            and self._next.text.upper() == "FN"
    4378        ):
    4379            self._advance(2)
    4380            fn_syntax = True
    4381
    4382        func = self._parse_function_call(
    4383            functions=functions,
    4384            anonymous=anonymous,
    4385            optional_parens=optional_parens,
    4386            any_token=any_token,
    4387        )
    4388
    4389        if fn_syntax:
    4390            self._match(TokenType.R_BRACE)
    4391
    4392        return func
    4393
    4394    def _parse_function_call(
    4395        self,
    4396        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4397        anonymous: bool = False,
    4398        optional_parens: bool = True,
    4399        any_token: bool = False,
    4400    ) -> t.Optional[exp.Expression]:
    4401        if not self._curr:
    4402            return None
    4403
    4404        comments = self._curr.comments
    4405        token_type = self._curr.token_type
    4406        this = self._curr.text
    4407        upper = this.upper()
    4408
    4409        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    4410        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    4411            self._advance()
    4412            return self._parse_window(parser(self))
    4413
    4414        if not self._next or self._next.token_type != TokenType.L_PAREN:
    4415            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    4416                self._advance()
    4417                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    4418
    4419            return None
    4420
    4421        if any_token:
    4422            if token_type in self.RESERVED_TOKENS:
    4423                return None
    4424        elif token_type not in self.FUNC_TOKENS:
    4425            return None
    4426
    4427        self._advance(2)
    4428
    4429        parser = self.FUNCTION_PARSERS.get(upper)
    4430        if parser and not anonymous:
    4431            this = parser(self)
    4432        else:
    4433            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    4434
    4435            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    4436                this = self.expression(subquery_predicate, this=self._parse_select())
    4437                self._match_r_paren()
    4438                return this
    4439
    4440            if functions is None:
    4441                functions = self.FUNCTIONS
    4442
    4443            function = functions.get(upper)
    4444
    4445            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    4446            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    4447
    4448            if alias:
    4449                args = self._kv_to_prop_eq(args)
    4450
    4451            if function and not anonymous:
    4452                if "dialect" in function.__code__.co_varnames:
    4453                    func = function(args, dialect=self.dialect)
    4454                else:
    4455                    func = function(args)
    4456
    4457                func = self.validate_expression(func, args)
    4458                if not self.dialect.NORMALIZE_FUNCTIONS:
    4459                    func.meta["name"] = this
    4460
    4461                this = func
    4462            else:
    4463                if token_type == TokenType.IDENTIFIER:
    4464                    this = exp.Identifier(this=this, quoted=True)
    4465                this = self.expression(exp.Anonymous, this=this, expressions=args)
    4466
    4467        if isinstance(this, exp.Expression):
    4468            this.add_comments(comments)
    4469
    4470        self._match_r_paren(this)
    4471        return self._parse_window(this)
    4472
    4473    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    4474        transformed = []
    4475
    4476        for e in expressions:
    4477            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    4478                if isinstance(e, exp.Alias):
    4479                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    4480
    4481                if not isinstance(e, exp.PropertyEQ):
    4482                    e = self.expression(
    4483                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    4484                    )
    4485
    4486                if isinstance(e.this, exp.Column):
    4487                    e.this.replace(e.this.this)
    4488
    4489            transformed.append(e)
    4490
    4491        return transformed
    4492
    4493    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    4494        return self._parse_column_def(self._parse_id_var())
    4495
    4496    def _parse_user_defined_function(
    4497        self, kind: t.Optional[TokenType] = None
    4498    ) -> t.Optional[exp.Expression]:
    4499        this = self._parse_id_var()
    4500
    4501        while self._match(TokenType.DOT):
    4502            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    4503
    4504        if not self._match(TokenType.L_PAREN):
    4505            return this
    4506
    4507        expressions = self._parse_csv(self._parse_function_parameter)
    4508        self._match_r_paren()
    4509        return self.expression(
    4510            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    4511        )
    4512
    4513    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    4514        literal = self._parse_primary()
    4515        if literal:
    4516            return self.expression(exp.Introducer, this=token.text, expression=literal)
    4517
    4518        return self.expression(exp.Identifier, this=token.text)
    4519
    4520    def _parse_session_parameter(self) -> exp.SessionParameter:
    4521        kind = None
    4522        this = self._parse_id_var() or self._parse_primary()
    4523
    4524        if this and self._match(TokenType.DOT):
    4525            kind = this.name
    4526            this = self._parse_var() or self._parse_primary()
    4527
    4528        return self.expression(exp.SessionParameter, this=this, kind=kind)
    4529
    4530    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4531        index = self._index
    4532
    4533        if self._match(TokenType.L_PAREN):
    4534            expressions = t.cast(
    4535                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
    4536            )
    4537
    4538            if not self._match(TokenType.R_PAREN):
    4539                self._retreat(index)
    4540        else:
    4541            expressions = [self._parse_id_var()]
    4542
    4543        if self._match_set(self.LAMBDAS):
    4544            return self.LAMBDAS[self._prev.token_type](self, expressions)
    4545
    4546        self._retreat(index)
    4547
    4548        this: t.Optional[exp.Expression]
    4549
    4550        if self._match(TokenType.DISTINCT):
    4551            this = self.expression(
    4552                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
    4553            )
    4554        else:
    4555            this = self._parse_select_or_expression(alias=alias)
    4556
    4557        return self._parse_limit(
    4558            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    4559        )
    4560
    4561    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4562        index = self._index
    4563        if not self._match(TokenType.L_PAREN):
    4564            return this
    4565
    4566        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    4567        # expr can be of both types
    4568        if self._match_set(self.SELECT_START_TOKENS):
    4569            self._retreat(index)
    4570            return this
    4571        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    4572        self._match_r_paren()
    4573        return self.expression(exp.Schema, this=this, expressions=args)
    4574
    4575    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    4576        return self._parse_column_def(self._parse_field(any_token=True))
    4577
    4578    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4579        # column defs are not really columns, they're identifiers
    4580        if isinstance(this, exp.Column):
    4581            this = this.this
    4582
    4583        kind = self._parse_types(schema=True)
    4584
    4585        if self._match_text_seq("FOR", "ORDINALITY"):
    4586            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    4587
    4588        constraints: t.List[exp.Expression] = []
    4589
    4590        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    4591            ("ALIAS", "MATERIALIZED")
    4592        ):
    4593            persisted = self._prev.text.upper() == "MATERIALIZED"
    4594            constraints.append(
    4595                self.expression(
    4596                    exp.ComputedColumnConstraint,
    4597                    this=self._parse_conjunction(),
    4598                    persisted=persisted or self._match_text_seq("PERSISTED"),
    4599                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    4600                )
    4601            )
    4602        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
    4603            self._match(TokenType.ALIAS)
    4604            constraints.append(
    4605                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
    4606            )
    4607
    4608        while True:
    4609            constraint = self._parse_column_constraint()
    4610            if not constraint:
    4611                break
    4612            constraints.append(constraint)
    4613
    4614        if not kind and not constraints:
    4615            return this
    4616
    4617        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    4618
    4619    def _parse_auto_increment(
    4620        self,
    4621    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    4622        start = None
    4623        increment = None
    4624
    4625        if self._match(TokenType.L_PAREN, advance=False):
    4626            args = self._parse_wrapped_csv(self._parse_bitwise)
    4627            start = seq_get(args, 0)
    4628            increment = seq_get(args, 1)
    4629        elif self._match_text_seq("START"):
    4630            start = self._parse_bitwise()
    4631            self._match_text_seq("INCREMENT")
    4632            increment = self._parse_bitwise()
    4633
    4634        if start and increment:
    4635            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    4636
    4637        return exp.AutoIncrementColumnConstraint()
    4638
    4639    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    4640        if not self._match_text_seq("REFRESH"):
    4641            self._retreat(self._index - 1)
    4642            return None
    4643        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    4644
    4645    def _parse_compress(self) -> exp.CompressColumnConstraint:
    4646        if self._match(TokenType.L_PAREN, advance=False):
    4647            return self.expression(
    4648                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    4649            )
    4650
    4651        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    4652
    4653    def _parse_generated_as_identity(
    4654        self,
    4655    ) -> (
    4656        exp.GeneratedAsIdentityColumnConstraint
    4657        | exp.ComputedColumnConstraint
    4658        | exp.GeneratedAsRowColumnConstraint
    4659    ):
    4660        if self._match_text_seq("BY", "DEFAULT"):
    4661            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    4662            this = self.expression(
    4663                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    4664            )
    4665        else:
    4666            self._match_text_seq("ALWAYS")
    4667            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    4668
    4669        self._match(TokenType.ALIAS)
    4670
    4671        if self._match_text_seq("ROW"):
    4672            start = self._match_text_seq("START")
    4673            if not start:
    4674                self._match(TokenType.END)
    4675            hidden = self._match_text_seq("HIDDEN")
    4676            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    4677
    4678        identity = self._match_text_seq("IDENTITY")
    4679
    4680        if self._match(TokenType.L_PAREN):
    4681            if self._match(TokenType.START_WITH):
    4682                this.set("start", self._parse_bitwise())
    4683            if self._match_text_seq("INCREMENT", "BY"):
    4684                this.set("increment", self._parse_bitwise())
    4685            if self._match_text_seq("MINVALUE"):
    4686                this.set("minvalue", self._parse_bitwise())
    4687            if self._match_text_seq("MAXVALUE"):
    4688                this.set("maxvalue", self._parse_bitwise())
    4689
    4690            if self._match_text_seq("CYCLE"):
    4691                this.set("cycle", True)
    4692            elif self._match_text_seq("NO", "CYCLE"):
    4693                this.set("cycle", False)
    4694
    4695            if not identity:
    4696                this.set("expression", self._parse_range())
    4697            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    4698                args = self._parse_csv(self._parse_bitwise)
    4699                this.set("start", seq_get(args, 0))
    4700                this.set("increment", seq_get(args, 1))
    4701
    4702            self._match_r_paren()
    4703
    4704        return this
    4705
    4706    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    4707        self._match_text_seq("LENGTH")
    4708        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    4709
    4710    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    4711        if self._match_text_seq("NULL"):
    4712            return self.expression(exp.NotNullColumnConstraint)
    4713        if self._match_text_seq("CASESPECIFIC"):
    4714            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    4715        if self._match_text_seq("FOR", "REPLICATION"):
    4716            return self.expression(exp.NotForReplicationColumnConstraint)
    4717        return None
    4718
    4719    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    4720        if self._match(TokenType.CONSTRAINT):
    4721            this = self._parse_id_var()
    4722        else:
    4723            this = None
    4724
    4725        if self._match_texts(self.CONSTRAINT_PARSERS):
    4726            return self.expression(
    4727                exp.ColumnConstraint,
    4728                this=this,
    4729                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    4730            )
    4731
    4732        return this
    4733
    4734    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    4735        if not self._match(TokenType.CONSTRAINT):
    4736            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    4737
    4738        return self.expression(
    4739            exp.Constraint,
    4740            this=self._parse_id_var(),
    4741            expressions=self._parse_unnamed_constraints(),
    4742        )
    4743
    4744    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    4745        constraints = []
    4746        while True:
    4747            constraint = self._parse_unnamed_constraint() or self._parse_function()
    4748            if not constraint:
    4749                break
    4750            constraints.append(constraint)
    4751
    4752        return constraints
    4753
    4754    def _parse_unnamed_constraint(
    4755        self, constraints: t.Optional[t.Collection[str]] = None
    4756    ) -> t.Optional[exp.Expression]:
    4757        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    4758            constraints or self.CONSTRAINT_PARSERS
    4759        ):
    4760            return None
    4761
    4762        constraint = self._prev.text.upper()
    4763        if constraint not in self.CONSTRAINT_PARSERS:
    4764            self.raise_error(f"No parser found for schema constraint {constraint}.")
    4765
    4766        return self.CONSTRAINT_PARSERS[constraint](self)
    4767
    4768    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    4769        self._match_text_seq("KEY")
    4770        return self.expression(
    4771            exp.UniqueColumnConstraint,
    4772            this=self._parse_schema(self._parse_id_var(any_token=False)),
    4773            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    4774            on_conflict=self._parse_on_conflict(),
    4775        )
    4776
    4777    def _parse_key_constraint_options(self) -> t.List[str]:
    4778        options = []
    4779        while True:
    4780            if not self._curr:
    4781                break
    4782
    4783            if self._match(TokenType.ON):
    4784                action = None
    4785                on = self._advance_any() and self._prev.text
    4786
    4787                if self._match_text_seq("NO", "ACTION"):
    4788                    action = "NO ACTION"
    4789                elif self._match_text_seq("CASCADE"):
    4790                    action = "CASCADE"
    4791                elif self._match_text_seq("RESTRICT"):
    4792                    action = "RESTRICT"
    4793                elif self._match_pair(TokenType.SET, TokenType.NULL):
    4794                    action = "SET NULL"
    4795                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    4796                    action = "SET DEFAULT"
    4797                else:
    4798                    self.raise_error("Invalid key constraint")
    4799
    4800                options.append(f"ON {on} {action}")
    4801            elif self._match_text_seq("NOT", "ENFORCED"):
    4802                options.append("NOT ENFORCED")
    4803            elif self._match_text_seq("DEFERRABLE"):
    4804                options.append("DEFERRABLE")
    4805            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    4806                options.append("INITIALLY DEFERRED")
    4807            elif self._match_text_seq("NORELY"):
    4808                options.append("NORELY")
    4809            elif self._match_text_seq("MATCH", "FULL"):
    4810                options.append("MATCH FULL")
    4811            else:
    4812                break
    4813
    4814        return options
    4815
    4816    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    4817        if match and not self._match(TokenType.REFERENCES):
    4818            return None
    4819
    4820        expressions = None
    4821        this = self._parse_table(schema=True)
    4822        options = self._parse_key_constraint_options()
    4823        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    4824
    4825    def _parse_foreign_key(self) -> exp.ForeignKey:
    4826        expressions = self._parse_wrapped_id_vars()
    4827        reference = self._parse_references()
    4828        options = {}
    4829
    4830        while self._match(TokenType.ON):
    4831            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    4832                self.raise_error("Expected DELETE or UPDATE")
    4833
    4834            kind = self._prev.text.lower()
    4835
    4836            if self._match_text_seq("NO", "ACTION"):
    4837                action = "NO ACTION"
    4838            elif self._match(TokenType.SET):
    4839                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    4840                action = "SET " + self._prev.text.upper()
    4841            else:
    4842                self._advance()
    4843                action = self._prev.text.upper()
    4844
    4845            options[kind] = action
    4846
    4847        return self.expression(
    4848            exp.ForeignKey,
    4849            expressions=expressions,
    4850            reference=reference,
    4851            **options,  # type: ignore
    4852        )
    4853
    4854    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    4855        return self._parse_field()
    4856
    4857    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    4858        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    4859            self._retreat(self._index - 1)
    4860            return None
    4861
    4862        id_vars = self._parse_wrapped_id_vars()
    4863        return self.expression(
    4864            exp.PeriodForSystemTimeConstraint,
    4865            this=seq_get(id_vars, 0),
    4866            expression=seq_get(id_vars, 1),
    4867        )
    4868
    4869    def _parse_primary_key(
    4870        self, wrapped_optional: bool = False, in_props: bool = False
    4871    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    4872        desc = (
    4873            self._match_set((TokenType.ASC, TokenType.DESC))
    4874            and self._prev.token_type == TokenType.DESC
    4875        )
    4876
    4877        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    4878            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    4879
    4880        expressions = self._parse_wrapped_csv(
    4881            self._parse_primary_key_part, optional=wrapped_optional
    4882        )
    4883        options = self._parse_key_constraint_options()
    4884        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    4885
    4886    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    4887        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
    4888
    4889    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4890        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    4891            return this
    4892
    4893        bracket_kind = self._prev.token_type
    4894        expressions = self._parse_csv(
    4895            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    4896        )
    4897
    4898        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    4899            self.raise_error("Expected ]")
    4900        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    4901            self.raise_error("Expected }")
    4902
    4903        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    4904        if bracket_kind == TokenType.L_BRACE:
    4905            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    4906        elif not this or this.name.upper() == "ARRAY":
    4907            this = self.expression(exp.Array, expressions=expressions)
    4908        else:
    4909            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    4910            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    4911
    4912        self._add_comments(this)
    4913        return self._parse_bracket(this)
    4914
    4915    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4916        if self._match(TokenType.COLON):
    4917            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
    4918        return this
    4919
    4920    def _parse_case(self) -> t.Optional[exp.Expression]:
    4921        ifs = []
    4922        default = None
    4923
    4924        comments = self._prev_comments
    4925        expression = self._parse_conjunction()
    4926
    4927        while self._match(TokenType.WHEN):
    4928            this = self._parse_conjunction()
    4929            self._match(TokenType.THEN)
    4930            then = self._parse_conjunction()
    4931            ifs.append(self.expression(exp.If, this=this, true=then))
    4932
    4933        if self._match(TokenType.ELSE):
    4934            default = self._parse_conjunction()
    4935
    4936        if not self._match(TokenType.END):
    4937            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    4938                default = exp.column("interval")
    4939            else:
    4940                self.raise_error("Expected END after CASE", self._prev)
    4941
    4942        return self.expression(
    4943            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    4944        )
    4945
    4946    def _parse_if(self) -> t.Optional[exp.Expression]:
    4947        if self._match(TokenType.L_PAREN):
    4948            args = self._parse_csv(self._parse_conjunction)
    4949            this = self.validate_expression(exp.If.from_arg_list(args), args)
    4950            self._match_r_paren()
    4951        else:
    4952            index = self._index - 1
    4953
    4954            if self.NO_PAREN_IF_COMMANDS and index == 0:
    4955                return self._parse_as_command(self._prev)
    4956
    4957            condition = self._parse_conjunction()
    4958
    4959            if not condition:
    4960                self._retreat(index)
    4961                return None
    4962
    4963            self._match(TokenType.THEN)
    4964            true = self._parse_conjunction()
    4965            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
    4966            self._match(TokenType.END)
    4967            this = self.expression(exp.If, this=condition, true=true, false=false)
    4968
    4969        return this
    4970
    4971    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    4972        if not self._match_text_seq("VALUE", "FOR"):
    4973            self._retreat(self._index - 1)
    4974            return None
    4975
    4976        return self.expression(
    4977            exp.NextValueFor,
    4978            this=self._parse_column(),
    4979            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    4980        )
    4981
    4982    def _parse_extract(self) -> exp.Extract:
    4983        this = self._parse_function() or self._parse_var() or self._parse_type()
    4984
    4985        if self._match(TokenType.FROM):
    4986            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    4987
    4988        if not self._match(TokenType.COMMA):
    4989            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    4990
    4991        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    4992
    4993    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    4994        this = self._parse_conjunction()
    4995
    4996        if not self._match(TokenType.ALIAS):
    4997            if self._match(TokenType.COMMA):
    4998                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    4999
    5000            self.raise_error("Expected AS after CAST")
    5001
    5002        fmt = None
    5003        to = self._parse_types()
    5004
    5005        if self._match(TokenType.FORMAT):
    5006            fmt_string = self._parse_string()
    5007            fmt = self._parse_at_time_zone(fmt_string)
    5008
    5009            if not to:
    5010                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    5011            if to.this in exp.DataType.TEMPORAL_TYPES:
    5012                this = self.expression(
    5013                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    5014                    this=this,
    5015                    format=exp.Literal.string(
    5016                        format_time(
    5017                            fmt_string.this if fmt_string else "",
    5018                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    5019                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    5020                        )
    5021                    ),
    5022                )
    5023
    5024                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    5025                    this.set("zone", fmt.args["zone"])
    5026                return this
    5027        elif not to:
    5028            self.raise_error("Expected TYPE after CAST")
    5029        elif isinstance(to, exp.Identifier):
    5030            to = exp.DataType.build(to.name, udt=True)
    5031        elif to.this == exp.DataType.Type.CHAR:
    5032            if self._match(TokenType.CHARACTER_SET):
    5033                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    5034
    5035        return self.expression(
    5036            exp.Cast if strict else exp.TryCast,
    5037            this=this,
    5038            to=to,
    5039            format=fmt,
    5040            safe=safe,
    5041            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    5042        )
    5043
    5044    def _parse_string_agg(self) -> exp.Expression:
    5045        if self._match(TokenType.DISTINCT):
    5046            args: t.List[t.Optional[exp.Expression]] = [
    5047                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
    5048            ]
    5049            if self._match(TokenType.COMMA):
    5050                args.extend(self._parse_csv(self._parse_conjunction))
    5051        else:
    5052            args = self._parse_csv(self._parse_conjunction)  # type: ignore
    5053
    5054        index = self._index
    5055        if not self._match(TokenType.R_PAREN) and args:
    5056            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    5057            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    5058            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    5059            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    5060
    5061        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    5062        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    5063        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    5064        if not self._match_text_seq("WITHIN", "GROUP"):
    5065            self._retreat(index)
    5066            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    5067
    5068        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    5069        order = self._parse_order(this=seq_get(args, 0))
    5070        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    5071
    5072    def _parse_convert(
    5073        self, strict: bool, safe: t.Optional[bool] = None
    5074    ) -> t.Optional[exp.Expression]:
    5075        this = self._parse_bitwise()
    5076
    5077        if self._match(TokenType.USING):
    5078            to: t.Optional[exp.Expression] = self.expression(
    5079                exp.CharacterSet, this=self._parse_var()
    5080            )
    5081        elif self._match(TokenType.COMMA):
    5082            to = self._parse_types()
    5083        else:
    5084            to = None
    5085
    5086        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    5087
    5088    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    5089        """
    5090        There are generally two variants of the DECODE function:
    5091
    5092        - DECODE(bin, charset)
    5093        - DECODE(expression, search, result [, search, result] ... [, default])
    5094
    5095        The second variant will always be parsed into a CASE expression. Note that NULL
    5096        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    5097        instead of relying on pattern matching.
    5098        """
    5099        args = self._parse_csv(self._parse_conjunction)
    5100
    5101        if len(args) < 3:
    5102            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    5103
    5104        expression, *expressions = args
    5105        if not expression:
    5106            return None
    5107
    5108        ifs = []
    5109        for search, result in zip(expressions[::2], expressions[1::2]):
    5110            if not search or not result:
    5111                return None
    5112
    5113            if isinstance(search, exp.Literal):
    5114                ifs.append(
    5115                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    5116                )
    5117            elif isinstance(search, exp.Null):
    5118                ifs.append(
    5119                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    5120                )
    5121            else:
    5122                cond = exp.or_(
    5123                    exp.EQ(this=expression.copy(), expression=search),
    5124                    exp.and_(
    5125                        exp.Is(this=expression.copy(), expression=exp.Null()),
    5126                        exp.Is(this=search.copy(), expression=exp.Null()),
    5127                        copy=False,
    5128                    ),
    5129                    copy=False,
    5130                )
    5131                ifs.append(exp.If(this=cond, true=result))
    5132
    5133        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    5134
    5135    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    5136        self._match_text_seq("KEY")
    5137        key = self._parse_column()
    5138        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    5139        self._match_text_seq("VALUE")
    5140        value = self._parse_bitwise()
    5141
    5142        if not key and not value:
    5143            return None
    5144        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    5145
    5146    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5147        if not this or not self._match_text_seq("FORMAT", "JSON"):
    5148            return this
    5149
    5150        return self.expression(exp.FormatJson, this=this)
    5151
    5152    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
    5153        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
    5154        for value in values:
    5155            if self._match_text_seq(value, "ON", on):
    5156                return f"{value} ON {on}"
    5157
    5158        return None
    5159
    5160    @t.overload
    5161    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    5162
    5163    @t.overload
    5164    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    5165
    5166    def _parse_json_object(self, agg=False):
    5167        star = self._parse_star()
    5168        expressions = (
    5169            [star]
    5170            if star
    5171            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    5172        )
    5173        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    5174
    5175        unique_keys = None
    5176        if self._match_text_seq("WITH", "UNIQUE"):
    5177            unique_keys = True
    5178        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    5179            unique_keys = False
    5180
    5181        self._match_text_seq("KEYS")
    5182
    5183        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    5184            self._parse_type()
    5185        )
    5186        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    5187
    5188        return self.expression(
    5189            exp.JSONObjectAgg if agg else exp.JSONObject,
    5190            expressions=expressions,
    5191            null_handling=null_handling,
    5192            unique_keys=unique_keys,
    5193            return_type=return_type,
    5194            encoding=encoding,
    5195        )
    5196
    5197    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    5198    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    5199        if not self._match_text_seq("NESTED"):
    5200            this = self._parse_id_var()
    5201            kind = self._parse_types(allow_identifiers=False)
    5202            nested = None
    5203        else:
    5204            this = None
    5205            kind = None
    5206            nested = True
    5207
    5208        path = self._match_text_seq("PATH") and self._parse_string()
    5209        nested_schema = nested and self._parse_json_schema()
    5210
    5211        return self.expression(
    5212            exp.JSONColumnDef,
    5213            this=this,
    5214            kind=kind,
    5215            path=path,
    5216            nested_schema=nested_schema,
    5217        )
    5218
    5219    def _parse_json_schema(self) -> exp.JSONSchema:
    5220        self._match_text_seq("COLUMNS")
    5221        return self.expression(
    5222            exp.JSONSchema,
    5223            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    5224        )
    5225
    5226    def _parse_json_table(self) -> exp.JSONTable:
    5227        this = self._parse_format_json(self._parse_bitwise())
    5228        path = self._match(TokenType.COMMA) and self._parse_string()
    5229        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    5230        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    5231        schema = self._parse_json_schema()
    5232
    5233        return exp.JSONTable(
    5234            this=this,
    5235            schema=schema,
    5236            path=path,
    5237            error_handling=error_handling,
    5238            empty_handling=empty_handling,
    5239        )
    5240
    5241    def _parse_match_against(self) -> exp.MatchAgainst:
    5242        expressions = self._parse_csv(self._parse_column)
    5243
    5244        self._match_text_seq(")", "AGAINST", "(")
    5245
    5246        this = self._parse_string()
    5247
    5248        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    5249            modifier = "IN NATURAL LANGUAGE MODE"
    5250            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5251                modifier = f"{modifier} WITH QUERY EXPANSION"
    5252        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    5253            modifier = "IN BOOLEAN MODE"
    5254        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5255            modifier = "WITH QUERY EXPANSION"
    5256        else:
    5257            modifier = None
    5258
    5259        return self.expression(
    5260            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    5261        )
    5262
    5263    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    5264    def _parse_open_json(self) -> exp.OpenJSON:
    5265        this = self._parse_bitwise()
    5266        path = self._match(TokenType.COMMA) and self._parse_string()
    5267
    5268        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    5269            this = self._parse_field(any_token=True)
    5270            kind = self._parse_types()
    5271            path = self._parse_string()
    5272            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    5273
    5274            return self.expression(
    5275                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    5276            )
    5277
    5278        expressions = None
    5279        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    5280            self._match_l_paren()
    5281            expressions = self._parse_csv(_parse_open_json_column_def)
    5282
    5283        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    5284
    5285    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    5286        args = self._parse_csv(self._parse_bitwise)
    5287
    5288        if self._match(TokenType.IN):
    5289            return self.expression(
    5290                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    5291            )
    5292
    5293        if haystack_first:
    5294            haystack = seq_get(args, 0)
    5295            needle = seq_get(args, 1)
    5296        else:
    5297            needle = seq_get(args, 0)
    5298            haystack = seq_get(args, 1)
    5299
    5300        return self.expression(
    5301            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    5302        )
    5303
    5304    def _parse_predict(self) -> exp.Predict:
    5305        self._match_text_seq("MODEL")
    5306        this = self._parse_table()
    5307
    5308        self._match(TokenType.COMMA)
    5309        self._match_text_seq("TABLE")
    5310
    5311        return self.expression(
    5312            exp.Predict,
    5313            this=this,
    5314            expression=self._parse_table(),
    5315            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    5316        )
    5317
    5318    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    5319        args = self._parse_csv(self._parse_table)
    5320        return exp.JoinHint(this=func_name.upper(), expressions=args)
    5321
    5322    def _parse_substring(self) -> exp.Substring:
    5323        # Postgres supports the form: substring(string [from int] [for int])
    5324        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    5325
    5326        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    5327
    5328        if self._match(TokenType.FROM):
    5329            args.append(self._parse_bitwise())
    5330        if self._match(TokenType.FOR):
    5331            if len(args) == 1:
    5332                args.append(exp.Literal.number(1))
    5333            args.append(self._parse_bitwise())
    5334
    5335        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    5336
    5337    def _parse_trim(self) -> exp.Trim:
    5338        # https://www.w3resource.com/sql/character-functions/trim.php
    5339        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    5340
    5341        position = None
    5342        collation = None
    5343        expression = None
    5344
    5345        if self._match_texts(self.TRIM_TYPES):
    5346            position = self._prev.text.upper()
    5347
    5348        this = self._parse_bitwise()
    5349        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    5350            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    5351            expression = self._parse_bitwise()
    5352
    5353            if invert_order:
    5354                this, expression = expression, this
    5355
    5356        if self._match(TokenType.COLLATE):
    5357            collation = self._parse_bitwise()
    5358
    5359        return self.expression(
    5360            exp.Trim, this=this, position=position, expression=expression, collation=collation
    5361        )
    5362
    5363    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    5364        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    5365
    5366    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    5367        return self._parse_window(self._parse_id_var(), alias=True)
    5368
    5369    def _parse_respect_or_ignore_nulls(
    5370        self, this: t.Optional[exp.Expression]
    5371    ) -> t.Optional[exp.Expression]:
    5372        if self._match_text_seq("IGNORE", "NULLS"):
    5373            return self.expression(exp.IgnoreNulls, this=this)
    5374        if self._match_text_seq("RESPECT", "NULLS"):
    5375            return self.expression(exp.RespectNulls, this=this)
    5376        return this
    5377
    5378    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5379        if self._match(TokenType.HAVING):
    5380            self._match_texts(("MAX", "MIN"))
    5381            max = self._prev.text.upper() != "MIN"
    5382            return self.expression(
    5383                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    5384            )
    5385
    5386        return this
    5387
    5388    def _parse_window(
    5389        self, this: t.Optional[exp.Expression], alias: bool = False
    5390    ) -> t.Optional[exp.Expression]:
    5391        func = this
    5392        comments = func.comments if isinstance(func, exp.Expression) else None
    5393
    5394        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    5395            self._match(TokenType.WHERE)
    5396            this = self.expression(
    5397                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    5398            )
    5399            self._match_r_paren()
    5400
    5401        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    5402        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    5403        if self._match_text_seq("WITHIN", "GROUP"):
    5404            order = self._parse_wrapped(self._parse_order)
    5405            this = self.expression(exp.WithinGroup, this=this, expression=order)
    5406
    5407        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    5408        # Some dialects choose to implement and some do not.
    5409        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    5410
    5411        # There is some code above in _parse_lambda that handles
    5412        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    5413
    5414        # The below changes handle
    5415        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    5416
    5417        # Oracle allows both formats
    5418        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    5419        #   and Snowflake chose to do the same for familiarity
    5420        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    5421        if isinstance(this, exp.AggFunc):
    5422            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    5423
    5424            if ignore_respect and ignore_respect is not this:
    5425                ignore_respect.replace(ignore_respect.this)
    5426                this = self.expression(ignore_respect.__class__, this=this)
    5427
    5428        this = self._parse_respect_or_ignore_nulls(this)
    5429
    5430        # bigquery select from window x AS (partition by ...)
    5431        if alias:
    5432            over = None
    5433            self._match(TokenType.ALIAS)
    5434        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    5435            return this
    5436        else:
    5437            over = self._prev.text.upper()
    5438
    5439        if comments and isinstance(func, exp.Expression):
    5440            func.pop_comments()
    5441
    5442        if not self._match(TokenType.L_PAREN):
    5443            return self.expression(
    5444                exp.Window,
    5445                comments=comments,
    5446                this=this,
    5447                alias=self._parse_id_var(False),
    5448                over=over,
    5449            )
    5450
    5451        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    5452
    5453        first = self._match(TokenType.FIRST)
    5454        if self._match_text_seq("LAST"):
    5455            first = False
    5456
    5457        partition, order = self._parse_partition_and_order()
    5458        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    5459
    5460        if kind:
    5461            self._match(TokenType.BETWEEN)
    5462            start = self._parse_window_spec()
    5463            self._match(TokenType.AND)
    5464            end = self._parse_window_spec()
    5465
    5466            spec = self.expression(
    5467                exp.WindowSpec,
    5468                kind=kind,
    5469                start=start["value"],
    5470                start_side=start["side"],
    5471                end=end["value"],
    5472                end_side=end["side"],
    5473            )
    5474        else:
    5475            spec = None
    5476
    5477        self._match_r_paren()
    5478
    5479        window = self.expression(
    5480            exp.Window,
    5481            comments=comments,
    5482            this=this,
    5483            partition_by=partition,
    5484            order=order,
    5485            spec=spec,
    5486            alias=window_alias,
    5487            over=over,
    5488            first=first,
    5489        )
    5490
    5491        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    5492        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    5493            return self._parse_window(window, alias=alias)
    5494
    5495        return window
    5496
    5497    def _parse_partition_and_order(
    5498        self,
    5499    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    5500        return self._parse_partition_by(), self._parse_order()
    5501
    5502    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    5503        self._match(TokenType.BETWEEN)
    5504
    5505        return {
    5506            "value": (
    5507                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    5508                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    5509                or self._parse_bitwise()
    5510            ),
    5511            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    5512        }
    5513
    5514    def _parse_alias(
    5515        self, this: t.Optional[exp.Expression], explicit: bool = False
    5516    ) -> t.Optional[exp.Expression]:
    5517        any_token = self._match(TokenType.ALIAS)
    5518        comments = self._prev_comments or []
    5519
    5520        if explicit and not any_token:
    5521            return this
    5522
    5523        if self._match(TokenType.L_PAREN):
    5524            aliases = self.expression(
    5525                exp.Aliases,
    5526                comments=comments,
    5527                this=this,
    5528                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    5529            )
    5530            self._match_r_paren(aliases)
    5531            return aliases
    5532
    5533        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    5534            self.STRING_ALIASES and self._parse_string_as_identifier()
    5535        )
    5536
    5537        if alias:
    5538            comments.extend(alias.pop_comments())
    5539            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    5540            column = this.this
    5541
    5542            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    5543            if not this.comments and column and column.comments:
    5544                this.comments = column.pop_comments()
    5545
    5546        return this
    5547
    5548    def _parse_id_var(
    5549        self,
    5550        any_token: bool = True,
    5551        tokens: t.Optional[t.Collection[TokenType]] = None,
    5552    ) -> t.Optional[exp.Expression]:
    5553        expression = self._parse_identifier()
    5554        if not expression and (
    5555            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    5556        ):
    5557            quoted = self._prev.token_type == TokenType.STRING
    5558            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    5559
    5560        return expression
    5561
    5562    def _parse_string(self) -> t.Optional[exp.Expression]:
    5563        if self._match_set(self.STRING_PARSERS):
    5564            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    5565        return self._parse_placeholder()
    5566
    5567    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    5568        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    5569
    5570    def _parse_number(self) -> t.Optional[exp.Expression]:
    5571        if self._match_set(self.NUMERIC_PARSERS):
    5572            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    5573        return self._parse_placeholder()
    5574
    5575    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    5576        if self._match(TokenType.IDENTIFIER):
    5577            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    5578        return self._parse_placeholder()
    5579
    5580    def _parse_var(
    5581        self,
    5582        any_token: bool = False,
    5583        tokens: t.Optional[t.Collection[TokenType]] = None,
    5584        upper: bool = False,
    5585    ) -> t.Optional[exp.Expression]:
    5586        if (
    5587            (any_token and self._advance_any())
    5588            or self._match(TokenType.VAR)
    5589            or (self._match_set(tokens) if tokens else False)
    5590        ):
    5591            return self.expression(
    5592                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    5593            )
    5594        return self._parse_placeholder()
    5595
    5596    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    5597        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    5598            self._advance()
    5599            return self._prev
    5600        return None
    5601
    5602    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    5603        return self._parse_var() or self._parse_string()
    5604
    5605    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    5606        return self._parse_primary() or self._parse_var(any_token=True)
    5607
    5608    def _parse_null(self) -> t.Optional[exp.Expression]:
    5609        if self._match_set(self.NULL_TOKENS):
    5610            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    5611        return self._parse_placeholder()
    5612
    5613    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    5614        if self._match(TokenType.TRUE):
    5615            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    5616        if self._match(TokenType.FALSE):
    5617            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    5618        return self._parse_placeholder()
    5619
    5620    def _parse_star(self) -> t.Optional[exp.Expression]:
    5621        if self._match(TokenType.STAR):
    5622            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    5623        return self._parse_placeholder()
    5624
    5625    def _parse_parameter(self) -> exp.Parameter:
    5626        self._match(TokenType.L_BRACE)
    5627        this = self._parse_identifier() or self._parse_primary_or_var()
    5628        expression = self._match(TokenType.COLON) and (
    5629            self._parse_identifier() or self._parse_primary_or_var()
    5630        )
    5631        self._match(TokenType.R_BRACE)
    5632        return self.expression(exp.Parameter, this=this, expression=expression)
    5633
    5634    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    5635        if self._match_set(self.PLACEHOLDER_PARSERS):
    5636            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    5637            if placeholder:
    5638                return placeholder
    5639            self._advance(-1)
    5640        return None
    5641
    5642    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
    5643        if not self._match(TokenType.EXCEPT):
    5644            return None
    5645        if self._match(TokenType.L_PAREN, advance=False):
    5646            return self._parse_wrapped_csv(self._parse_column)
    5647
    5648        except_column = self._parse_column()
    5649        return [except_column] if except_column else None
    5650
    5651    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
    5652        if not self._match(TokenType.REPLACE):
    5653            return None
    5654        if self._match(TokenType.L_PAREN, advance=False):
    5655            return self._parse_wrapped_csv(self._parse_expression)
    5656
    5657        replace_expression = self._parse_expression()
    5658        return [replace_expression] if replace_expression else None
    5659
    5660    def _parse_csv(
    5661        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    5662    ) -> t.List[exp.Expression]:
    5663        parse_result = parse_method()
    5664        items = [parse_result] if parse_result is not None else []
    5665
    5666        while self._match(sep):
    5667            self._add_comments(parse_result)
    5668            parse_result = parse_method()
    5669            if parse_result is not None:
    5670                items.append(parse_result)
    5671
    5672        return items
    5673
    5674    def _parse_tokens(
    5675        self, parse_method: t.Callable, expressions: t.Dict
    5676    ) -> t.Optional[exp.Expression]:
    5677        this = parse_method()
    5678
    5679        while self._match_set(expressions):
    5680            this = self.expression(
    5681                expressions[self._prev.token_type],
    5682                this=this,
    5683                comments=self._prev_comments,
    5684                expression=parse_method(),
    5685            )
    5686
    5687        return this
    5688
    5689    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    5690        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    5691
    5692    def _parse_wrapped_csv(
    5693        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    5694    ) -> t.List[exp.Expression]:
    5695        return self._parse_wrapped(
    5696            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    5697        )
    5698
    5699    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    5700        wrapped = self._match(TokenType.L_PAREN)
    5701        if not wrapped and not optional:
    5702            self.raise_error("Expecting (")
    5703        parse_result = parse_method()
    5704        if wrapped:
    5705            self._match_r_paren()
    5706        return parse_result
    5707
    5708    def _parse_expressions(self) -> t.List[exp.Expression]:
    5709        return self._parse_csv(self._parse_expression)
    5710
    5711    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5712        return self._parse_select() or self._parse_set_operations(
    5713            self._parse_expression() if alias else self._parse_conjunction()
    5714        )
    5715
    5716    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    5717        return self._parse_query_modifiers(
    5718            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    5719        )
    5720
    5721    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    5722        this = None
    5723        if self._match_texts(self.TRANSACTION_KIND):
    5724            this = self._prev.text
    5725
    5726        self._match_texts(("TRANSACTION", "WORK"))
    5727
    5728        modes = []
    5729        while True:
    5730            mode = []
    5731            while self._match(TokenType.VAR):
    5732                mode.append(self._prev.text)
    5733
    5734            if mode:
    5735                modes.append(" ".join(mode))
    5736            if not self._match(TokenType.COMMA):
    5737                break
    5738
    5739        return self.expression(exp.Transaction, this=this, modes=modes)
    5740
    5741    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    5742        chain = None
    5743        savepoint = None
    5744        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    5745
    5746        self._match_texts(("TRANSACTION", "WORK"))
    5747
    5748        if self._match_text_seq("TO"):
    5749            self._match_text_seq("SAVEPOINT")
    5750            savepoint = self._parse_id_var()
    5751
    5752        if self._match(TokenType.AND):
    5753            chain = not self._match_text_seq("NO")
    5754            self._match_text_seq("CHAIN")
    5755
    5756        if is_rollback:
    5757            return self.expression(exp.Rollback, savepoint=savepoint)
    5758
    5759        return self.expression(exp.Commit, chain=chain)
    5760
    5761    def _parse_refresh(self) -> exp.Refresh:
    5762        self._match(TokenType.TABLE)
    5763        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    5764
    5765    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    5766        if not self._match_text_seq("ADD"):
    5767            return None
    5768
    5769        self._match(TokenType.COLUMN)
    5770        exists_column = self._parse_exists(not_=True)
    5771        expression = self._parse_field_def()
    5772
    5773        if expression:
    5774            expression.set("exists", exists_column)
    5775
    5776            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    5777            if self._match_texts(("FIRST", "AFTER")):
    5778                position = self._prev.text
    5779                column_position = self.expression(
    5780                    exp.ColumnPosition, this=self._parse_column(), position=position
    5781                )
    5782                expression.set("position", column_position)
    5783
    5784        return expression
    5785
    5786    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    5787        drop = self._match(TokenType.DROP) and self._parse_drop()
    5788        if drop and not isinstance(drop, exp.Command):
    5789            drop.set("kind", drop.args.get("kind", "COLUMN"))
    5790        return drop
    5791
    5792    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    5793    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    5794        return self.expression(
    5795            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    5796        )
    5797
    5798    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    5799        index = self._index - 1
    5800
    5801        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    5802            return self._parse_csv(
    5803                lambda: self.expression(
    5804                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    5805                )
    5806            )
    5807
    5808        self._retreat(index)
    5809        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    5810            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    5811        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    5812
    5813    def _parse_alter_table_alter(self) -> exp.AlterColumn:
    5814        self._match(TokenType.COLUMN)
    5815        column = self._parse_field(any_token=True)
    5816
    5817        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    5818            return self.expression(exp.AlterColumn, this=column, drop=True)
    5819        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5820            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
    5821        if self._match(TokenType.COMMENT):
    5822            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    5823
    5824        self._match_text_seq("SET", "DATA")
    5825        self._match_text_seq("TYPE")
    5826        return self.expression(
    5827            exp.AlterColumn,
    5828            this=column,
    5829            dtype=self._parse_types(),
    5830            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    5831            using=self._match(TokenType.USING) and self._parse_conjunction(),
    5832        )
    5833
    5834    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    5835        index = self._index - 1
    5836
    5837        partition_exists = self._parse_exists()
    5838        if self._match(TokenType.PARTITION, advance=False):
    5839            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    5840
    5841        self._retreat(index)
    5842        return self._parse_csv(self._parse_drop_column)
    5843
    5844    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
    5845        if self._match(TokenType.COLUMN):
    5846            exists = self._parse_exists()
    5847            old_column = self._parse_column()
    5848            to = self._match_text_seq("TO")
    5849            new_column = self._parse_column()
    5850
    5851            if old_column is None or to is None or new_column is None:
    5852                return None
    5853
    5854            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    5855
    5856        self._match_text_seq("TO")
    5857        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    5858
    5859    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    5860        start = self._prev
    5861
    5862        if not self._match(TokenType.TABLE):
    5863            return self._parse_as_command(start)
    5864
    5865        exists = self._parse_exists()
    5866        only = self._match_text_seq("ONLY")
    5867        this = self._parse_table(schema=True)
    5868
    5869        if self._next:
    5870            self._advance()
    5871
    5872        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    5873        if parser:
    5874            actions = ensure_list(parser(self))
    5875            options = self._parse_csv(self._parse_property)
    5876
    5877            if not self._curr and actions:
    5878                return self.expression(
    5879                    exp.AlterTable,
    5880                    this=this,
    5881                    exists=exists,
    5882                    actions=actions,
    5883                    only=only,
    5884                    options=options,
    5885                )
    5886
    5887        return self._parse_as_command(start)
    5888
    5889    def _parse_merge(self) -> exp.Merge:
    5890        self._match(TokenType.INTO)
    5891        target = self._parse_table()
    5892
    5893        if target and self._match(TokenType.ALIAS, advance=False):
    5894            target.set("alias", self._parse_table_alias())
    5895
    5896        self._match(TokenType.USING)
    5897        using = self._parse_table()
    5898
    5899        self._match(TokenType.ON)
    5900        on = self._parse_conjunction()
    5901
    5902        return self.expression(
    5903            exp.Merge,
    5904            this=target,
    5905            using=using,
    5906            on=on,
    5907            expressions=self._parse_when_matched(),
    5908        )
    5909
    5910    def _parse_when_matched(self) -> t.List[exp.When]:
    5911        whens = []
    5912
    5913        while self._match(TokenType.WHEN):
    5914            matched = not self._match(TokenType.NOT)
    5915            self._match_text_seq("MATCHED")
    5916            source = (
    5917                False
    5918                if self._match_text_seq("BY", "TARGET")
    5919                else self._match_text_seq("BY", "SOURCE")
    5920            )
    5921            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
    5922
    5923            self._match(TokenType.THEN)
    5924
    5925            if self._match(TokenType.INSERT):
    5926                _this = self._parse_star()
    5927                if _this:
    5928                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    5929                else:
    5930                    then = self.expression(
    5931                        exp.Insert,
    5932                        this=self._parse_value(),
    5933                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    5934                    )
    5935            elif self._match(TokenType.UPDATE):
    5936                expressions = self._parse_star()
    5937                if expressions:
    5938                    then = self.expression(exp.Update, expressions=expressions)
    5939                else:
    5940                    then = self.expression(
    5941                        exp.Update,
    5942                        expressions=self._match(TokenType.SET)
    5943                        and self._parse_csv(self._parse_equality),
    5944                    )
    5945            elif self._match(TokenType.DELETE):
    5946                then = self.expression(exp.Var, this=self._prev.text)
    5947            else:
    5948                then = None
    5949
    5950            whens.append(
    5951                self.expression(
    5952                    exp.When,
    5953                    matched=matched,
    5954                    source=source,
    5955                    condition=condition,
    5956                    then=then,
    5957                )
    5958            )
    5959        return whens
    5960
    5961    def _parse_show(self) -> t.Optional[exp.Expression]:
    5962        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    5963        if parser:
    5964            return parser(self)
    5965        return self._parse_as_command(self._prev)
    5966
    5967    def _parse_set_item_assignment(
    5968        self, kind: t.Optional[str] = None
    5969    ) -> t.Optional[exp.Expression]:
    5970        index = self._index
    5971
    5972        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    5973            return self._parse_set_transaction(global_=kind == "GLOBAL")
    5974
    5975        left = self._parse_primary() or self._parse_id_var()
    5976        assignment_delimiter = self._match_texts(("=", "TO"))
    5977
    5978        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    5979            self._retreat(index)
    5980            return None
    5981
    5982        right = self._parse_statement() or self._parse_id_var()
    5983        this = self.expression(exp.EQ, this=left, expression=right)
    5984
    5985        return self.expression(exp.SetItem, this=this, kind=kind)
    5986
    5987    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    5988        self._match_text_seq("TRANSACTION")
    5989        characteristics = self._parse_csv(
    5990            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    5991        )
    5992        return self.expression(
    5993            exp.SetItem,
    5994            expressions=characteristics,
    5995            kind="TRANSACTION",
    5996            **{"global": global_},  # type: ignore
    5997        )
    5998
    5999    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    6000        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    6001        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    6002
    6003    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    6004        index = self._index
    6005        set_ = self.expression(
    6006            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    6007        )
    6008
    6009        if self._curr:
    6010            self._retreat(index)
    6011            return self._parse_as_command(self._prev)
    6012
    6013        return set_
    6014
    6015    def _parse_var_from_options(
    6016        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    6017    ) -> t.Optional[exp.Var]:
    6018        start = self._curr
    6019        if not start:
    6020            return None
    6021
    6022        option = start.text.upper()
    6023        continuations = options.get(option)
    6024
    6025        index = self._index
    6026        self._advance()
    6027        for keywords in continuations or []:
    6028            if isinstance(keywords, str):
    6029                keywords = (keywords,)
    6030
    6031            if self._match_text_seq(*keywords):
    6032                option = f"{option} {' '.join(keywords)}"
    6033                break
    6034        else:
    6035            if continuations or continuations is None:
    6036                if raise_unmatched:
    6037                    self.raise_error(f"Unknown option {option}")
    6038
    6039                self._retreat(index)
    6040                return None
    6041
    6042        return exp.var(option)
    6043
    6044    def _parse_as_command(self, start: Token) -> exp.Command:
    6045        while self._curr:
    6046            self._advance()
    6047        text = self._find_sql(start, self._prev)
    6048        size = len(start.text)
    6049        self._warn_unsupported()
    6050        return exp.Command(this=text[:size], expression=text[size:])
    6051
    6052    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    6053        settings = []
    6054
    6055        self._match_l_paren()
    6056        kind = self._parse_id_var()
    6057
    6058        if self._match(TokenType.L_PAREN):
    6059            while True:
    6060                key = self._parse_id_var()
    6061                value = self._parse_primary()
    6062
    6063                if not key and value is None:
    6064                    break
    6065                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    6066            self._match(TokenType.R_PAREN)
    6067
    6068        self._match_r_paren()
    6069
    6070        return self.expression(
    6071            exp.DictProperty,
    6072            this=this,
    6073            kind=kind.this if kind else None,
    6074            settings=settings,
    6075        )
    6076
    6077    def _parse_dict_range(self, this: str) -> exp.DictRange:
    6078        self._match_l_paren()
    6079        has_min = self._match_text_seq("MIN")
    6080        if has_min:
    6081            min = self._parse_var() or self._parse_primary()
    6082            self._match_text_seq("MAX")
    6083            max = self._parse_var() or self._parse_primary()
    6084        else:
    6085            max = self._parse_var() or self._parse_primary()
    6086            min = exp.Literal.number(0)
    6087        self._match_r_paren()
    6088        return self.expression(exp.DictRange, this=this, min=min, max=max)
    6089
    6090    def _parse_comprehension(
    6091        self, this: t.Optional[exp.Expression]
    6092    ) -> t.Optional[exp.Comprehension]:
    6093        index = self._index
    6094        expression = self._parse_column()
    6095        if not self._match(TokenType.IN):
    6096            self._retreat(index - 1)
    6097            return None
    6098        iterator = self._parse_column()
    6099        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
    6100        return self.expression(
    6101            exp.Comprehension,
    6102            this=this,
    6103            expression=expression,
    6104            iterator=iterator,
    6105            condition=condition,
    6106        )
    6107
    6108    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    6109        if self._match(TokenType.HEREDOC_STRING):
    6110            return self.expression(exp.Heredoc, this=self._prev.text)
    6111
    6112        if not self._match_text_seq("$"):
    6113            return None
    6114
    6115        tags = ["$"]
    6116        tag_text = None
    6117
    6118        if self._is_connected():
    6119            self._advance()
    6120            tags.append(self._prev.text.upper())
    6121        else:
    6122            self.raise_error("No closing $ found")
    6123
    6124        if tags[-1] != "$":
    6125            if self._is_connected() and self._match_text_seq("$"):
    6126                tag_text = tags[-1]
    6127                tags.append("$")
    6128            else:
    6129                self.raise_error("No closing $ found")
    6130
    6131        heredoc_start = self._curr
    6132
    6133        while self._curr:
    6134            if self._match_text_seq(*tags, advance=False):
    6135                this = self._find_sql(heredoc_start, self._prev)
    6136                self._advance(len(tags))
    6137                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    6138
    6139            self._advance()
    6140
    6141        self.raise_error(f"No closing {''.join(tags)} found")
    6142        return None
    6143
    6144    def _find_parser(
    6145        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    6146    ) -> t.Optional[t.Callable]:
    6147        if not self._curr:
    6148            return None
    6149
    6150        index = self._index
    6151        this = []
    6152        while True:
    6153            # The current token might be multiple words
    6154            curr = self._curr.text.upper()
    6155            key = curr.split(" ")
    6156            this.append(curr)
    6157
    6158            self._advance()
    6159            result, trie = in_trie(trie, key)
    6160            if result == TrieResult.FAILED:
    6161                break
    6162
    6163            if result == TrieResult.EXISTS:
    6164                subparser = parsers[" ".join(this)]
    6165                return subparser
    6166
    6167        self._retreat(index)
    6168        return None
    6169
    6170    def _match(self, token_type, advance=True, expression=None):
    6171        if not self._curr:
    6172            return None
    6173
    6174        if self._curr.token_type == token_type:
    6175            if advance:
    6176                self._advance()
    6177            self._add_comments(expression)
    6178            return True
    6179
    6180        return None
    6181
    6182    def _match_set(self, types, advance=True):
    6183        if not self._curr:
    6184            return None
    6185
    6186        if self._curr.token_type in types:
    6187            if advance:
    6188                self._advance()
    6189            return True
    6190
    6191        return None
    6192
    6193    def _match_pair(self, token_type_a, token_type_b, advance=True):
    6194        if not self._curr or not self._next:
    6195            return None
    6196
    6197        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    6198            if advance:
    6199                self._advance(2)
    6200            return True
    6201
    6202        return None
    6203
    6204    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6205        if not self._match(TokenType.L_PAREN, expression=expression):
    6206            self.raise_error("Expecting (")
    6207
    6208    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6209        if not self._match(TokenType.R_PAREN, expression=expression):
    6210            self.raise_error("Expecting )")
    6211
    6212    def _match_texts(self, texts, advance=True):
    6213        if self._curr and self._curr.text.upper() in texts:
    6214            if advance:
    6215                self._advance()
    6216            return True
    6217        return None
    6218
    6219    def _match_text_seq(self, *texts, advance=True):
    6220        index = self._index
    6221        for text in texts:
    6222            if self._curr and self._curr.text.upper() == text:
    6223                self._advance()
    6224            else:
    6225                self._retreat(index)
    6226                return None
    6227
    6228        if not advance:
    6229            self._retreat(index)
    6230
    6231        return True
    6232
    6233    def _replace_lambda(
    6234        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
    6235    ) -> t.Optional[exp.Expression]:
    6236        if not node:
    6237            return node
    6238
    6239        for column in node.find_all(exp.Column):
    6240            if column.parts[0].name in lambda_variables:
    6241                dot_or_id = column.to_dot() if column.table else column.this
    6242                parent = column.parent
    6243
    6244                while isinstance(parent, exp.Dot):
    6245                    if not isinstance(parent.parent, exp.Dot):
    6246                        parent.replace(dot_or_id)
    6247                        break
    6248                    parent = parent.parent
    6249                else:
    6250                    if column is node:
    6251                        node = dot_or_id
    6252                    else:
    6253                        column.replace(dot_or_id)
    6254        return node
    6255
    6256    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    6257        start = self._prev
    6258
    6259        # Not to be confused with TRUNCATE(number, decimals) function call
    6260        if self._match(TokenType.L_PAREN):
    6261            self._retreat(self._index - 2)
    6262            return self._parse_function()
    6263
    6264        # Clickhouse supports TRUNCATE DATABASE as well
    6265        is_database = self._match(TokenType.DATABASE)
    6266
    6267        self._match(TokenType.TABLE)
    6268
    6269        exists = self._parse_exists(not_=False)
    6270
    6271        expressions = self._parse_csv(
    6272            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    6273        )
    6274
    6275        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6276
    6277        if self._match_text_seq("RESTART", "IDENTITY"):
    6278            identity = "RESTART"
    6279        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    6280            identity = "CONTINUE"
    6281        else:
    6282            identity = None
    6283
    6284        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    6285            option = self._prev.text
    6286        else:
    6287            option = None
    6288
    6289        partition = self._parse_partition()
    6290
    6291        # Fallback case
    6292        if self._curr:
    6293            return self._parse_as_command(start)
    6294
    6295        return self.expression(
    6296            exp.TruncateTable,
    6297            expressions=expressions,
    6298            is_database=is_database,
    6299            exists=exists,
    6300            cluster=cluster,
    6301            identity=identity,
    6302            option=option,
    6303            partition=partition,
    6304        )
    6305
    6306    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    6307        this = self._parse_ordered(self._parse_opclass)
    6308
    6309        if not self._match(TokenType.WITH):
    6310            return this
    6311
    6312        op = self._parse_var(any_token=True)
    6313
    6314        return self.expression(exp.WithOperator, this=this, op=op)
    6315
    6316    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    6317        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    6318
    6319        options = []
    6320        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    6321            option = self._parse_unquoted_field()
    6322            value = None
    6323            # Some options are defined as functions with the values as params
    6324            if not isinstance(option, exp.Func):
    6325                # Different dialects might separate options and values by white space, "=" and "AS"
    6326                self._match(TokenType.EQ)
    6327                self._match(TokenType.ALIAS)
    6328                value = self._parse_unquoted_field()
    6329
    6330            param = self.expression(exp.CopyParameter, this=option, expression=value)
    6331            options.append(param)
    6332
    6333            if sep:
    6334                self._match(sep)
    6335
    6336        return options
    6337
    6338    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    6339        def parse_options():
    6340            opts = []
    6341            self._match(TokenType.EQ)
    6342            self._match(TokenType.L_PAREN)
    6343            while self._curr and not self._match(TokenType.R_PAREN):
    6344                opts.append(self._parse_conjunction())
    6345            return opts
    6346
    6347        expr = self.expression(exp.Credentials)
    6348
    6349        if self._match_text_seq("STORAGE_INTEGRATION", advance=False):
    6350            expr.set("storage", self._parse_conjunction())
    6351        if self._match_text_seq("CREDENTIALS"):
    6352            # Snowflake supports CREDENTIALS = (...), while Redshift CREDENTIALS <string>
    6353            creds = parse_options() if self._match(TokenType.EQ) else self._parse_field()
    6354            expr.set("credentials", creds)
    6355        if self._match_text_seq("ENCRYPTION"):
    6356            expr.set("encryption", parse_options())
    6357        if self._match_text_seq("IAM_ROLE"):
    6358            expr.set("iam_role", self._parse_field())
    6359        if self._match_text_seq("REGION"):
    6360            expr.set("region", self._parse_field())
    6361
    6362        return expr
    6363
    6364    def _parse_copy(self):
    6365        start = self._prev
    6366
    6367        self._match(TokenType.INTO)
    6368
    6369        this = (
    6370            self._parse_conjunction()
    6371            if self._match(TokenType.L_PAREN, advance=False)
    6372            else self._parse_table(schema=True)
    6373        )
    6374
    6375        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    6376
    6377        files = self._parse_csv(self._parse_conjunction)
    6378        credentials = self._parse_credentials()
    6379
    6380        self._match_text_seq("WITH")
    6381
    6382        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    6383
    6384        # Fallback case
    6385        if self._curr:
    6386            return self._parse_as_command(start)
    6387
    6388        return self.expression(
    6389            exp.Copy,
    6390            this=this,
    6391            kind=kind,
    6392            credentials=credentials,
    6393            files=files,
    6394            params=params,
    6395        )

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 isinstance(this, exp.UNWRAPPED_QUERIES):
    4328                this = self._parse_set_operations(
    4329                    self._parse_subquery(this=this, parse_alias=False)
    4330                )
    4331            elif isinstance(this, exp.Subquery):
    4332                this = self._parse_subquery(
    4333                    this=self._parse_set_operations(this), parse_alias=False
    4334                )
    4335            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    4336                this = self.expression(exp.Tuple, expressions=expressions)
    4337            else:
    4338                this = self.expression(exp.Paren, this=this)
    4339
    4340            if this:
    4341                this.add_comments(comments)
    4342
    4343            self._match_r_paren(expression=this)
    4344            return this
    4345
    4346        return None
    4347
    4348    def _parse_field(
    4349        self,
    4350        any_token: bool = False,
    4351        tokens: t.Optional[t.Collection[TokenType]] = None,
    4352        anonymous_func: bool = False,
    4353    ) -> t.Optional[exp.Expression]:
    4354        if anonymous_func:
    4355            field = (
    4356                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    4357                or self._parse_primary()
    4358            )
    4359        else:
    4360            field = self._parse_primary() or self._parse_function(
    4361                anonymous=anonymous_func, any_token=any_token
    4362            )
    4363        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    4364
    4365    def _parse_function(
    4366        self,
    4367        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4368        anonymous: bool = False,
    4369        optional_parens: bool = True,
    4370        any_token: bool = False,
    4371    ) -> t.Optional[exp.Expression]:
    4372        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    4373        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    4374        fn_syntax = False
    4375        if (
    4376            self._match(TokenType.L_BRACE, advance=False)
    4377            and self._next
    4378            and self._next.text.upper() == "FN"
    4379        ):
    4380            self._advance(2)
    4381            fn_syntax = True
    4382
    4383        func = self._parse_function_call(
    4384            functions=functions,
    4385            anonymous=anonymous,
    4386            optional_parens=optional_parens,
    4387            any_token=any_token,
    4388        )
    4389
    4390        if fn_syntax:
    4391            self._match(TokenType.R_BRACE)
    4392
    4393        return func
    4394
    4395    def _parse_function_call(
    4396        self,
    4397        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4398        anonymous: bool = False,
    4399        optional_parens: bool = True,
    4400        any_token: bool = False,
    4401    ) -> t.Optional[exp.Expression]:
    4402        if not self._curr:
    4403            return None
    4404
    4405        comments = self._curr.comments
    4406        token_type = self._curr.token_type
    4407        this = self._curr.text
    4408        upper = this.upper()
    4409
    4410        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    4411        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    4412            self._advance()
    4413            return self._parse_window(parser(self))
    4414
    4415        if not self._next or self._next.token_type != TokenType.L_PAREN:
    4416            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    4417                self._advance()
    4418                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    4419
    4420            return None
    4421
    4422        if any_token:
    4423            if token_type in self.RESERVED_TOKENS:
    4424                return None
    4425        elif token_type not in self.FUNC_TOKENS:
    4426            return None
    4427
    4428        self._advance(2)
    4429
    4430        parser = self.FUNCTION_PARSERS.get(upper)
    4431        if parser and not anonymous:
    4432            this = parser(self)
    4433        else:
    4434            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    4435
    4436            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    4437                this = self.expression(subquery_predicate, this=self._parse_select())
    4438                self._match_r_paren()
    4439                return this
    4440
    4441            if functions is None:
    4442                functions = self.FUNCTIONS
    4443
    4444            function = functions.get(upper)
    4445
    4446            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    4447            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    4448
    4449            if alias:
    4450                args = self._kv_to_prop_eq(args)
    4451
    4452            if function and not anonymous:
    4453                if "dialect" in function.__code__.co_varnames:
    4454                    func = function(args, dialect=self.dialect)
    4455                else:
    4456                    func = function(args)
    4457
    4458                func = self.validate_expression(func, args)
    4459                if not self.dialect.NORMALIZE_FUNCTIONS:
    4460                    func.meta["name"] = this
    4461
    4462                this = func
    4463            else:
    4464                if token_type == TokenType.IDENTIFIER:
    4465                    this = exp.Identifier(this=this, quoted=True)
    4466                this = self.expression(exp.Anonymous, this=this, expressions=args)
    4467
    4468        if isinstance(this, exp.Expression):
    4469            this.add_comments(comments)
    4470
    4471        self._match_r_paren(this)
    4472        return self._parse_window(this)
    4473
    4474    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    4475        transformed = []
    4476
    4477        for e in expressions:
    4478            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    4479                if isinstance(e, exp.Alias):
    4480                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    4481
    4482                if not isinstance(e, exp.PropertyEQ):
    4483                    e = self.expression(
    4484                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    4485                    )
    4486
    4487                if isinstance(e.this, exp.Column):
    4488                    e.this.replace(e.this.this)
    4489
    4490            transformed.append(e)
    4491
    4492        return transformed
    4493
    4494    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    4495        return self._parse_column_def(self._parse_id_var())
    4496
    4497    def _parse_user_defined_function(
    4498        self, kind: t.Optional[TokenType] = None
    4499    ) -> t.Optional[exp.Expression]:
    4500        this = self._parse_id_var()
    4501
    4502        while self._match(TokenType.DOT):
    4503            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    4504
    4505        if not self._match(TokenType.L_PAREN):
    4506            return this
    4507
    4508        expressions = self._parse_csv(self._parse_function_parameter)
    4509        self._match_r_paren()
    4510        return self.expression(
    4511            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    4512        )
    4513
    4514    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    4515        literal = self._parse_primary()
    4516        if literal:
    4517            return self.expression(exp.Introducer, this=token.text, expression=literal)
    4518
    4519        return self.expression(exp.Identifier, this=token.text)
    4520
    4521    def _parse_session_parameter(self) -> exp.SessionParameter:
    4522        kind = None
    4523        this = self._parse_id_var() or self._parse_primary()
    4524
    4525        if this and self._match(TokenType.DOT):
    4526            kind = this.name
    4527            this = self._parse_var() or self._parse_primary()
    4528
    4529        return self.expression(exp.SessionParameter, this=this, kind=kind)
    4530
    4531    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4532        index = self._index
    4533
    4534        if self._match(TokenType.L_PAREN):
    4535            expressions = t.cast(
    4536                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
    4537            )
    4538
    4539            if not self._match(TokenType.R_PAREN):
    4540                self._retreat(index)
    4541        else:
    4542            expressions = [self._parse_id_var()]
    4543
    4544        if self._match_set(self.LAMBDAS):
    4545            return self.LAMBDAS[self._prev.token_type](self, expressions)
    4546
    4547        self._retreat(index)
    4548
    4549        this: t.Optional[exp.Expression]
    4550
    4551        if self._match(TokenType.DISTINCT):
    4552            this = self.expression(
    4553                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
    4554            )
    4555        else:
    4556            this = self._parse_select_or_expression(alias=alias)
    4557
    4558        return self._parse_limit(
    4559            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    4560        )
    4561
    4562    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4563        index = self._index
    4564        if not self._match(TokenType.L_PAREN):
    4565            return this
    4566
    4567        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    4568        # expr can be of both types
    4569        if self._match_set(self.SELECT_START_TOKENS):
    4570            self._retreat(index)
    4571            return this
    4572        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    4573        self._match_r_paren()
    4574        return self.expression(exp.Schema, this=this, expressions=args)
    4575
    4576    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    4577        return self._parse_column_def(self._parse_field(any_token=True))
    4578
    4579    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4580        # column defs are not really columns, they're identifiers
    4581        if isinstance(this, exp.Column):
    4582            this = this.this
    4583
    4584        kind = self._parse_types(schema=True)
    4585
    4586        if self._match_text_seq("FOR", "ORDINALITY"):
    4587            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    4588
    4589        constraints: t.List[exp.Expression] = []
    4590
    4591        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    4592            ("ALIAS", "MATERIALIZED")
    4593        ):
    4594            persisted = self._prev.text.upper() == "MATERIALIZED"
    4595            constraints.append(
    4596                self.expression(
    4597                    exp.ComputedColumnConstraint,
    4598                    this=self._parse_conjunction(),
    4599                    persisted=persisted or self._match_text_seq("PERSISTED"),
    4600                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    4601                )
    4602            )
    4603        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
    4604            self._match(TokenType.ALIAS)
    4605            constraints.append(
    4606                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
    4607            )
    4608
    4609        while True:
    4610            constraint = self._parse_column_constraint()
    4611            if not constraint:
    4612                break
    4613            constraints.append(constraint)
    4614
    4615        if not kind and not constraints:
    4616            return this
    4617
    4618        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    4619
    4620    def _parse_auto_increment(
    4621        self,
    4622    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    4623        start = None
    4624        increment = None
    4625
    4626        if self._match(TokenType.L_PAREN, advance=False):
    4627            args = self._parse_wrapped_csv(self._parse_bitwise)
    4628            start = seq_get(args, 0)
    4629            increment = seq_get(args, 1)
    4630        elif self._match_text_seq("START"):
    4631            start = self._parse_bitwise()
    4632            self._match_text_seq("INCREMENT")
    4633            increment = self._parse_bitwise()
    4634
    4635        if start and increment:
    4636            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    4637
    4638        return exp.AutoIncrementColumnConstraint()
    4639
    4640    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    4641        if not self._match_text_seq("REFRESH"):
    4642            self._retreat(self._index - 1)
    4643            return None
    4644        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    4645
    4646    def _parse_compress(self) -> exp.CompressColumnConstraint:
    4647        if self._match(TokenType.L_PAREN, advance=False):
    4648            return self.expression(
    4649                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    4650            )
    4651
    4652        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    4653
    4654    def _parse_generated_as_identity(
    4655        self,
    4656    ) -> (
    4657        exp.GeneratedAsIdentityColumnConstraint
    4658        | exp.ComputedColumnConstraint
    4659        | exp.GeneratedAsRowColumnConstraint
    4660    ):
    4661        if self._match_text_seq("BY", "DEFAULT"):
    4662            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    4663            this = self.expression(
    4664                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    4665            )
    4666        else:
    4667            self._match_text_seq("ALWAYS")
    4668            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    4669
    4670        self._match(TokenType.ALIAS)
    4671
    4672        if self._match_text_seq("ROW"):
    4673            start = self._match_text_seq("START")
    4674            if not start:
    4675                self._match(TokenType.END)
    4676            hidden = self._match_text_seq("HIDDEN")
    4677            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    4678
    4679        identity = self._match_text_seq("IDENTITY")
    4680
    4681        if self._match(TokenType.L_PAREN):
    4682            if self._match(TokenType.START_WITH):
    4683                this.set("start", self._parse_bitwise())
    4684            if self._match_text_seq("INCREMENT", "BY"):
    4685                this.set("increment", self._parse_bitwise())
    4686            if self._match_text_seq("MINVALUE"):
    4687                this.set("minvalue", self._parse_bitwise())
    4688            if self._match_text_seq("MAXVALUE"):
    4689                this.set("maxvalue", self._parse_bitwise())
    4690
    4691            if self._match_text_seq("CYCLE"):
    4692                this.set("cycle", True)
    4693            elif self._match_text_seq("NO", "CYCLE"):
    4694                this.set("cycle", False)
    4695
    4696            if not identity:
    4697                this.set("expression", self._parse_range())
    4698            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    4699                args = self._parse_csv(self._parse_bitwise)
    4700                this.set("start", seq_get(args, 0))
    4701                this.set("increment", seq_get(args, 1))
    4702
    4703            self._match_r_paren()
    4704
    4705        return this
    4706
    4707    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    4708        self._match_text_seq("LENGTH")
    4709        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    4710
    4711    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    4712        if self._match_text_seq("NULL"):
    4713            return self.expression(exp.NotNullColumnConstraint)
    4714        if self._match_text_seq("CASESPECIFIC"):
    4715            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    4716        if self._match_text_seq("FOR", "REPLICATION"):
    4717            return self.expression(exp.NotForReplicationColumnConstraint)
    4718        return None
    4719
    4720    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    4721        if self._match(TokenType.CONSTRAINT):
    4722            this = self._parse_id_var()
    4723        else:
    4724            this = None
    4725
    4726        if self._match_texts(self.CONSTRAINT_PARSERS):
    4727            return self.expression(
    4728                exp.ColumnConstraint,
    4729                this=this,
    4730                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    4731            )
    4732
    4733        return this
    4734
    4735    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    4736        if not self._match(TokenType.CONSTRAINT):
    4737            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    4738
    4739        return self.expression(
    4740            exp.Constraint,
    4741            this=self._parse_id_var(),
    4742            expressions=self._parse_unnamed_constraints(),
    4743        )
    4744
    4745    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    4746        constraints = []
    4747        while True:
    4748            constraint = self._parse_unnamed_constraint() or self._parse_function()
    4749            if not constraint:
    4750                break
    4751            constraints.append(constraint)
    4752
    4753        return constraints
    4754
    4755    def _parse_unnamed_constraint(
    4756        self, constraints: t.Optional[t.Collection[str]] = None
    4757    ) -> t.Optional[exp.Expression]:
    4758        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    4759            constraints or self.CONSTRAINT_PARSERS
    4760        ):
    4761            return None
    4762
    4763        constraint = self._prev.text.upper()
    4764        if constraint not in self.CONSTRAINT_PARSERS:
    4765            self.raise_error(f"No parser found for schema constraint {constraint}.")
    4766
    4767        return self.CONSTRAINT_PARSERS[constraint](self)
    4768
    4769    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    4770        self._match_text_seq("KEY")
    4771        return self.expression(
    4772            exp.UniqueColumnConstraint,
    4773            this=self._parse_schema(self._parse_id_var(any_token=False)),
    4774            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    4775            on_conflict=self._parse_on_conflict(),
    4776        )
    4777
    4778    def _parse_key_constraint_options(self) -> t.List[str]:
    4779        options = []
    4780        while True:
    4781            if not self._curr:
    4782                break
    4783
    4784            if self._match(TokenType.ON):
    4785                action = None
    4786                on = self._advance_any() and self._prev.text
    4787
    4788                if self._match_text_seq("NO", "ACTION"):
    4789                    action = "NO ACTION"
    4790                elif self._match_text_seq("CASCADE"):
    4791                    action = "CASCADE"
    4792                elif self._match_text_seq("RESTRICT"):
    4793                    action = "RESTRICT"
    4794                elif self._match_pair(TokenType.SET, TokenType.NULL):
    4795                    action = "SET NULL"
    4796                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    4797                    action = "SET DEFAULT"
    4798                else:
    4799                    self.raise_error("Invalid key constraint")
    4800
    4801                options.append(f"ON {on} {action}")
    4802            elif self._match_text_seq("NOT", "ENFORCED"):
    4803                options.append("NOT ENFORCED")
    4804            elif self._match_text_seq("DEFERRABLE"):
    4805                options.append("DEFERRABLE")
    4806            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    4807                options.append("INITIALLY DEFERRED")
    4808            elif self._match_text_seq("NORELY"):
    4809                options.append("NORELY")
    4810            elif self._match_text_seq("MATCH", "FULL"):
    4811                options.append("MATCH FULL")
    4812            else:
    4813                break
    4814
    4815        return options
    4816
    4817    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    4818        if match and not self._match(TokenType.REFERENCES):
    4819            return None
    4820
    4821        expressions = None
    4822        this = self._parse_table(schema=True)
    4823        options = self._parse_key_constraint_options()
    4824        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    4825
    4826    def _parse_foreign_key(self) -> exp.ForeignKey:
    4827        expressions = self._parse_wrapped_id_vars()
    4828        reference = self._parse_references()
    4829        options = {}
    4830
    4831        while self._match(TokenType.ON):
    4832            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    4833                self.raise_error("Expected DELETE or UPDATE")
    4834
    4835            kind = self._prev.text.lower()
    4836
    4837            if self._match_text_seq("NO", "ACTION"):
    4838                action = "NO ACTION"
    4839            elif self._match(TokenType.SET):
    4840                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    4841                action = "SET " + self._prev.text.upper()
    4842            else:
    4843                self._advance()
    4844                action = self._prev.text.upper()
    4845
    4846            options[kind] = action
    4847
    4848        return self.expression(
    4849            exp.ForeignKey,
    4850            expressions=expressions,
    4851            reference=reference,
    4852            **options,  # type: ignore
    4853        )
    4854
    4855    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    4856        return self._parse_field()
    4857
    4858    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    4859        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    4860            self._retreat(self._index - 1)
    4861            return None
    4862
    4863        id_vars = self._parse_wrapped_id_vars()
    4864        return self.expression(
    4865            exp.PeriodForSystemTimeConstraint,
    4866            this=seq_get(id_vars, 0),
    4867            expression=seq_get(id_vars, 1),
    4868        )
    4869
    4870    def _parse_primary_key(
    4871        self, wrapped_optional: bool = False, in_props: bool = False
    4872    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    4873        desc = (
    4874            self._match_set((TokenType.ASC, TokenType.DESC))
    4875            and self._prev.token_type == TokenType.DESC
    4876        )
    4877
    4878        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    4879            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    4880
    4881        expressions = self._parse_wrapped_csv(
    4882            self._parse_primary_key_part, optional=wrapped_optional
    4883        )
    4884        options = self._parse_key_constraint_options()
    4885        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    4886
    4887    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    4888        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
    4889
    4890    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4891        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    4892            return this
    4893
    4894        bracket_kind = self._prev.token_type
    4895        expressions = self._parse_csv(
    4896            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    4897        )
    4898
    4899        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    4900            self.raise_error("Expected ]")
    4901        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    4902            self.raise_error("Expected }")
    4903
    4904        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    4905        if bracket_kind == TokenType.L_BRACE:
    4906            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    4907        elif not this or this.name.upper() == "ARRAY":
    4908            this = self.expression(exp.Array, expressions=expressions)
    4909        else:
    4910            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    4911            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    4912
    4913        self._add_comments(this)
    4914        return self._parse_bracket(this)
    4915
    4916    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4917        if self._match(TokenType.COLON):
    4918            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
    4919        return this
    4920
    4921    def _parse_case(self) -> t.Optional[exp.Expression]:
    4922        ifs = []
    4923        default = None
    4924
    4925        comments = self._prev_comments
    4926        expression = self._parse_conjunction()
    4927
    4928        while self._match(TokenType.WHEN):
    4929            this = self._parse_conjunction()
    4930            self._match(TokenType.THEN)
    4931            then = self._parse_conjunction()
    4932            ifs.append(self.expression(exp.If, this=this, true=then))
    4933
    4934        if self._match(TokenType.ELSE):
    4935            default = self._parse_conjunction()
    4936
    4937        if not self._match(TokenType.END):
    4938            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    4939                default = exp.column("interval")
    4940            else:
    4941                self.raise_error("Expected END after CASE", self._prev)
    4942
    4943        return self.expression(
    4944            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    4945        )
    4946
    4947    def _parse_if(self) -> t.Optional[exp.Expression]:
    4948        if self._match(TokenType.L_PAREN):
    4949            args = self._parse_csv(self._parse_conjunction)
    4950            this = self.validate_expression(exp.If.from_arg_list(args), args)
    4951            self._match_r_paren()
    4952        else:
    4953            index = self._index - 1
    4954
    4955            if self.NO_PAREN_IF_COMMANDS and index == 0:
    4956                return self._parse_as_command(self._prev)
    4957
    4958            condition = self._parse_conjunction()
    4959
    4960            if not condition:
    4961                self._retreat(index)
    4962                return None
    4963
    4964            self._match(TokenType.THEN)
    4965            true = self._parse_conjunction()
    4966            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
    4967            self._match(TokenType.END)
    4968            this = self.expression(exp.If, this=condition, true=true, false=false)
    4969
    4970        return this
    4971
    4972    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    4973        if not self._match_text_seq("VALUE", "FOR"):
    4974            self._retreat(self._index - 1)
    4975            return None
    4976
    4977        return self.expression(
    4978            exp.NextValueFor,
    4979            this=self._parse_column(),
    4980            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    4981        )
    4982
    4983    def _parse_extract(self) -> exp.Extract:
    4984        this = self._parse_function() or self._parse_var() or self._parse_type()
    4985
    4986        if self._match(TokenType.FROM):
    4987            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    4988
    4989        if not self._match(TokenType.COMMA):
    4990            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    4991
    4992        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    4993
    4994    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    4995        this = self._parse_conjunction()
    4996
    4997        if not self._match(TokenType.ALIAS):
    4998            if self._match(TokenType.COMMA):
    4999                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    5000
    5001            self.raise_error("Expected AS after CAST")
    5002
    5003        fmt = None
    5004        to = self._parse_types()
    5005
    5006        if self._match(TokenType.FORMAT):
    5007            fmt_string = self._parse_string()
    5008            fmt = self._parse_at_time_zone(fmt_string)
    5009
    5010            if not to:
    5011                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    5012            if to.this in exp.DataType.TEMPORAL_TYPES:
    5013                this = self.expression(
    5014                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    5015                    this=this,
    5016                    format=exp.Literal.string(
    5017                        format_time(
    5018                            fmt_string.this if fmt_string else "",
    5019                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    5020                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    5021                        )
    5022                    ),
    5023                )
    5024
    5025                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    5026                    this.set("zone", fmt.args["zone"])
    5027                return this
    5028        elif not to:
    5029            self.raise_error("Expected TYPE after CAST")
    5030        elif isinstance(to, exp.Identifier):
    5031            to = exp.DataType.build(to.name, udt=True)
    5032        elif to.this == exp.DataType.Type.CHAR:
    5033            if self._match(TokenType.CHARACTER_SET):
    5034                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    5035
    5036        return self.expression(
    5037            exp.Cast if strict else exp.TryCast,
    5038            this=this,
    5039            to=to,
    5040            format=fmt,
    5041            safe=safe,
    5042            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    5043        )
    5044
    5045    def _parse_string_agg(self) -> exp.Expression:
    5046        if self._match(TokenType.DISTINCT):
    5047            args: t.List[t.Optional[exp.Expression]] = [
    5048                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
    5049            ]
    5050            if self._match(TokenType.COMMA):
    5051                args.extend(self._parse_csv(self._parse_conjunction))
    5052        else:
    5053            args = self._parse_csv(self._parse_conjunction)  # type: ignore
    5054
    5055        index = self._index
    5056        if not self._match(TokenType.R_PAREN) and args:
    5057            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    5058            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    5059            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    5060            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    5061
    5062        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    5063        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    5064        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    5065        if not self._match_text_seq("WITHIN", "GROUP"):
    5066            self._retreat(index)
    5067            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    5068
    5069        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    5070        order = self._parse_order(this=seq_get(args, 0))
    5071        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    5072
    5073    def _parse_convert(
    5074        self, strict: bool, safe: t.Optional[bool] = None
    5075    ) -> t.Optional[exp.Expression]:
    5076        this = self._parse_bitwise()
    5077
    5078        if self._match(TokenType.USING):
    5079            to: t.Optional[exp.Expression] = self.expression(
    5080                exp.CharacterSet, this=self._parse_var()
    5081            )
    5082        elif self._match(TokenType.COMMA):
    5083            to = self._parse_types()
    5084        else:
    5085            to = None
    5086
    5087        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    5088
    5089    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    5090        """
    5091        There are generally two variants of the DECODE function:
    5092
    5093        - DECODE(bin, charset)
    5094        - DECODE(expression, search, result [, search, result] ... [, default])
    5095
    5096        The second variant will always be parsed into a CASE expression. Note that NULL
    5097        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    5098        instead of relying on pattern matching.
    5099        """
    5100        args = self._parse_csv(self._parse_conjunction)
    5101
    5102        if len(args) < 3:
    5103            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    5104
    5105        expression, *expressions = args
    5106        if not expression:
    5107            return None
    5108
    5109        ifs = []
    5110        for search, result in zip(expressions[::2], expressions[1::2]):
    5111            if not search or not result:
    5112                return None
    5113
    5114            if isinstance(search, exp.Literal):
    5115                ifs.append(
    5116                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    5117                )
    5118            elif isinstance(search, exp.Null):
    5119                ifs.append(
    5120                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    5121                )
    5122            else:
    5123                cond = exp.or_(
    5124                    exp.EQ(this=expression.copy(), expression=search),
    5125                    exp.and_(
    5126                        exp.Is(this=expression.copy(), expression=exp.Null()),
    5127                        exp.Is(this=search.copy(), expression=exp.Null()),
    5128                        copy=False,
    5129                    ),
    5130                    copy=False,
    5131                )
    5132                ifs.append(exp.If(this=cond, true=result))
    5133
    5134        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    5135
    5136    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    5137        self._match_text_seq("KEY")
    5138        key = self._parse_column()
    5139        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    5140        self._match_text_seq("VALUE")
    5141        value = self._parse_bitwise()
    5142
    5143        if not key and not value:
    5144            return None
    5145        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    5146
    5147    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5148        if not this or not self._match_text_seq("FORMAT", "JSON"):
    5149            return this
    5150
    5151        return self.expression(exp.FormatJson, this=this)
    5152
    5153    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
    5154        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
    5155        for value in values:
    5156            if self._match_text_seq(value, "ON", on):
    5157                return f"{value} ON {on}"
    5158
    5159        return None
    5160
    5161    @t.overload
    5162    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    5163
    5164    @t.overload
    5165    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    5166
    5167    def _parse_json_object(self, agg=False):
    5168        star = self._parse_star()
    5169        expressions = (
    5170            [star]
    5171            if star
    5172            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    5173        )
    5174        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    5175
    5176        unique_keys = None
    5177        if self._match_text_seq("WITH", "UNIQUE"):
    5178            unique_keys = True
    5179        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    5180            unique_keys = False
    5181
    5182        self._match_text_seq("KEYS")
    5183
    5184        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    5185            self._parse_type()
    5186        )
    5187        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    5188
    5189        return self.expression(
    5190            exp.JSONObjectAgg if agg else exp.JSONObject,
    5191            expressions=expressions,
    5192            null_handling=null_handling,
    5193            unique_keys=unique_keys,
    5194            return_type=return_type,
    5195            encoding=encoding,
    5196        )
    5197
    5198    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    5199    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    5200        if not self._match_text_seq("NESTED"):
    5201            this = self._parse_id_var()
    5202            kind = self._parse_types(allow_identifiers=False)
    5203            nested = None
    5204        else:
    5205            this = None
    5206            kind = None
    5207            nested = True
    5208
    5209        path = self._match_text_seq("PATH") and self._parse_string()
    5210        nested_schema = nested and self._parse_json_schema()
    5211
    5212        return self.expression(
    5213            exp.JSONColumnDef,
    5214            this=this,
    5215            kind=kind,
    5216            path=path,
    5217            nested_schema=nested_schema,
    5218        )
    5219
    5220    def _parse_json_schema(self) -> exp.JSONSchema:
    5221        self._match_text_seq("COLUMNS")
    5222        return self.expression(
    5223            exp.JSONSchema,
    5224            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    5225        )
    5226
    5227    def _parse_json_table(self) -> exp.JSONTable:
    5228        this = self._parse_format_json(self._parse_bitwise())
    5229        path = self._match(TokenType.COMMA) and self._parse_string()
    5230        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    5231        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    5232        schema = self._parse_json_schema()
    5233
    5234        return exp.JSONTable(
    5235            this=this,
    5236            schema=schema,
    5237            path=path,
    5238            error_handling=error_handling,
    5239            empty_handling=empty_handling,
    5240        )
    5241
    5242    def _parse_match_against(self) -> exp.MatchAgainst:
    5243        expressions = self._parse_csv(self._parse_column)
    5244
    5245        self._match_text_seq(")", "AGAINST", "(")
    5246
    5247        this = self._parse_string()
    5248
    5249        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    5250            modifier = "IN NATURAL LANGUAGE MODE"
    5251            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5252                modifier = f"{modifier} WITH QUERY EXPANSION"
    5253        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    5254            modifier = "IN BOOLEAN MODE"
    5255        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5256            modifier = "WITH QUERY EXPANSION"
    5257        else:
    5258            modifier = None
    5259
    5260        return self.expression(
    5261            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    5262        )
    5263
    5264    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    5265    def _parse_open_json(self) -> exp.OpenJSON:
    5266        this = self._parse_bitwise()
    5267        path = self._match(TokenType.COMMA) and self._parse_string()
    5268
    5269        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    5270            this = self._parse_field(any_token=True)
    5271            kind = self._parse_types()
    5272            path = self._parse_string()
    5273            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    5274
    5275            return self.expression(
    5276                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    5277            )
    5278
    5279        expressions = None
    5280        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    5281            self._match_l_paren()
    5282            expressions = self._parse_csv(_parse_open_json_column_def)
    5283
    5284        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    5285
    5286    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    5287        args = self._parse_csv(self._parse_bitwise)
    5288
    5289        if self._match(TokenType.IN):
    5290            return self.expression(
    5291                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    5292            )
    5293
    5294        if haystack_first:
    5295            haystack = seq_get(args, 0)
    5296            needle = seq_get(args, 1)
    5297        else:
    5298            needle = seq_get(args, 0)
    5299            haystack = seq_get(args, 1)
    5300
    5301        return self.expression(
    5302            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    5303        )
    5304
    5305    def _parse_predict(self) -> exp.Predict:
    5306        self._match_text_seq("MODEL")
    5307        this = self._parse_table()
    5308
    5309        self._match(TokenType.COMMA)
    5310        self._match_text_seq("TABLE")
    5311
    5312        return self.expression(
    5313            exp.Predict,
    5314            this=this,
    5315            expression=self._parse_table(),
    5316            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    5317        )
    5318
    5319    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    5320        args = self._parse_csv(self._parse_table)
    5321        return exp.JoinHint(this=func_name.upper(), expressions=args)
    5322
    5323    def _parse_substring(self) -> exp.Substring:
    5324        # Postgres supports the form: substring(string [from int] [for int])
    5325        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    5326
    5327        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    5328
    5329        if self._match(TokenType.FROM):
    5330            args.append(self._parse_bitwise())
    5331        if self._match(TokenType.FOR):
    5332            if len(args) == 1:
    5333                args.append(exp.Literal.number(1))
    5334            args.append(self._parse_bitwise())
    5335
    5336        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    5337
    5338    def _parse_trim(self) -> exp.Trim:
    5339        # https://www.w3resource.com/sql/character-functions/trim.php
    5340        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    5341
    5342        position = None
    5343        collation = None
    5344        expression = None
    5345
    5346        if self._match_texts(self.TRIM_TYPES):
    5347            position = self._prev.text.upper()
    5348
    5349        this = self._parse_bitwise()
    5350        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    5351            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    5352            expression = self._parse_bitwise()
    5353
    5354            if invert_order:
    5355                this, expression = expression, this
    5356
    5357        if self._match(TokenType.COLLATE):
    5358            collation = self._parse_bitwise()
    5359
    5360        return self.expression(
    5361            exp.Trim, this=this, position=position, expression=expression, collation=collation
    5362        )
    5363
    5364    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    5365        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    5366
    5367    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    5368        return self._parse_window(self._parse_id_var(), alias=True)
    5369
    5370    def _parse_respect_or_ignore_nulls(
    5371        self, this: t.Optional[exp.Expression]
    5372    ) -> t.Optional[exp.Expression]:
    5373        if self._match_text_seq("IGNORE", "NULLS"):
    5374            return self.expression(exp.IgnoreNulls, this=this)
    5375        if self._match_text_seq("RESPECT", "NULLS"):
    5376            return self.expression(exp.RespectNulls, this=this)
    5377        return this
    5378
    5379    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5380        if self._match(TokenType.HAVING):
    5381            self._match_texts(("MAX", "MIN"))
    5382            max = self._prev.text.upper() != "MIN"
    5383            return self.expression(
    5384                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    5385            )
    5386
    5387        return this
    5388
    5389    def _parse_window(
    5390        self, this: t.Optional[exp.Expression], alias: bool = False
    5391    ) -> t.Optional[exp.Expression]:
    5392        func = this
    5393        comments = func.comments if isinstance(func, exp.Expression) else None
    5394
    5395        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    5396            self._match(TokenType.WHERE)
    5397            this = self.expression(
    5398                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    5399            )
    5400            self._match_r_paren()
    5401
    5402        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    5403        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    5404        if self._match_text_seq("WITHIN", "GROUP"):
    5405            order = self._parse_wrapped(self._parse_order)
    5406            this = self.expression(exp.WithinGroup, this=this, expression=order)
    5407
    5408        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    5409        # Some dialects choose to implement and some do not.
    5410        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    5411
    5412        # There is some code above in _parse_lambda that handles
    5413        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    5414
    5415        # The below changes handle
    5416        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    5417
    5418        # Oracle allows both formats
    5419        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    5420        #   and Snowflake chose to do the same for familiarity
    5421        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    5422        if isinstance(this, exp.AggFunc):
    5423            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    5424
    5425            if ignore_respect and ignore_respect is not this:
    5426                ignore_respect.replace(ignore_respect.this)
    5427                this = self.expression(ignore_respect.__class__, this=this)
    5428
    5429        this = self._parse_respect_or_ignore_nulls(this)
    5430
    5431        # bigquery select from window x AS (partition by ...)
    5432        if alias:
    5433            over = None
    5434            self._match(TokenType.ALIAS)
    5435        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    5436            return this
    5437        else:
    5438            over = self._prev.text.upper()
    5439
    5440        if comments and isinstance(func, exp.Expression):
    5441            func.pop_comments()
    5442
    5443        if not self._match(TokenType.L_PAREN):
    5444            return self.expression(
    5445                exp.Window,
    5446                comments=comments,
    5447                this=this,
    5448                alias=self._parse_id_var(False),
    5449                over=over,
    5450            )
    5451
    5452        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    5453
    5454        first = self._match(TokenType.FIRST)
    5455        if self._match_text_seq("LAST"):
    5456            first = False
    5457
    5458        partition, order = self._parse_partition_and_order()
    5459        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    5460
    5461        if kind:
    5462            self._match(TokenType.BETWEEN)
    5463            start = self._parse_window_spec()
    5464            self._match(TokenType.AND)
    5465            end = self._parse_window_spec()
    5466
    5467            spec = self.expression(
    5468                exp.WindowSpec,
    5469                kind=kind,
    5470                start=start["value"],
    5471                start_side=start["side"],
    5472                end=end["value"],
    5473                end_side=end["side"],
    5474            )
    5475        else:
    5476            spec = None
    5477
    5478        self._match_r_paren()
    5479
    5480        window = self.expression(
    5481            exp.Window,
    5482            comments=comments,
    5483            this=this,
    5484            partition_by=partition,
    5485            order=order,
    5486            spec=spec,
    5487            alias=window_alias,
    5488            over=over,
    5489            first=first,
    5490        )
    5491
    5492        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    5493        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    5494            return self._parse_window(window, alias=alias)
    5495
    5496        return window
    5497
    5498    def _parse_partition_and_order(
    5499        self,
    5500    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    5501        return self._parse_partition_by(), self._parse_order()
    5502
    5503    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    5504        self._match(TokenType.BETWEEN)
    5505
    5506        return {
    5507            "value": (
    5508                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    5509                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    5510                or self._parse_bitwise()
    5511            ),
    5512            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    5513        }
    5514
    5515    def _parse_alias(
    5516        self, this: t.Optional[exp.Expression], explicit: bool = False
    5517    ) -> t.Optional[exp.Expression]:
    5518        any_token = self._match(TokenType.ALIAS)
    5519        comments = self._prev_comments or []
    5520
    5521        if explicit and not any_token:
    5522            return this
    5523
    5524        if self._match(TokenType.L_PAREN):
    5525            aliases = self.expression(
    5526                exp.Aliases,
    5527                comments=comments,
    5528                this=this,
    5529                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    5530            )
    5531            self._match_r_paren(aliases)
    5532            return aliases
    5533
    5534        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    5535            self.STRING_ALIASES and self._parse_string_as_identifier()
    5536        )
    5537
    5538        if alias:
    5539            comments.extend(alias.pop_comments())
    5540            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    5541            column = this.this
    5542
    5543            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    5544            if not this.comments and column and column.comments:
    5545                this.comments = column.pop_comments()
    5546
    5547        return this
    5548
    5549    def _parse_id_var(
    5550        self,
    5551        any_token: bool = True,
    5552        tokens: t.Optional[t.Collection[TokenType]] = None,
    5553    ) -> t.Optional[exp.Expression]:
    5554        expression = self._parse_identifier()
    5555        if not expression and (
    5556            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    5557        ):
    5558            quoted = self._prev.token_type == TokenType.STRING
    5559            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    5560
    5561        return expression
    5562
    5563    def _parse_string(self) -> t.Optional[exp.Expression]:
    5564        if self._match_set(self.STRING_PARSERS):
    5565            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    5566        return self._parse_placeholder()
    5567
    5568    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    5569        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    5570
    5571    def _parse_number(self) -> t.Optional[exp.Expression]:
    5572        if self._match_set(self.NUMERIC_PARSERS):
    5573            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    5574        return self._parse_placeholder()
    5575
    5576    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    5577        if self._match(TokenType.IDENTIFIER):
    5578            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    5579        return self._parse_placeholder()
    5580
    5581    def _parse_var(
    5582        self,
    5583        any_token: bool = False,
    5584        tokens: t.Optional[t.Collection[TokenType]] = None,
    5585        upper: bool = False,
    5586    ) -> t.Optional[exp.Expression]:
    5587        if (
    5588            (any_token and self._advance_any())
    5589            or self._match(TokenType.VAR)
    5590            or (self._match_set(tokens) if tokens else False)
    5591        ):
    5592            return self.expression(
    5593                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    5594            )
    5595        return self._parse_placeholder()
    5596
    5597    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    5598        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    5599            self._advance()
    5600            return self._prev
    5601        return None
    5602
    5603    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    5604        return self._parse_var() or self._parse_string()
    5605
    5606    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    5607        return self._parse_primary() or self._parse_var(any_token=True)
    5608
    5609    def _parse_null(self) -> t.Optional[exp.Expression]:
    5610        if self._match_set(self.NULL_TOKENS):
    5611            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    5612        return self._parse_placeholder()
    5613
    5614    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    5615        if self._match(TokenType.TRUE):
    5616            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    5617        if self._match(TokenType.FALSE):
    5618            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    5619        return self._parse_placeholder()
    5620
    5621    def _parse_star(self) -> t.Optional[exp.Expression]:
    5622        if self._match(TokenType.STAR):
    5623            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    5624        return self._parse_placeholder()
    5625
    5626    def _parse_parameter(self) -> exp.Parameter:
    5627        self._match(TokenType.L_BRACE)
    5628        this = self._parse_identifier() or self._parse_primary_or_var()
    5629        expression = self._match(TokenType.COLON) and (
    5630            self._parse_identifier() or self._parse_primary_or_var()
    5631        )
    5632        self._match(TokenType.R_BRACE)
    5633        return self.expression(exp.Parameter, this=this, expression=expression)
    5634
    5635    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    5636        if self._match_set(self.PLACEHOLDER_PARSERS):
    5637            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    5638            if placeholder:
    5639                return placeholder
    5640            self._advance(-1)
    5641        return None
    5642
    5643    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
    5644        if not self._match(TokenType.EXCEPT):
    5645            return None
    5646        if self._match(TokenType.L_PAREN, advance=False):
    5647            return self._parse_wrapped_csv(self._parse_column)
    5648
    5649        except_column = self._parse_column()
    5650        return [except_column] if except_column else None
    5651
    5652    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
    5653        if not self._match(TokenType.REPLACE):
    5654            return None
    5655        if self._match(TokenType.L_PAREN, advance=False):
    5656            return self._parse_wrapped_csv(self._parse_expression)
    5657
    5658        replace_expression = self._parse_expression()
    5659        return [replace_expression] if replace_expression else None
    5660
    5661    def _parse_csv(
    5662        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    5663    ) -> t.List[exp.Expression]:
    5664        parse_result = parse_method()
    5665        items = [parse_result] if parse_result is not None else []
    5666
    5667        while self._match(sep):
    5668            self._add_comments(parse_result)
    5669            parse_result = parse_method()
    5670            if parse_result is not None:
    5671                items.append(parse_result)
    5672
    5673        return items
    5674
    5675    def _parse_tokens(
    5676        self, parse_method: t.Callable, expressions: t.Dict
    5677    ) -> t.Optional[exp.Expression]:
    5678        this = parse_method()
    5679
    5680        while self._match_set(expressions):
    5681            this = self.expression(
    5682                expressions[self._prev.token_type],
    5683                this=this,
    5684                comments=self._prev_comments,
    5685                expression=parse_method(),
    5686            )
    5687
    5688        return this
    5689
    5690    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    5691        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    5692
    5693    def _parse_wrapped_csv(
    5694        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    5695    ) -> t.List[exp.Expression]:
    5696        return self._parse_wrapped(
    5697            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    5698        )
    5699
    5700    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    5701        wrapped = self._match(TokenType.L_PAREN)
    5702        if not wrapped and not optional:
    5703            self.raise_error("Expecting (")
    5704        parse_result = parse_method()
    5705        if wrapped:
    5706            self._match_r_paren()
    5707        return parse_result
    5708
    5709    def _parse_expressions(self) -> t.List[exp.Expression]:
    5710        return self._parse_csv(self._parse_expression)
    5711
    5712    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5713        return self._parse_select() or self._parse_set_operations(
    5714            self._parse_expression() if alias else self._parse_conjunction()
    5715        )
    5716
    5717    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    5718        return self._parse_query_modifiers(
    5719            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    5720        )
    5721
    5722    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    5723        this = None
    5724        if self._match_texts(self.TRANSACTION_KIND):
    5725            this = self._prev.text
    5726
    5727        self._match_texts(("TRANSACTION", "WORK"))
    5728
    5729        modes = []
    5730        while True:
    5731            mode = []
    5732            while self._match(TokenType.VAR):
    5733                mode.append(self._prev.text)
    5734
    5735            if mode:
    5736                modes.append(" ".join(mode))
    5737            if not self._match(TokenType.COMMA):
    5738                break
    5739
    5740        return self.expression(exp.Transaction, this=this, modes=modes)
    5741
    5742    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    5743        chain = None
    5744        savepoint = None
    5745        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    5746
    5747        self._match_texts(("TRANSACTION", "WORK"))
    5748
    5749        if self._match_text_seq("TO"):
    5750            self._match_text_seq("SAVEPOINT")
    5751            savepoint = self._parse_id_var()
    5752
    5753        if self._match(TokenType.AND):
    5754            chain = not self._match_text_seq("NO")
    5755            self._match_text_seq("CHAIN")
    5756
    5757        if is_rollback:
    5758            return self.expression(exp.Rollback, savepoint=savepoint)
    5759
    5760        return self.expression(exp.Commit, chain=chain)
    5761
    5762    def _parse_refresh(self) -> exp.Refresh:
    5763        self._match(TokenType.TABLE)
    5764        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    5765
    5766    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    5767        if not self._match_text_seq("ADD"):
    5768            return None
    5769
    5770        self._match(TokenType.COLUMN)
    5771        exists_column = self._parse_exists(not_=True)
    5772        expression = self._parse_field_def()
    5773
    5774        if expression:
    5775            expression.set("exists", exists_column)
    5776
    5777            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    5778            if self._match_texts(("FIRST", "AFTER")):
    5779                position = self._prev.text
    5780                column_position = self.expression(
    5781                    exp.ColumnPosition, this=self._parse_column(), position=position
    5782                )
    5783                expression.set("position", column_position)
    5784
    5785        return expression
    5786
    5787    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    5788        drop = self._match(TokenType.DROP) and self._parse_drop()
    5789        if drop and not isinstance(drop, exp.Command):
    5790            drop.set("kind", drop.args.get("kind", "COLUMN"))
    5791        return drop
    5792
    5793    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    5794    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    5795        return self.expression(
    5796            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    5797        )
    5798
    5799    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    5800        index = self._index - 1
    5801
    5802        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    5803            return self._parse_csv(
    5804                lambda: self.expression(
    5805                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    5806                )
    5807            )
    5808
    5809        self._retreat(index)
    5810        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    5811            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    5812        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    5813
    5814    def _parse_alter_table_alter(self) -> exp.AlterColumn:
    5815        self._match(TokenType.COLUMN)
    5816        column = self._parse_field(any_token=True)
    5817
    5818        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    5819            return self.expression(exp.AlterColumn, this=column, drop=True)
    5820        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5821            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
    5822        if self._match(TokenType.COMMENT):
    5823            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    5824
    5825        self._match_text_seq("SET", "DATA")
    5826        self._match_text_seq("TYPE")
    5827        return self.expression(
    5828            exp.AlterColumn,
    5829            this=column,
    5830            dtype=self._parse_types(),
    5831            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    5832            using=self._match(TokenType.USING) and self._parse_conjunction(),
    5833        )
    5834
    5835    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    5836        index = self._index - 1
    5837
    5838        partition_exists = self._parse_exists()
    5839        if self._match(TokenType.PARTITION, advance=False):
    5840            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    5841
    5842        self._retreat(index)
    5843        return self._parse_csv(self._parse_drop_column)
    5844
    5845    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
    5846        if self._match(TokenType.COLUMN):
    5847            exists = self._parse_exists()
    5848            old_column = self._parse_column()
    5849            to = self._match_text_seq("TO")
    5850            new_column = self._parse_column()
    5851
    5852            if old_column is None or to is None or new_column is None:
    5853                return None
    5854
    5855            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    5856
    5857        self._match_text_seq("TO")
    5858        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    5859
    5860    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    5861        start = self._prev
    5862
    5863        if not self._match(TokenType.TABLE):
    5864            return self._parse_as_command(start)
    5865
    5866        exists = self._parse_exists()
    5867        only = self._match_text_seq("ONLY")
    5868        this = self._parse_table(schema=True)
    5869
    5870        if self._next:
    5871            self._advance()
    5872
    5873        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    5874        if parser:
    5875            actions = ensure_list(parser(self))
    5876            options = self._parse_csv(self._parse_property)
    5877
    5878            if not self._curr and actions:
    5879                return self.expression(
    5880                    exp.AlterTable,
    5881                    this=this,
    5882                    exists=exists,
    5883                    actions=actions,
    5884                    only=only,
    5885                    options=options,
    5886                )
    5887
    5888        return self._parse_as_command(start)
    5889
    5890    def _parse_merge(self) -> exp.Merge:
    5891        self._match(TokenType.INTO)
    5892        target = self._parse_table()
    5893
    5894        if target and self._match(TokenType.ALIAS, advance=False):
    5895            target.set("alias", self._parse_table_alias())
    5896
    5897        self._match(TokenType.USING)
    5898        using = self._parse_table()
    5899
    5900        self._match(TokenType.ON)
    5901        on = self._parse_conjunction()
    5902
    5903        return self.expression(
    5904            exp.Merge,
    5905            this=target,
    5906            using=using,
    5907            on=on,
    5908            expressions=self._parse_when_matched(),
    5909        )
    5910
    5911    def _parse_when_matched(self) -> t.List[exp.When]:
    5912        whens = []
    5913
    5914        while self._match(TokenType.WHEN):
    5915            matched = not self._match(TokenType.NOT)
    5916            self._match_text_seq("MATCHED")
    5917            source = (
    5918                False
    5919                if self._match_text_seq("BY", "TARGET")
    5920                else self._match_text_seq("BY", "SOURCE")
    5921            )
    5922            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
    5923
    5924            self._match(TokenType.THEN)
    5925
    5926            if self._match(TokenType.INSERT):
    5927                _this = self._parse_star()
    5928                if _this:
    5929                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    5930                else:
    5931                    then = self.expression(
    5932                        exp.Insert,
    5933                        this=self._parse_value(),
    5934                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    5935                    )
    5936            elif self._match(TokenType.UPDATE):
    5937                expressions = self._parse_star()
    5938                if expressions:
    5939                    then = self.expression(exp.Update, expressions=expressions)
    5940                else:
    5941                    then = self.expression(
    5942                        exp.Update,
    5943                        expressions=self._match(TokenType.SET)
    5944                        and self._parse_csv(self._parse_equality),
    5945                    )
    5946            elif self._match(TokenType.DELETE):
    5947                then = self.expression(exp.Var, this=self._prev.text)
    5948            else:
    5949                then = None
    5950
    5951            whens.append(
    5952                self.expression(
    5953                    exp.When,
    5954                    matched=matched,
    5955                    source=source,
    5956                    condition=condition,
    5957                    then=then,
    5958                )
    5959            )
    5960        return whens
    5961
    5962    def _parse_show(self) -> t.Optional[exp.Expression]:
    5963        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    5964        if parser:
    5965            return parser(self)
    5966        return self._parse_as_command(self._prev)
    5967
    5968    def _parse_set_item_assignment(
    5969        self, kind: t.Optional[str] = None
    5970    ) -> t.Optional[exp.Expression]:
    5971        index = self._index
    5972
    5973        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    5974            return self._parse_set_transaction(global_=kind == "GLOBAL")
    5975
    5976        left = self._parse_primary() or self._parse_id_var()
    5977        assignment_delimiter = self._match_texts(("=", "TO"))
    5978
    5979        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    5980            self._retreat(index)
    5981            return None
    5982
    5983        right = self._parse_statement() or self._parse_id_var()
    5984        this = self.expression(exp.EQ, this=left, expression=right)
    5985
    5986        return self.expression(exp.SetItem, this=this, kind=kind)
    5987
    5988    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    5989        self._match_text_seq("TRANSACTION")
    5990        characteristics = self._parse_csv(
    5991            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    5992        )
    5993        return self.expression(
    5994            exp.SetItem,
    5995            expressions=characteristics,
    5996            kind="TRANSACTION",
    5997            **{"global": global_},  # type: ignore
    5998        )
    5999
    6000    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    6001        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    6002        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    6003
    6004    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    6005        index = self._index
    6006        set_ = self.expression(
    6007            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    6008        )
    6009
    6010        if self._curr:
    6011            self._retreat(index)
    6012            return self._parse_as_command(self._prev)
    6013
    6014        return set_
    6015
    6016    def _parse_var_from_options(
    6017        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    6018    ) -> t.Optional[exp.Var]:
    6019        start = self._curr
    6020        if not start:
    6021            return None
    6022
    6023        option = start.text.upper()
    6024        continuations = options.get(option)
    6025
    6026        index = self._index
    6027        self._advance()
    6028        for keywords in continuations or []:
    6029            if isinstance(keywords, str):
    6030                keywords = (keywords,)
    6031
    6032            if self._match_text_seq(*keywords):
    6033                option = f"{option} {' '.join(keywords)}"
    6034                break
    6035        else:
    6036            if continuations or continuations is None:
    6037                if raise_unmatched:
    6038                    self.raise_error(f"Unknown option {option}")
    6039
    6040                self._retreat(index)
    6041                return None
    6042
    6043        return exp.var(option)
    6044
    6045    def _parse_as_command(self, start: Token) -> exp.Command:
    6046        while self._curr:
    6047            self._advance()
    6048        text = self._find_sql(start, self._prev)
    6049        size = len(start.text)
    6050        self._warn_unsupported()
    6051        return exp.Command(this=text[:size], expression=text[size:])
    6052
    6053    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    6054        settings = []
    6055
    6056        self._match_l_paren()
    6057        kind = self._parse_id_var()
    6058
    6059        if self._match(TokenType.L_PAREN):
    6060            while True:
    6061                key = self._parse_id_var()
    6062                value = self._parse_primary()
    6063
    6064                if not key and value is None:
    6065                    break
    6066                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    6067            self._match(TokenType.R_PAREN)
    6068
    6069        self._match_r_paren()
    6070
    6071        return self.expression(
    6072            exp.DictProperty,
    6073            this=this,
    6074            kind=kind.this if kind else None,
    6075            settings=settings,
    6076        )
    6077
    6078    def _parse_dict_range(self, this: str) -> exp.DictRange:
    6079        self._match_l_paren()
    6080        has_min = self._match_text_seq("MIN")
    6081        if has_min:
    6082            min = self._parse_var() or self._parse_primary()
    6083            self._match_text_seq("MAX")
    6084            max = self._parse_var() or self._parse_primary()
    6085        else:
    6086            max = self._parse_var() or self._parse_primary()
    6087            min = exp.Literal.number(0)
    6088        self._match_r_paren()
    6089        return self.expression(exp.DictRange, this=this, min=min, max=max)
    6090
    6091    def _parse_comprehension(
    6092        self, this: t.Optional[exp.Expression]
    6093    ) -> t.Optional[exp.Comprehension]:
    6094        index = self._index
    6095        expression = self._parse_column()
    6096        if not self._match(TokenType.IN):
    6097            self._retreat(index - 1)
    6098            return None
    6099        iterator = self._parse_column()
    6100        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
    6101        return self.expression(
    6102            exp.Comprehension,
    6103            this=this,
    6104            expression=expression,
    6105            iterator=iterator,
    6106            condition=condition,
    6107        )
    6108
    6109    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    6110        if self._match(TokenType.HEREDOC_STRING):
    6111            return self.expression(exp.Heredoc, this=self._prev.text)
    6112
    6113        if not self._match_text_seq("$"):
    6114            return None
    6115
    6116        tags = ["$"]
    6117        tag_text = None
    6118
    6119        if self._is_connected():
    6120            self._advance()
    6121            tags.append(self._prev.text.upper())
    6122        else:
    6123            self.raise_error("No closing $ found")
    6124
    6125        if tags[-1] != "$":
    6126            if self._is_connected() and self._match_text_seq("$"):
    6127                tag_text = tags[-1]
    6128                tags.append("$")
    6129            else:
    6130                self.raise_error("No closing $ found")
    6131
    6132        heredoc_start = self._curr
    6133
    6134        while self._curr:
    6135            if self._match_text_seq(*tags, advance=False):
    6136                this = self._find_sql(heredoc_start, self._prev)
    6137                self._advance(len(tags))
    6138                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    6139
    6140            self._advance()
    6141
    6142        self.raise_error(f"No closing {''.join(tags)} found")
    6143        return None
    6144
    6145    def _find_parser(
    6146        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    6147    ) -> t.Optional[t.Callable]:
    6148        if not self._curr:
    6149            return None
    6150
    6151        index = self._index
    6152        this = []
    6153        while True:
    6154            # The current token might be multiple words
    6155            curr = self._curr.text.upper()
    6156            key = curr.split(" ")
    6157            this.append(curr)
    6158
    6159            self._advance()
    6160            result, trie = in_trie(trie, key)
    6161            if result == TrieResult.FAILED:
    6162                break
    6163
    6164            if result == TrieResult.EXISTS:
    6165                subparser = parsers[" ".join(this)]
    6166                return subparser
    6167
    6168        self._retreat(index)
    6169        return None
    6170
    6171    def _match(self, token_type, advance=True, expression=None):
    6172        if not self._curr:
    6173            return None
    6174
    6175        if self._curr.token_type == token_type:
    6176            if advance:
    6177                self._advance()
    6178            self._add_comments(expression)
    6179            return True
    6180
    6181        return None
    6182
    6183    def _match_set(self, types, advance=True):
    6184        if not self._curr:
    6185            return None
    6186
    6187        if self._curr.token_type in types:
    6188            if advance:
    6189                self._advance()
    6190            return True
    6191
    6192        return None
    6193
    6194    def _match_pair(self, token_type_a, token_type_b, advance=True):
    6195        if not self._curr or not self._next:
    6196            return None
    6197
    6198        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    6199            if advance:
    6200                self._advance(2)
    6201            return True
    6202
    6203        return None
    6204
    6205    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6206        if not self._match(TokenType.L_PAREN, expression=expression):
    6207            self.raise_error("Expecting (")
    6208
    6209    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6210        if not self._match(TokenType.R_PAREN, expression=expression):
    6211            self.raise_error("Expecting )")
    6212
    6213    def _match_texts(self, texts, advance=True):
    6214        if self._curr and self._curr.text.upper() in texts:
    6215            if advance:
    6216                self._advance()
    6217            return True
    6218        return None
    6219
    6220    def _match_text_seq(self, *texts, advance=True):
    6221        index = self._index
    6222        for text in texts:
    6223            if self._curr and self._curr.text.upper() == text:
    6224                self._advance()
    6225            else:
    6226                self._retreat(index)
    6227                return None
    6228
    6229        if not advance:
    6230            self._retreat(index)
    6231
    6232        return True
    6233
    6234    def _replace_lambda(
    6235        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
    6236    ) -> t.Optional[exp.Expression]:
    6237        if not node:
    6238            return node
    6239
    6240        for column in node.find_all(exp.Column):
    6241            if column.parts[0].name in lambda_variables:
    6242                dot_or_id = column.to_dot() if column.table else column.this
    6243                parent = column.parent
    6244
    6245                while isinstance(parent, exp.Dot):
    6246                    if not isinstance(parent.parent, exp.Dot):
    6247                        parent.replace(dot_or_id)
    6248                        break
    6249                    parent = parent.parent
    6250                else:
    6251                    if column is node:
    6252                        node = dot_or_id
    6253                    else:
    6254                        column.replace(dot_or_id)
    6255        return node
    6256
    6257    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    6258        start = self._prev
    6259
    6260        # Not to be confused with TRUNCATE(number, decimals) function call
    6261        if self._match(TokenType.L_PAREN):
    6262            self._retreat(self._index - 2)
    6263            return self._parse_function()
    6264
    6265        # Clickhouse supports TRUNCATE DATABASE as well
    6266        is_database = self._match(TokenType.DATABASE)
    6267
    6268        self._match(TokenType.TABLE)
    6269
    6270        exists = self._parse_exists(not_=False)
    6271
    6272        expressions = self._parse_csv(
    6273            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    6274        )
    6275
    6276        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6277
    6278        if self._match_text_seq("RESTART", "IDENTITY"):
    6279            identity = "RESTART"
    6280        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    6281            identity = "CONTINUE"
    6282        else:
    6283            identity = None
    6284
    6285        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    6286            option = self._prev.text
    6287        else:
    6288            option = None
    6289
    6290        partition = self._parse_partition()
    6291
    6292        # Fallback case
    6293        if self._curr:
    6294            return self._parse_as_command(start)
    6295
    6296        return self.expression(
    6297            exp.TruncateTable,
    6298            expressions=expressions,
    6299            is_database=is_database,
    6300            exists=exists,
    6301            cluster=cluster,
    6302            identity=identity,
    6303            option=option,
    6304            partition=partition,
    6305        )
    6306
    6307    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    6308        this = self._parse_ordered(self._parse_opclass)
    6309
    6310        if not self._match(TokenType.WITH):
    6311            return this
    6312
    6313        op = self._parse_var(any_token=True)
    6314
    6315        return self.expression(exp.WithOperator, this=this, op=op)
    6316
    6317    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    6318        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    6319
    6320        options = []
    6321        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    6322            option = self._parse_unquoted_field()
    6323            value = None
    6324            # Some options are defined as functions with the values as params
    6325            if not isinstance(option, exp.Func):
    6326                # Different dialects might separate options and values by white space, "=" and "AS"
    6327                self._match(TokenType.EQ)
    6328                self._match(TokenType.ALIAS)
    6329                value = self._parse_unquoted_field()
    6330
    6331            param = self.expression(exp.CopyParameter, this=option, expression=value)
    6332            options.append(param)
    6333
    6334            if sep:
    6335                self._match(sep)
    6336
    6337        return options
    6338
    6339    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    6340        def parse_options():
    6341            opts = []
    6342            self._match(TokenType.EQ)
    6343            self._match(TokenType.L_PAREN)
    6344            while self._curr and not self._match(TokenType.R_PAREN):
    6345                opts.append(self._parse_conjunction())
    6346            return opts
    6347
    6348        expr = self.expression(exp.Credentials)
    6349
    6350        if self._match_text_seq("STORAGE_INTEGRATION", advance=False):
    6351            expr.set("storage", self._parse_conjunction())
    6352        if self._match_text_seq("CREDENTIALS"):
    6353            # Snowflake supports CREDENTIALS = (...), while Redshift CREDENTIALS <string>
    6354            creds = parse_options() if self._match(TokenType.EQ) else self._parse_field()
    6355            expr.set("credentials", creds)
    6356        if self._match_text_seq("ENCRYPTION"):
    6357            expr.set("encryption", parse_options())
    6358        if self._match_text_seq("IAM_ROLE"):
    6359            expr.set("iam_role", self._parse_field())
    6360        if self._match_text_seq("REGION"):
    6361            expr.set("region", self._parse_field())
    6362
    6363        return expr
    6364
    6365    def _parse_copy(self):
    6366        start = self._prev
    6367
    6368        self._match(TokenType.INTO)
    6369
    6370        this = (
    6371            self._parse_conjunction()
    6372            if self._match(TokenType.L_PAREN, advance=False)
    6373            else self._parse_table(schema=True)
    6374        )
    6375
    6376        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    6377
    6378        files = self._parse_csv(self._parse_conjunction)
    6379        credentials = self._parse_credentials()
    6380
    6381        self._match_text_seq("WITH")
    6382
    6383        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    6384
    6385        # Fallback case
    6386        if self._curr:
    6387            return self._parse_as_command(start)
    6388
    6389        return self.expression(
    6390            exp.Copy,
    6391            this=this,
    6392            kind=kind,
    6393            credentials=credentials,
    6394            files=files,
    6395            params=params,
    6396        )

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.ARRAY: 'ARRAY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE: 'DATE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INT256: 'INT256'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>}
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.UNKNOWN: 'UNKNOWN'>, <TokenType.NOT: 'NOT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.LT: 'LT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.AMP: 'AMP'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.SELECT: 'SELECT'>, <TokenType.SLASH: 'SLASH'>, <TokenType.COMMA: 'COMMA'>, <TokenType.DOT: 'DOT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.STAR: 'STAR'>, <TokenType.EQ: 'EQ'>, <TokenType.HASH: 'HASH'>, <TokenType.CARET: 'CARET'>, <TokenType.PLUS: 'PLUS'>, <TokenType.DASH: 'DASH'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.TILDA: 'TILDA'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.COLON: 'COLON'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.GT: 'GT'>, <TokenType.MOD: 'MOD'>}
DB_CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>}
ID_VAR_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
INTERVAL_VARS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
TABLE_ALIAS_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
ALIAS_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INSERT: 'INSERT'>, <TokenType.XOR: 'XOR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.GLOB: 'GLOB'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.ROW: 'ROW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.DATE: 'DATE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NAME: 'NAME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SOME: 'SOME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>, <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 = {'UNIQUE', 'PRIMARY KEY', 'PERIOD', 'CHECK', 'EXCLUDE', 'LIKE', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
INSERT_ALTERNATIVES = {'ROLLBACK', 'REPLACE', 'ABORT', 'IGNORE', 'FAIL'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'OFFSET', 'TIMESTAMP', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'NULLS', 'ASC', 'DESC', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>, <TokenType.IGNORE: 'IGNORE'>}
VIEW_ATTRIBUTES = {'ENCRYPTION', 'VIEW_METADATA', 'SCHEMABINDING'}
WINDOW_ALIAS_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.IS: 'IS'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
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.KEEP: 'KEEP'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INET: 'INET'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.XML: 'XML'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT: 'INT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROW: 'ROW'>, <TokenType.SET: 'SET'>, <TokenType.TOP: 'TOP'>, <TokenType.NULL: 'NULL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DATE: 'DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ASC: 'ASC'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.VAR: 'VAR'>, <TokenType.ALL: 'ALL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.CASE: 'CASE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COPY: 'COPY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FULL: 'FULL'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAME: 'NAME'>, <TokenType.END: 'END'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.KILL: 'KILL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BIT: 'BIT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.ROWS: 'ROWS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.USE: 'USE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INT256: 'INT256'>, <TokenType.DESC: 'DESC'>, <TokenType.ASOF: 'ASOF'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FALSE: 'FALSE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT128: 'INT128'>, <TokenType.UUID: 'UUID'>, <TokenType.IS: 'IS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.IMAGE: 'IMAGE'>}
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