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

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

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

Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.

###### Arguments:

- error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
- error_message_context: The amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
- max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3

Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) View Source

    1135    def __init__(
    1136        self,
    1137        error_level: t.Optional[ErrorLevel] = None,
    1138        error_message_context: int = 100,
    1139        max_errors: int = 3,
    1140        dialect: DialectType = None,
    1141    ):
    1142        from sqlglot.dialects import Dialect
    1143
    1144        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1145        self.error_message_context = error_message_context
    1146        self.max_errors = max_errors
    1147        self.dialect = Dialect.get_or_raise(dialect)
    1148        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_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.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.OBJECT: 'OBJECT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>}
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.L_BRACKET: 'L_BRACKET'>, <TokenType.NOT: 'NOT'>, <TokenType.CARET: 'CARET'>, <TokenType.GT: 'GT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.TILDA: 'TILDA'>, <TokenType.HASH: 'HASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.MOD: 'MOD'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.AMP: 'AMP'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.STAR: 'STAR'>, <TokenType.SLASH: 'SLASH'>, <TokenType.DOT: 'DOT'>, <TokenType.COLON: 'COLON'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.EQ: 'EQ'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.COMMA: 'COMMA'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.DASH: 'DASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.LT: 'LT'>}
DB_CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ID_VAR_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
INTERVAL_VARS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
TABLE_ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>}
ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>}
UPDATE_ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>}
TRIM_TYPES = {'BOTH', 'TRAILING', 'LEADING'}
FUNC_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.GLOB: 'GLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SOME: 'SOME'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.INSERT: 'INSERT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT256: 'INT256'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.XOR: 'XOR'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.ALL: 'ALL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LEFT: 'LEFT'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.POSITIONAL: 'POSITIONAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.CROSS: 'CROSS'>}
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.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'FOREIGN KEY', 'LIKE', 'EXCLUDE', 'UNIQUE', 'CHECK', 'PERIOD', 'PRIMARY KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.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 = {'IGNORE', 'FAIL', 'REPLACE', 'ABORT', 'ROLLBACK'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'TIMESTAMP', 'STREAM', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'ASC', 'NULLS', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COLON: 'COLON'>, <TokenType.COMMA: 'COMMA'>}
FETCH_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.ROW: 'ROW'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MONEY: 'MONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NAME: 'NAME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.CASE: 'CASE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.FULL: 'FULL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.USE: 'USE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.KILL: 'KILL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.SOME: 'SOME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ROWS: 'ROWS'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.INT128: 'INT128'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.XML: 'XML'>, <TokenType.ASC: 'ASC'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ASOF: 'ASOF'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.VAR: 'VAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NULL: 'NULL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DIV: 'DIV'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SET: 'SET'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT: 'INT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DATE: 'DATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.END: 'END'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.LEFT: 'LEFT'>}
SELECT_START_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <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 = {'order', 'limit', 'offset'}
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

    1150    def reset(self):
    1151        self.sql = ""
    1152        self.errors = []
    1153        self._tokens = []
    1154        self._index = 0
    1155        self._curr = None
    1156        self._next = None
    1157        self._prev = None
    1158        self._prev_comments = None

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

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

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

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

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

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

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

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

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