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 in_trie, new_trie
      13
      14if t.TYPE_CHECKING:
      15    from sqlglot._typing import E
      16
      17logger = logging.getLogger("sqlglot")
      18
      19
      20def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
      21    if len(args) == 1 and args[0].is_star:
      22        return exp.StarMap(this=args[0])
      23
      24    keys = []
      25    values = []
      26    for i in range(0, len(args), 2):
      27        keys.append(args[i])
      28        values.append(args[i + 1])
      29
      30    return exp.VarMap(
      31        keys=exp.Array(expressions=keys),
      32        values=exp.Array(expressions=values),
      33    )
      34
      35
      36def parse_like(args: t.List) -> exp.Escape | exp.Like:
      37    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
      38    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
      39
      40
      41def binary_range_parser(
      42    expr_type: t.Type[exp.Expression],
      43) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
      44    return lambda self, this: self._parse_escape(
      45        self.expression(expr_type, this=this, expression=self._parse_bitwise())
      46    )
      47
      48
      49class _Parser(type):
      50    def __new__(cls, clsname, bases, attrs):
      51        klass = super().__new__(cls, clsname, bases, attrs)
      52
      53        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
      54        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
      55
      56        return klass
      57
      58
      59class Parser(metaclass=_Parser):
      60    """
      61    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
      62
      63    Args:
      64        error_level: The desired error level.
      65            Default: ErrorLevel.IMMEDIATE
      66        error_message_context: Determines the amount of context to capture from a
      67            query string when displaying the error message (in number of characters).
      68            Default: 100
      69        max_errors: Maximum number of error messages to include in a raised ParseError.
      70            This is only relevant if error_level is ErrorLevel.RAISE.
      71            Default: 3
      72    """
      73
      74    FUNCTIONS: t.Dict[str, t.Callable] = {
      75        **{name: f.from_arg_list for f in exp.ALL_FUNCTIONS for name in f.sql_names()},
      76        "DATE_TO_DATE_STR": lambda args: exp.Cast(
      77            this=seq_get(args, 0),
      78            to=exp.DataType(this=exp.DataType.Type.TEXT),
      79        ),
      80        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
      81        "LIKE": parse_like,
      82        "TIME_TO_TIME_STR": lambda args: exp.Cast(
      83            this=seq_get(args, 0),
      84            to=exp.DataType(this=exp.DataType.Type.TEXT),
      85        ),
      86        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
      87            this=exp.Cast(
      88                this=seq_get(args, 0),
      89                to=exp.DataType(this=exp.DataType.Type.TEXT),
      90            ),
      91            start=exp.Literal.number(1),
      92            length=exp.Literal.number(10),
      93        ),
      94        "VAR_MAP": parse_var_map,
      95    }
      96
      97    NO_PAREN_FUNCTIONS = {
      98        TokenType.CURRENT_DATE: exp.CurrentDate,
      99        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     100        TokenType.CURRENT_TIME: exp.CurrentTime,
     101        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     102        TokenType.CURRENT_USER: exp.CurrentUser,
     103    }
     104
     105    NESTED_TYPE_TOKENS = {
     106        TokenType.ARRAY,
     107        TokenType.MAP,
     108        TokenType.NULLABLE,
     109        TokenType.STRUCT,
     110    }
     111
     112    ENUM_TYPE_TOKENS = {
     113        TokenType.ENUM,
     114    }
     115
     116    TYPE_TOKENS = {
     117        TokenType.BIT,
     118        TokenType.BOOLEAN,
     119        TokenType.TINYINT,
     120        TokenType.UTINYINT,
     121        TokenType.SMALLINT,
     122        TokenType.USMALLINT,
     123        TokenType.INT,
     124        TokenType.UINT,
     125        TokenType.BIGINT,
     126        TokenType.UBIGINT,
     127        TokenType.INT128,
     128        TokenType.UINT128,
     129        TokenType.INT256,
     130        TokenType.UINT256,
     131        TokenType.FLOAT,
     132        TokenType.DOUBLE,
     133        TokenType.CHAR,
     134        TokenType.NCHAR,
     135        TokenType.VARCHAR,
     136        TokenType.NVARCHAR,
     137        TokenType.TEXT,
     138        TokenType.MEDIUMTEXT,
     139        TokenType.LONGTEXT,
     140        TokenType.MEDIUMBLOB,
     141        TokenType.LONGBLOB,
     142        TokenType.BINARY,
     143        TokenType.VARBINARY,
     144        TokenType.JSON,
     145        TokenType.JSONB,
     146        TokenType.INTERVAL,
     147        TokenType.TIME,
     148        TokenType.TIMESTAMP,
     149        TokenType.TIMESTAMPTZ,
     150        TokenType.TIMESTAMPLTZ,
     151        TokenType.DATETIME,
     152        TokenType.DATETIME64,
     153        TokenType.DATE,
     154        TokenType.INT4RANGE,
     155        TokenType.INT4MULTIRANGE,
     156        TokenType.INT8RANGE,
     157        TokenType.INT8MULTIRANGE,
     158        TokenType.NUMRANGE,
     159        TokenType.NUMMULTIRANGE,
     160        TokenType.TSRANGE,
     161        TokenType.TSMULTIRANGE,
     162        TokenType.TSTZRANGE,
     163        TokenType.TSTZMULTIRANGE,
     164        TokenType.DATERANGE,
     165        TokenType.DATEMULTIRANGE,
     166        TokenType.DECIMAL,
     167        TokenType.BIGDECIMAL,
     168        TokenType.UUID,
     169        TokenType.GEOGRAPHY,
     170        TokenType.GEOMETRY,
     171        TokenType.HLLSKETCH,
     172        TokenType.HSTORE,
     173        TokenType.PSEUDO_TYPE,
     174        TokenType.SUPER,
     175        TokenType.SERIAL,
     176        TokenType.SMALLSERIAL,
     177        TokenType.BIGSERIAL,
     178        TokenType.XML,
     179        TokenType.UNIQUEIDENTIFIER,
     180        TokenType.MONEY,
     181        TokenType.SMALLMONEY,
     182        TokenType.ROWVERSION,
     183        TokenType.IMAGE,
     184        TokenType.VARIANT,
     185        TokenType.OBJECT,
     186        TokenType.INET,
     187        TokenType.ENUM,
     188        *NESTED_TYPE_TOKENS,
     189    }
     190
     191    SUBQUERY_PREDICATES = {
     192        TokenType.ANY: exp.Any,
     193        TokenType.ALL: exp.All,
     194        TokenType.EXISTS: exp.Exists,
     195        TokenType.SOME: exp.Any,
     196    }
     197
     198    RESERVED_KEYWORDS = {
     199        *Tokenizer.SINGLE_TOKENS.values(),
     200        TokenType.SELECT,
     201    }
     202
     203    DB_CREATABLES = {
     204        TokenType.DATABASE,
     205        TokenType.SCHEMA,
     206        TokenType.TABLE,
     207        TokenType.VIEW,
     208        TokenType.DICTIONARY,
     209    }
     210
     211    CREATABLES = {
     212        TokenType.COLUMN,
     213        TokenType.FUNCTION,
     214        TokenType.INDEX,
     215        TokenType.PROCEDURE,
     216        *DB_CREATABLES,
     217    }
     218
     219    # Tokens that can represent identifiers
     220    ID_VAR_TOKENS = {
     221        TokenType.VAR,
     222        TokenType.ANTI,
     223        TokenType.APPLY,
     224        TokenType.ASC,
     225        TokenType.AUTO_INCREMENT,
     226        TokenType.BEGIN,
     227        TokenType.CACHE,
     228        TokenType.CASE,
     229        TokenType.COLLATE,
     230        TokenType.COMMAND,
     231        TokenType.COMMENT,
     232        TokenType.COMMIT,
     233        TokenType.CONSTRAINT,
     234        TokenType.DEFAULT,
     235        TokenType.DELETE,
     236        TokenType.DESC,
     237        TokenType.DESCRIBE,
     238        TokenType.DICTIONARY,
     239        TokenType.DIV,
     240        TokenType.END,
     241        TokenType.EXECUTE,
     242        TokenType.ESCAPE,
     243        TokenType.FALSE,
     244        TokenType.FIRST,
     245        TokenType.FILTER,
     246        TokenType.FORMAT,
     247        TokenType.FULL,
     248        TokenType.IF,
     249        TokenType.IS,
     250        TokenType.ISNULL,
     251        TokenType.INTERVAL,
     252        TokenType.KEEP,
     253        TokenType.LEFT,
     254        TokenType.LOAD,
     255        TokenType.MERGE,
     256        TokenType.NATURAL,
     257        TokenType.NEXT,
     258        TokenType.OFFSET,
     259        TokenType.ORDINALITY,
     260        TokenType.OVERWRITE,
     261        TokenType.PARTITION,
     262        TokenType.PERCENT,
     263        TokenType.PIVOT,
     264        TokenType.PRAGMA,
     265        TokenType.RANGE,
     266        TokenType.REFERENCES,
     267        TokenType.RIGHT,
     268        TokenType.ROW,
     269        TokenType.ROWS,
     270        TokenType.SEMI,
     271        TokenType.SET,
     272        TokenType.SETTINGS,
     273        TokenType.SHOW,
     274        TokenType.TEMPORARY,
     275        TokenType.TOP,
     276        TokenType.TRUE,
     277        TokenType.UNIQUE,
     278        TokenType.UNPIVOT,
     279        TokenType.UPDATE,
     280        TokenType.VOLATILE,
     281        TokenType.WINDOW,
     282        *CREATABLES,
     283        *SUBQUERY_PREDICATES,
     284        *TYPE_TOKENS,
     285        *NO_PAREN_FUNCTIONS,
     286    }
     287
     288    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
     289
     290    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     291        TokenType.APPLY,
     292        TokenType.ASOF,
     293        TokenType.FULL,
     294        TokenType.LEFT,
     295        TokenType.LOCK,
     296        TokenType.NATURAL,
     297        TokenType.OFFSET,
     298        TokenType.RIGHT,
     299        TokenType.WINDOW,
     300    }
     301
     302    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     303
     304    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     305
     306    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     307
     308    FUNC_TOKENS = {
     309        TokenType.COMMAND,
     310        TokenType.CURRENT_DATE,
     311        TokenType.CURRENT_DATETIME,
     312        TokenType.CURRENT_TIMESTAMP,
     313        TokenType.CURRENT_TIME,
     314        TokenType.CURRENT_USER,
     315        TokenType.FILTER,
     316        TokenType.FIRST,
     317        TokenType.FORMAT,
     318        TokenType.GLOB,
     319        TokenType.IDENTIFIER,
     320        TokenType.INDEX,
     321        TokenType.ISNULL,
     322        TokenType.ILIKE,
     323        TokenType.LIKE,
     324        TokenType.MERGE,
     325        TokenType.OFFSET,
     326        TokenType.PRIMARY_KEY,
     327        TokenType.RANGE,
     328        TokenType.REPLACE,
     329        TokenType.ROW,
     330        TokenType.UNNEST,
     331        TokenType.VAR,
     332        TokenType.LEFT,
     333        TokenType.RIGHT,
     334        TokenType.DATE,
     335        TokenType.DATETIME,
     336        TokenType.TABLE,
     337        TokenType.TIMESTAMP,
     338        TokenType.TIMESTAMPTZ,
     339        TokenType.WINDOW,
     340        *TYPE_TOKENS,
     341        *SUBQUERY_PREDICATES,
     342    }
     343
     344    CONJUNCTION = {
     345        TokenType.AND: exp.And,
     346        TokenType.OR: exp.Or,
     347    }
     348
     349    EQUALITY = {
     350        TokenType.EQ: exp.EQ,
     351        TokenType.NEQ: exp.NEQ,
     352        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     353    }
     354
     355    COMPARISON = {
     356        TokenType.GT: exp.GT,
     357        TokenType.GTE: exp.GTE,
     358        TokenType.LT: exp.LT,
     359        TokenType.LTE: exp.LTE,
     360    }
     361
     362    BITWISE = {
     363        TokenType.AMP: exp.BitwiseAnd,
     364        TokenType.CARET: exp.BitwiseXor,
     365        TokenType.PIPE: exp.BitwiseOr,
     366        TokenType.DPIPE: exp.DPipe,
     367    }
     368
     369    TERM = {
     370        TokenType.DASH: exp.Sub,
     371        TokenType.PLUS: exp.Add,
     372        TokenType.MOD: exp.Mod,
     373        TokenType.COLLATE: exp.Collate,
     374    }
     375
     376    FACTOR = {
     377        TokenType.DIV: exp.IntDiv,
     378        TokenType.LR_ARROW: exp.Distance,
     379        TokenType.SLASH: exp.Div,
     380        TokenType.STAR: exp.Mul,
     381    }
     382
     383    TIMESTAMPS = {
     384        TokenType.TIME,
     385        TokenType.TIMESTAMP,
     386        TokenType.TIMESTAMPTZ,
     387        TokenType.TIMESTAMPLTZ,
     388    }
     389
     390    SET_OPERATIONS = {
     391        TokenType.UNION,
     392        TokenType.INTERSECT,
     393        TokenType.EXCEPT,
     394    }
     395
     396    JOIN_METHODS = {
     397        TokenType.NATURAL,
     398        TokenType.ASOF,
     399    }
     400
     401    JOIN_SIDES = {
     402        TokenType.LEFT,
     403        TokenType.RIGHT,
     404        TokenType.FULL,
     405    }
     406
     407    JOIN_KINDS = {
     408        TokenType.INNER,
     409        TokenType.OUTER,
     410        TokenType.CROSS,
     411        TokenType.SEMI,
     412        TokenType.ANTI,
     413    }
     414
     415    JOIN_HINTS: t.Set[str] = set()
     416
     417    LAMBDAS = {
     418        TokenType.ARROW: lambda self, expressions: self.expression(
     419            exp.Lambda,
     420            this=self._replace_lambda(
     421                self._parse_conjunction(),
     422                {node.name for node in expressions},
     423            ),
     424            expressions=expressions,
     425        ),
     426        TokenType.FARROW: lambda self, expressions: self.expression(
     427            exp.Kwarg,
     428            this=exp.var(expressions[0].name),
     429            expression=self._parse_conjunction(),
     430        ),
     431    }
     432
     433    COLUMN_OPERATORS = {
     434        TokenType.DOT: None,
     435        TokenType.DCOLON: lambda self, this, to: self.expression(
     436            exp.Cast if self.STRICT_CAST else exp.TryCast,
     437            this=this,
     438            to=to,
     439        ),
     440        TokenType.ARROW: lambda self, this, path: self.expression(
     441            exp.JSONExtract,
     442            this=this,
     443            expression=path,
     444        ),
     445        TokenType.DARROW: lambda self, this, path: self.expression(
     446            exp.JSONExtractScalar,
     447            this=this,
     448            expression=path,
     449        ),
     450        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     451            exp.JSONBExtract,
     452            this=this,
     453            expression=path,
     454        ),
     455        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     456            exp.JSONBExtractScalar,
     457            this=this,
     458            expression=path,
     459        ),
     460        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     461            exp.JSONBContains,
     462            this=this,
     463            expression=key,
     464        ),
     465    }
     466
     467    EXPRESSION_PARSERS = {
     468        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, "CLUSTER", "BY"),
     469        exp.Column: lambda self: self._parse_column(),
     470        exp.Condition: lambda self: self._parse_conjunction(),
     471        exp.DataType: lambda self: self._parse_types(),
     472        exp.Expression: lambda self: self._parse_statement(),
     473        exp.From: lambda self: self._parse_from(),
     474        exp.Group: lambda self: self._parse_group(),
     475        exp.Having: lambda self: self._parse_having(),
     476        exp.Identifier: lambda self: self._parse_id_var(),
     477        exp.Join: lambda self: self._parse_join(),
     478        exp.Lambda: lambda self: self._parse_lambda(),
     479        exp.Lateral: lambda self: self._parse_lateral(),
     480        exp.Limit: lambda self: self._parse_limit(),
     481        exp.Offset: lambda self: self._parse_offset(),
     482        exp.Order: lambda self: self._parse_order(),
     483        exp.Ordered: lambda self: self._parse_ordered(),
     484        exp.Properties: lambda self: self._parse_properties(),
     485        exp.Qualify: lambda self: self._parse_qualify(),
     486        exp.Returning: lambda self: self._parse_returning(),
     487        exp.Sort: lambda self: self._parse_sort(exp.Sort, "SORT", "BY"),
     488        exp.Table: lambda self: self._parse_table_parts(),
     489        exp.TableAlias: lambda self: self._parse_table_alias(),
     490        exp.Where: lambda self: self._parse_where(),
     491        exp.Window: lambda self: self._parse_named_window(),
     492        exp.With: lambda self: self._parse_with(),
     493        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     494    }
     495
     496    STATEMENT_PARSERS = {
     497        TokenType.ALTER: lambda self: self._parse_alter(),
     498        TokenType.BEGIN: lambda self: self._parse_transaction(),
     499        TokenType.CACHE: lambda self: self._parse_cache(),
     500        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     501        TokenType.COMMENT: lambda self: self._parse_comment(),
     502        TokenType.CREATE: lambda self: self._parse_create(),
     503        TokenType.DELETE: lambda self: self._parse_delete(),
     504        TokenType.DESC: lambda self: self._parse_describe(),
     505        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     506        TokenType.DROP: lambda self: self._parse_drop(),
     507        TokenType.END: lambda self: self._parse_commit_or_rollback(),
     508        TokenType.FROM: lambda self: exp.select("*").from_(
     509            t.cast(exp.From, self._parse_from(skip_from_token=True))
     510        ),
     511        TokenType.INSERT: lambda self: self._parse_insert(),
     512        TokenType.LOAD: lambda self: self._parse_load(),
     513        TokenType.MERGE: lambda self: self._parse_merge(),
     514        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     515        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     516        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     517        TokenType.SET: lambda self: self._parse_set(),
     518        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     519        TokenType.UPDATE: lambda self: self._parse_update(),
     520        TokenType.USE: lambda self: self.expression(
     521            exp.Use,
     522            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
     523            and exp.var(self._prev.text),
     524            this=self._parse_table(schema=False),
     525        ),
     526    }
     527
     528    UNARY_PARSERS = {
     529        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     530        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     531        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     532        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     533    }
     534
     535    PRIMARY_PARSERS = {
     536        TokenType.STRING: lambda self, token: self.expression(
     537            exp.Literal, this=token.text, is_string=True
     538        ),
     539        TokenType.NUMBER: lambda self, token: self.expression(
     540            exp.Literal, this=token.text, is_string=False
     541        ),
     542        TokenType.STAR: lambda self, _: self.expression(
     543            exp.Star,
     544            **{"except": self._parse_except(), "replace": self._parse_replace()},
     545        ),
     546        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     547        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     548        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     549        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     550        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
     551        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     552        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     553        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     554            exp.National, this=token.text
     555        ),
     556        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     557        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     558    }
     559
     560    PLACEHOLDER_PARSERS = {
     561        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     562        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     563        TokenType.COLON: lambda self: self.expression(exp.Placeholder, this=self._prev.text)
     564        if self._match_set((TokenType.NUMBER, TokenType.VAR))
     565        else None,
     566    }
     567
     568    RANGE_PARSERS = {
     569        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     570        TokenType.GLOB: binary_range_parser(exp.Glob),
     571        TokenType.ILIKE: binary_range_parser(exp.ILike),
     572        TokenType.IN: lambda self, this: self._parse_in(this),
     573        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     574        TokenType.IS: lambda self, this: self._parse_is(this),
     575        TokenType.LIKE: binary_range_parser(exp.Like),
     576        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     577        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     578        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     579    }
     580
     581    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     582        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     583        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     584        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     585        "CHARACTER SET": lambda self: self._parse_character_set(),
     586        "CHECKSUM": lambda self: self._parse_checksum(),
     587        "CLUSTER": lambda self: self._parse_cluster(),
     588        "COLLATE": lambda self: self._parse_property_assignment(exp.CollateProperty),
     589        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     590        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     591        "DEFINER": lambda self: self._parse_definer(),
     592        "DETERMINISTIC": lambda self: self.expression(
     593            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     594        ),
     595        "DISTKEY": lambda self: self._parse_distkey(),
     596        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     597        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     598        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     599        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     600        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     601        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     602        "FREESPACE": lambda self: self._parse_freespace(),
     603        "IMMUTABLE": lambda self: self.expression(
     604            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     605        ),
     606        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     607        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     608        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     609        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     610        "LIKE": lambda self: self._parse_create_like(),
     611        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     612        "LOCK": lambda self: self._parse_locking(),
     613        "LOCKING": lambda self: self._parse_locking(),
     614        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     615        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     616        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     617        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     618        "NO": lambda self: self._parse_no_property(),
     619        "ON": lambda self: self._parse_on_property(),
     620        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     621        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     622        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     623        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     624        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     625        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     626        "RETURNS": lambda self: self._parse_returns(),
     627        "ROW": lambda self: self._parse_row(),
     628        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     629        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
     630        "SETTINGS": lambda self: self.expression(
     631            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
     632        ),
     633        "SORTKEY": lambda self: self._parse_sortkey(),
     634        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
     635        "STABLE": lambda self: self.expression(
     636            exp.StabilityProperty, this=exp.Literal.string("STABLE")
     637        ),
     638        "STORED": lambda self: self._parse_stored(),
     639        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
     640        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
     641        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
     642        "TO": lambda self: self._parse_to_table(),
     643        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
     644        "TTL": lambda self: self._parse_ttl(),
     645        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     646        "VOLATILE": lambda self: self._parse_volatile_property(),
     647        "WITH": lambda self: self._parse_with_property(),
     648    }
     649
     650    CONSTRAINT_PARSERS = {
     651        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
     652        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
     653        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
     654        "CHARACTER SET": lambda self: self.expression(
     655            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
     656        ),
     657        "CHECK": lambda self: self.expression(
     658            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
     659        ),
     660        "COLLATE": lambda self: self.expression(
     661            exp.CollateColumnConstraint, this=self._parse_var()
     662        ),
     663        "COMMENT": lambda self: self.expression(
     664            exp.CommentColumnConstraint, this=self._parse_string()
     665        ),
     666        "COMPRESS": lambda self: self._parse_compress(),
     667        "DEFAULT": lambda self: self.expression(
     668            exp.DefaultColumnConstraint, this=self._parse_bitwise()
     669        ),
     670        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
     671        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
     672        "FORMAT": lambda self: self.expression(
     673            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
     674        ),
     675        "GENERATED": lambda self: self._parse_generated_as_identity(),
     676        "IDENTITY": lambda self: self._parse_auto_increment(),
     677        "INLINE": lambda self: self._parse_inline(),
     678        "LIKE": lambda self: self._parse_create_like(),
     679        "NOT": lambda self: self._parse_not_constraint(),
     680        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
     681        "ON": lambda self: self._match(TokenType.UPDATE)
     682        and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function()),
     683        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
     684        "PRIMARY KEY": lambda self: self._parse_primary_key(),
     685        "REFERENCES": lambda self: self._parse_references(match=False),
     686        "TITLE": lambda self: self.expression(
     687            exp.TitleColumnConstraint, this=self._parse_var_or_string()
     688        ),
     689        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
     690        "UNIQUE": lambda self: self._parse_unique(),
     691        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
     692    }
     693
     694    ALTER_PARSERS = {
     695        "ADD": lambda self: self._parse_alter_table_add(),
     696        "ALTER": lambda self: self._parse_alter_table_alter(),
     697        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
     698        "DROP": lambda self: self._parse_alter_table_drop(),
     699        "RENAME": lambda self: self._parse_alter_table_rename(),
     700    }
     701
     702    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE"}
     703
     704    NO_PAREN_FUNCTION_PARSERS = {
     705        TokenType.ANY: lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
     706        TokenType.CASE: lambda self: self._parse_case(),
     707        TokenType.IF: lambda self: self._parse_if(),
     708        TokenType.NEXT_VALUE_FOR: lambda self: self.expression(
     709            exp.NextValueFor,
     710            this=self._parse_column(),
     711            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
     712        ),
     713    }
     714
     715    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
     716
     717    FUNCTION_PARSERS: t.Dict[str, t.Callable] = {
     718        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
     719        "CONCAT": lambda self: self._parse_concat(),
     720        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
     721        "DECODE": lambda self: self._parse_decode(),
     722        "EXTRACT": lambda self: self._parse_extract(),
     723        "JSON_OBJECT": lambda self: self._parse_json_object(),
     724        "LOG": lambda self: self._parse_logarithm(),
     725        "MATCH": lambda self: self._parse_match_against(),
     726        "OPENJSON": lambda self: self._parse_open_json(),
     727        "POSITION": lambda self: self._parse_position(),
     728        "SAFE_CAST": lambda self: self._parse_cast(False),
     729        "STRING_AGG": lambda self: self._parse_string_agg(),
     730        "SUBSTRING": lambda self: self._parse_substring(),
     731        "TRIM": lambda self: self._parse_trim(),
     732        "TRY_CAST": lambda self: self._parse_cast(False),
     733        "TRY_CONVERT": lambda self: self._parse_convert(False),
     734    }
     735
     736    QUERY_MODIFIER_PARSERS = {
     737        "joins": lambda self: list(iter(self._parse_join, None)),
     738        "laterals": lambda self: list(iter(self._parse_lateral, None)),
     739        "match": lambda self: self._parse_match_recognize(),
     740        "where": lambda self: self._parse_where(),
     741        "group": lambda self: self._parse_group(),
     742        "having": lambda self: self._parse_having(),
     743        "qualify": lambda self: self._parse_qualify(),
     744        "windows": lambda self: self._parse_window_clause(),
     745        "order": lambda self: self._parse_order(),
     746        "limit": lambda self: self._parse_limit(),
     747        "offset": lambda self: self._parse_offset(),
     748        "locks": lambda self: self._parse_locks(),
     749        "sample": lambda self: self._parse_table_sample(as_modifier=True),
     750    }
     751
     752    SET_PARSERS = {
     753        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
     754        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
     755        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
     756        "TRANSACTION": lambda self: self._parse_set_transaction(),
     757    }
     758
     759    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
     760
     761    TYPE_LITERAL_PARSERS: t.Dict[exp.DataType.Type, t.Callable] = {}
     762
     763    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
     764
     765    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
     766
     767    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
     768
     769    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
     770    TRANSACTION_CHARACTERISTICS = {
     771        "ISOLATION LEVEL REPEATABLE READ",
     772        "ISOLATION LEVEL READ COMMITTED",
     773        "ISOLATION LEVEL READ UNCOMMITTED",
     774        "ISOLATION LEVEL SERIALIZABLE",
     775        "READ WRITE",
     776        "READ ONLY",
     777    }
     778
     779    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
     780
     781    CLONE_KINDS = {"TIMESTAMP", "OFFSET", "STATEMENT"}
     782
     783    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
     784    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
     785    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
     786
     787    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
     788
     789    STRICT_CAST = True
     790
     791    CONCAT_NULL_OUTPUTS_STRING = False  # A NULL arg in CONCAT yields NULL by default
     792
     793    CONVERT_TYPE_FIRST = False
     794
     795    PREFIXED_PIVOT_COLUMNS = False
     796    IDENTIFY_PIVOT_STRINGS = False
     797
     798    LOG_BASE_FIRST = True
     799    LOG_DEFAULTS_TO_LN = False
     800
     801    __slots__ = (
     802        "error_level",
     803        "error_message_context",
     804        "max_errors",
     805        "sql",
     806        "errors",
     807        "_tokens",
     808        "_index",
     809        "_curr",
     810        "_next",
     811        "_prev",
     812        "_prev_comments",
     813    )
     814
     815    # Autofilled
     816    INDEX_OFFSET: int = 0
     817    UNNEST_COLUMN_ONLY: bool = False
     818    ALIAS_POST_TABLESAMPLE: bool = False
     819    STRICT_STRING_CONCAT = False
     820    NULL_ORDERING: str = "nulls_are_small"
     821    SHOW_TRIE: t.Dict = {}
     822    SET_TRIE: t.Dict = {}
     823    FORMAT_MAPPING: t.Dict[str, str] = {}
     824    FORMAT_TRIE: t.Dict = {}
     825    TIME_MAPPING: t.Dict[str, str] = {}
     826    TIME_TRIE: t.Dict = {}
     827
     828    def __init__(
     829        self,
     830        error_level: t.Optional[ErrorLevel] = None,
     831        error_message_context: int = 100,
     832        max_errors: int = 3,
     833    ):
     834        self.error_level = error_level or ErrorLevel.IMMEDIATE
     835        self.error_message_context = error_message_context
     836        self.max_errors = max_errors
     837        self.reset()
     838
     839    def reset(self):
     840        self.sql = ""
     841        self.errors = []
     842        self._tokens = []
     843        self._index = 0
     844        self._curr = None
     845        self._next = None
     846        self._prev = None
     847        self._prev_comments = None
     848
     849    def parse(
     850        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
     851    ) -> t.List[t.Optional[exp.Expression]]:
     852        """
     853        Parses a list of tokens and returns a list of syntax trees, one tree
     854        per parsed SQL statement.
     855
     856        Args:
     857            raw_tokens: The list of tokens.
     858            sql: The original SQL string, used to produce helpful debug messages.
     859
     860        Returns:
     861            The list of the produced syntax trees.
     862        """
     863        return self._parse(
     864            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
     865        )
     866
     867    def parse_into(
     868        self,
     869        expression_types: exp.IntoType,
     870        raw_tokens: t.List[Token],
     871        sql: t.Optional[str] = None,
     872    ) -> t.List[t.Optional[exp.Expression]]:
     873        """
     874        Parses a list of tokens into a given Expression type. If a collection of Expression
     875        types is given instead, this method will try to parse the token list into each one
     876        of them, stopping at the first for which the parsing succeeds.
     877
     878        Args:
     879            expression_types: The expression type(s) to try and parse the token list into.
     880            raw_tokens: The list of tokens.
     881            sql: The original SQL string, used to produce helpful debug messages.
     882
     883        Returns:
     884            The target Expression.
     885        """
     886        errors = []
     887        for expression_type in ensure_list(expression_types):
     888            parser = self.EXPRESSION_PARSERS.get(expression_type)
     889            if not parser:
     890                raise TypeError(f"No parser registered for {expression_type}")
     891
     892            try:
     893                return self._parse(parser, raw_tokens, sql)
     894            except ParseError as e:
     895                e.errors[0]["into_expression"] = expression_type
     896                errors.append(e)
     897
     898        raise ParseError(
     899            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
     900            errors=merge_errors(errors),
     901        ) from errors[-1]
     902
     903    def _parse(
     904        self,
     905        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
     906        raw_tokens: t.List[Token],
     907        sql: t.Optional[str] = None,
     908    ) -> t.List[t.Optional[exp.Expression]]:
     909        self.reset()
     910        self.sql = sql or ""
     911
     912        total = len(raw_tokens)
     913        chunks: t.List[t.List[Token]] = [[]]
     914
     915        for i, token in enumerate(raw_tokens):
     916            if token.token_type == TokenType.SEMICOLON:
     917                if i < total - 1:
     918                    chunks.append([])
     919            else:
     920                chunks[-1].append(token)
     921
     922        expressions = []
     923
     924        for tokens in chunks:
     925            self._index = -1
     926            self._tokens = tokens
     927            self._advance()
     928
     929            expressions.append(parse_method(self))
     930
     931            if self._index < len(self._tokens):
     932                self.raise_error("Invalid expression / Unexpected token")
     933
     934            self.check_errors()
     935
     936        return expressions
     937
     938    def check_errors(self) -> None:
     939        """Logs or raises any found errors, depending on the chosen error level setting."""
     940        if self.error_level == ErrorLevel.WARN:
     941            for error in self.errors:
     942                logger.error(str(error))
     943        elif self.error_level == ErrorLevel.RAISE and self.errors:
     944            raise ParseError(
     945                concat_messages(self.errors, self.max_errors),
     946                errors=merge_errors(self.errors),
     947            )
     948
     949    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
     950        """
     951        Appends an error in the list of recorded errors or raises it, depending on the chosen
     952        error level setting.
     953        """
     954        token = token or self._curr or self._prev or Token.string("")
     955        start = token.start
     956        end = token.end + 1
     957        start_context = self.sql[max(start - self.error_message_context, 0) : start]
     958        highlight = self.sql[start:end]
     959        end_context = self.sql[end : end + self.error_message_context]
     960
     961        error = ParseError.new(
     962            f"{message}. Line {token.line}, Col: {token.col}.\n"
     963            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
     964            description=message,
     965            line=token.line,
     966            col=token.col,
     967            start_context=start_context,
     968            highlight=highlight,
     969            end_context=end_context,
     970        )
     971
     972        if self.error_level == ErrorLevel.IMMEDIATE:
     973            raise error
     974
     975        self.errors.append(error)
     976
     977    def expression(
     978        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
     979    ) -> E:
     980        """
     981        Creates a new, validated Expression.
     982
     983        Args:
     984            exp_class: The expression class to instantiate.
     985            comments: An optional list of comments to attach to the expression.
     986            kwargs: The arguments to set for the expression along with their respective values.
     987
     988        Returns:
     989            The target expression.
     990        """
     991        instance = exp_class(**kwargs)
     992        instance.add_comments(comments) if comments else self._add_comments(instance)
     993        return self.validate_expression(instance)
     994
     995    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
     996        if expression and self._prev_comments:
     997            expression.add_comments(self._prev_comments)
     998            self._prev_comments = None
     999
    1000    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1001        """
    1002        Validates an Expression, making sure that all its mandatory arguments are set.
    1003
    1004        Args:
    1005            expression: The expression to validate.
    1006            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1007
    1008        Returns:
    1009            The validated expression.
    1010        """
    1011        if self.error_level != ErrorLevel.IGNORE:
    1012            for error_message in expression.error_messages(args):
    1013                self.raise_error(error_message)
    1014
    1015        return expression
    1016
    1017    def _find_sql(self, start: Token, end: Token) -> str:
    1018        return self.sql[start.start : end.end + 1]
    1019
    1020    def _advance(self, times: int = 1) -> None:
    1021        self._index += times
    1022        self._curr = seq_get(self._tokens, self._index)
    1023        self._next = seq_get(self._tokens, self._index + 1)
    1024
    1025        if self._index > 0:
    1026            self._prev = self._tokens[self._index - 1]
    1027            self._prev_comments = self._prev.comments
    1028        else:
    1029            self._prev = None
    1030            self._prev_comments = None
    1031
    1032    def _retreat(self, index: int) -> None:
    1033        if index != self._index:
    1034            self._advance(index - self._index)
    1035
    1036    def _parse_command(self) -> exp.Command:
    1037        return self.expression(exp.Command, this=self._prev.text, expression=self._parse_string())
    1038
    1039    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1040        start = self._prev
    1041        exists = self._parse_exists() if allow_exists else None
    1042
    1043        self._match(TokenType.ON)
    1044
    1045        kind = self._match_set(self.CREATABLES) and self._prev
    1046        if not kind:
    1047            return self._parse_as_command(start)
    1048
    1049        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1050            this = self._parse_user_defined_function(kind=kind.token_type)
    1051        elif kind.token_type == TokenType.TABLE:
    1052            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1053        elif kind.token_type == TokenType.COLUMN:
    1054            this = self._parse_column()
    1055        else:
    1056            this = self._parse_id_var()
    1057
    1058        self._match(TokenType.IS)
    1059
    1060        return self.expression(
    1061            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
    1062        )
    1063
    1064    def _parse_to_table(
    1065        self,
    1066    ) -> exp.ToTableProperty:
    1067        table = self._parse_table_parts(schema=True)
    1068        return self.expression(exp.ToTableProperty, this=table)
    1069
    1070    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1071    def _parse_ttl(self) -> exp.Expression:
    1072        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1073            this = self._parse_bitwise()
    1074
    1075            if self._match_text_seq("DELETE"):
    1076                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1077            if self._match_text_seq("RECOMPRESS"):
    1078                return self.expression(
    1079                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1080                )
    1081            if self._match_text_seq("TO", "DISK"):
    1082                return self.expression(
    1083                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1084                )
    1085            if self._match_text_seq("TO", "VOLUME"):
    1086                return self.expression(
    1087                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1088                )
    1089
    1090            return this
    1091
    1092        expressions = self._parse_csv(_parse_ttl_action)
    1093        where = self._parse_where()
    1094        group = self._parse_group()
    1095
    1096        aggregates = None
    1097        if group and self._match(TokenType.SET):
    1098            aggregates = self._parse_csv(self._parse_set_item)
    1099
    1100        return self.expression(
    1101            exp.MergeTreeTTL,
    1102            expressions=expressions,
    1103            where=where,
    1104            group=group,
    1105            aggregates=aggregates,
    1106        )
    1107
    1108    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1109        if self._curr is None:
    1110            return None
    1111
    1112        if self._match_set(self.STATEMENT_PARSERS):
    1113            return self.STATEMENT_PARSERS[self._prev.token_type](self)
    1114
    1115        if self._match_set(Tokenizer.COMMANDS):
    1116            return self._parse_command()
    1117
    1118        expression = self._parse_expression()
    1119        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1120        return self._parse_query_modifiers(expression)
    1121
    1122    def _parse_drop(self) -> exp.Drop | exp.Command:
    1123        start = self._prev
    1124        temporary = self._match(TokenType.TEMPORARY)
    1125        materialized = self._match_text_seq("MATERIALIZED")
    1126
    1127        kind = self._match_set(self.CREATABLES) and self._prev.text
    1128        if not kind:
    1129            return self._parse_as_command(start)
    1130
    1131        return self.expression(
    1132            exp.Drop,
    1133            exists=self._parse_exists(),
    1134            this=self._parse_table(schema=True),
    1135            kind=kind,
    1136            temporary=temporary,
    1137            materialized=materialized,
    1138            cascade=self._match_text_seq("CASCADE"),
    1139            constraints=self._match_text_seq("CONSTRAINTS"),
    1140            purge=self._match_text_seq("PURGE"),
    1141        )
    1142
    1143    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1144        return (
    1145            self._match(TokenType.IF)
    1146            and (not not_ or self._match(TokenType.NOT))
    1147            and self._match(TokenType.EXISTS)
    1148        )
    1149
    1150    def _parse_create(self) -> exp.Create | exp.Command:
    1151        # Note: this can't be None because we've matched a statement parser
    1152        start = self._prev
    1153        replace = start.text.upper() == "REPLACE" or self._match_pair(
    1154            TokenType.OR, TokenType.REPLACE
    1155        )
    1156        unique = self._match(TokenType.UNIQUE)
    1157
    1158        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1159            self._advance()
    1160
    1161        properties = None
    1162        create_token = self._match_set(self.CREATABLES) and self._prev
    1163
    1164        if not create_token:
    1165            # exp.Properties.Location.POST_CREATE
    1166            properties = self._parse_properties()
    1167            create_token = self._match_set(self.CREATABLES) and self._prev
    1168
    1169            if not properties or not create_token:
    1170                return self._parse_as_command(start)
    1171
    1172        exists = self._parse_exists(not_=True)
    1173        this = None
    1174        expression = None
    1175        indexes = None
    1176        no_schema_binding = None
    1177        begin = None
    1178        clone = None
    1179
    1180        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1181            nonlocal properties
    1182            if properties and temp_props:
    1183                properties.expressions.extend(temp_props.expressions)
    1184            elif temp_props:
    1185                properties = temp_props
    1186
    1187        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1188            this = self._parse_user_defined_function(kind=create_token.token_type)
    1189
    1190            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1191            extend_props(self._parse_properties())
    1192
    1193            self._match(TokenType.ALIAS)
    1194            begin = self._match(TokenType.BEGIN)
    1195            return_ = self._match_text_seq("RETURN")
    1196            expression = self._parse_statement()
    1197
    1198            if return_:
    1199                expression = self.expression(exp.Return, this=expression)
    1200        elif create_token.token_type == TokenType.INDEX:
    1201            this = self._parse_index(index=self._parse_id_var())
    1202        elif create_token.token_type in self.DB_CREATABLES:
    1203            table_parts = self._parse_table_parts(schema=True)
    1204
    1205            # exp.Properties.Location.POST_NAME
    1206            self._match(TokenType.COMMA)
    1207            extend_props(self._parse_properties(before=True))
    1208
    1209            this = self._parse_schema(this=table_parts)
    1210
    1211            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1212            extend_props(self._parse_properties())
    1213
    1214            self._match(TokenType.ALIAS)
    1215            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1216                # exp.Properties.Location.POST_ALIAS
    1217                extend_props(self._parse_properties())
    1218
    1219            expression = self._parse_ddl_select()
    1220
    1221            if create_token.token_type == TokenType.TABLE:
    1222                indexes = []
    1223                while True:
    1224                    index = self._parse_index()
    1225
    1226                    # exp.Properties.Location.POST_EXPRESSION and POST_INDEX
    1227                    extend_props(self._parse_properties())
    1228
    1229                    if not index:
    1230                        break
    1231                    else:
    1232                        self._match(TokenType.COMMA)
    1233                        indexes.append(index)
    1234            elif create_token.token_type == TokenType.VIEW:
    1235                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1236                    no_schema_binding = True
    1237
    1238            if self._match_text_seq("CLONE"):
    1239                clone = self._parse_table(schema=True)
    1240                when = self._match_texts({"AT", "BEFORE"}) and self._prev.text.upper()
    1241                clone_kind = (
    1242                    self._match(TokenType.L_PAREN)
    1243                    and self._match_texts(self.CLONE_KINDS)
    1244                    and self._prev.text.upper()
    1245                )
    1246                clone_expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    1247                self._match(TokenType.R_PAREN)
    1248                clone = self.expression(
    1249                    exp.Clone, this=clone, when=when, kind=clone_kind, expression=clone_expression
    1250                )
    1251
    1252        return self.expression(
    1253            exp.Create,
    1254            this=this,
    1255            kind=create_token.text,
    1256            replace=replace,
    1257            unique=unique,
    1258            expression=expression,
    1259            exists=exists,
    1260            properties=properties,
    1261            indexes=indexes,
    1262            no_schema_binding=no_schema_binding,
    1263            begin=begin,
    1264            clone=clone,
    1265        )
    1266
    1267    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    1268        # only used for teradata currently
    1269        self._match(TokenType.COMMA)
    1270
    1271        kwargs = {
    1272            "no": self._match_text_seq("NO"),
    1273            "dual": self._match_text_seq("DUAL"),
    1274            "before": self._match_text_seq("BEFORE"),
    1275            "default": self._match_text_seq("DEFAULT"),
    1276            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    1277            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    1278            "after": self._match_text_seq("AFTER"),
    1279            "minimum": self._match_texts(("MIN", "MINIMUM")),
    1280            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    1281        }
    1282
    1283        if self._match_texts(self.PROPERTY_PARSERS):
    1284            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    1285            try:
    1286                return parser(self, **{k: v for k, v in kwargs.items() if v})
    1287            except TypeError:
    1288                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    1289
    1290        return None
    1291
    1292    def _parse_property(self) -> t.Optional[exp.Expression]:
    1293        if self._match_texts(self.PROPERTY_PARSERS):
    1294            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    1295
    1296        if self._match_pair(TokenType.DEFAULT, TokenType.CHARACTER_SET):
    1297            return self._parse_character_set(default=True)
    1298
    1299        if self._match_text_seq("COMPOUND", "SORTKEY"):
    1300            return self._parse_sortkey(compound=True)
    1301
    1302        if self._match_text_seq("SQL", "SECURITY"):
    1303            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    1304
    1305        assignment = self._match_pair(
    1306            TokenType.VAR, TokenType.EQ, advance=False
    1307        ) or self._match_pair(TokenType.STRING, TokenType.EQ, advance=False)
    1308
    1309        if assignment:
    1310            key = self._parse_var_or_string()
    1311            self._match(TokenType.EQ)
    1312            return self.expression(exp.Property, this=key, value=self._parse_column())
    1313
    1314        return None
    1315
    1316    def _parse_stored(self) -> exp.FileFormatProperty:
    1317        self._match(TokenType.ALIAS)
    1318
    1319        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    1320        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    1321
    1322        return self.expression(
    1323            exp.FileFormatProperty,
    1324            this=self.expression(
    1325                exp.InputOutputFormat, input_format=input_format, output_format=output_format
    1326            )
    1327            if input_format or output_format
    1328            else self._parse_var_or_string() or self._parse_number() or self._parse_id_var(),
    1329        )
    1330
    1331    def _parse_property_assignment(self, exp_class: t.Type[E]) -> E:
    1332        self._match(TokenType.EQ)
    1333        self._match(TokenType.ALIAS)
    1334        return self.expression(exp_class, this=self._parse_field())
    1335
    1336    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    1337        properties = []
    1338        while True:
    1339            if before:
    1340                prop = self._parse_property_before()
    1341            else:
    1342                prop = self._parse_property()
    1343
    1344            if not prop:
    1345                break
    1346            for p in ensure_list(prop):
    1347                properties.append(p)
    1348
    1349        if properties:
    1350            return self.expression(exp.Properties, expressions=properties)
    1351
    1352        return None
    1353
    1354    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    1355        return self.expression(
    1356            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    1357        )
    1358
    1359    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    1360        if self._index >= 2:
    1361            pre_volatile_token = self._tokens[self._index - 2]
    1362        else:
    1363            pre_volatile_token = None
    1364
    1365        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    1366            return exp.VolatileProperty()
    1367
    1368        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    1369
    1370    def _parse_with_property(
    1371        self,
    1372    ) -> t.Optional[exp.Expression] | t.List[t.Optional[exp.Expression]]:
    1373        self._match(TokenType.WITH)
    1374        if self._match(TokenType.L_PAREN, advance=False):
    1375            return self._parse_wrapped_csv(self._parse_property)
    1376
    1377        if self._match_text_seq("JOURNAL"):
    1378            return self._parse_withjournaltable()
    1379
    1380        if self._match_text_seq("DATA"):
    1381            return self._parse_withdata(no=False)
    1382        elif self._match_text_seq("NO", "DATA"):
    1383            return self._parse_withdata(no=True)
    1384
    1385        if not self._next:
    1386            return None
    1387
    1388        return self._parse_withisolatedloading()
    1389
    1390    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    1391    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    1392        self._match(TokenType.EQ)
    1393
    1394        user = self._parse_id_var()
    1395        self._match(TokenType.PARAMETER)
    1396        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    1397
    1398        if not user or not host:
    1399            return None
    1400
    1401        return exp.DefinerProperty(this=f"{user}@{host}")
    1402
    1403    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    1404        self._match(TokenType.TABLE)
    1405        self._match(TokenType.EQ)
    1406        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    1407
    1408    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    1409        return self.expression(exp.LogProperty, no=no)
    1410
    1411    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    1412        return self.expression(exp.JournalProperty, **kwargs)
    1413
    1414    def _parse_checksum(self) -> exp.ChecksumProperty:
    1415        self._match(TokenType.EQ)
    1416
    1417        on = None
    1418        if self._match(TokenType.ON):
    1419            on = True
    1420        elif self._match_text_seq("OFF"):
    1421            on = False
    1422
    1423        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    1424
    1425    def _parse_cluster(self) -> t.Optional[exp.Cluster]:
    1426        if not self._match_text_seq("BY"):
    1427            self._retreat(self._index - 1)
    1428            return None
    1429
    1430        return self.expression(exp.Cluster, expressions=self._parse_csv(self._parse_ordered))
    1431
    1432    def _parse_freespace(self) -> exp.FreespaceProperty:
    1433        self._match(TokenType.EQ)
    1434        return self.expression(
    1435            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    1436        )
    1437
    1438    def _parse_mergeblockratio(
    1439        self, no: bool = False, default: bool = False
    1440    ) -> exp.MergeBlockRatioProperty:
    1441        if self._match(TokenType.EQ):
    1442            return self.expression(
    1443                exp.MergeBlockRatioProperty,
    1444                this=self._parse_number(),
    1445                percent=self._match(TokenType.PERCENT),
    1446            )
    1447
    1448        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    1449
    1450    def _parse_datablocksize(
    1451        self,
    1452        default: t.Optional[bool] = None,
    1453        minimum: t.Optional[bool] = None,
    1454        maximum: t.Optional[bool] = None,
    1455    ) -> exp.DataBlocksizeProperty:
    1456        self._match(TokenType.EQ)
    1457        size = self._parse_number()
    1458
    1459        units = None
    1460        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    1461            units = self._prev.text
    1462
    1463        return self.expression(
    1464            exp.DataBlocksizeProperty,
    1465            size=size,
    1466            units=units,
    1467            default=default,
    1468            minimum=minimum,
    1469            maximum=maximum,
    1470        )
    1471
    1472    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    1473        self._match(TokenType.EQ)
    1474        always = self._match_text_seq("ALWAYS")
    1475        manual = self._match_text_seq("MANUAL")
    1476        never = self._match_text_seq("NEVER")
    1477        default = self._match_text_seq("DEFAULT")
    1478
    1479        autotemp = None
    1480        if self._match_text_seq("AUTOTEMP"):
    1481            autotemp = self._parse_schema()
    1482
    1483        return self.expression(
    1484            exp.BlockCompressionProperty,
    1485            always=always,
    1486            manual=manual,
    1487            never=never,
    1488            default=default,
    1489            autotemp=autotemp,
    1490        )
    1491
    1492    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
    1493        no = self._match_text_seq("NO")
    1494        concurrent = self._match_text_seq("CONCURRENT")
    1495        self._match_text_seq("ISOLATED", "LOADING")
    1496        for_all = self._match_text_seq("FOR", "ALL")
    1497        for_insert = self._match_text_seq("FOR", "INSERT")
    1498        for_none = self._match_text_seq("FOR", "NONE")
    1499        return self.expression(
    1500            exp.IsolatedLoadingProperty,
    1501            no=no,
    1502            concurrent=concurrent,
    1503            for_all=for_all,
    1504            for_insert=for_insert,
    1505            for_none=for_none,
    1506        )
    1507
    1508    def _parse_locking(self) -> exp.LockingProperty:
    1509        if self._match(TokenType.TABLE):
    1510            kind = "TABLE"
    1511        elif self._match(TokenType.VIEW):
    1512            kind = "VIEW"
    1513        elif self._match(TokenType.ROW):
    1514            kind = "ROW"
    1515        elif self._match_text_seq("DATABASE"):
    1516            kind = "DATABASE"
    1517        else:
    1518            kind = None
    1519
    1520        if kind in ("DATABASE", "TABLE", "VIEW"):
    1521            this = self._parse_table_parts()
    1522        else:
    1523            this = None
    1524
    1525        if self._match(TokenType.FOR):
    1526            for_or_in = "FOR"
    1527        elif self._match(TokenType.IN):
    1528            for_or_in = "IN"
    1529        else:
    1530            for_or_in = None
    1531
    1532        if self._match_text_seq("ACCESS"):
    1533            lock_type = "ACCESS"
    1534        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    1535            lock_type = "EXCLUSIVE"
    1536        elif self._match_text_seq("SHARE"):
    1537            lock_type = "SHARE"
    1538        elif self._match_text_seq("READ"):
    1539            lock_type = "READ"
    1540        elif self._match_text_seq("WRITE"):
    1541            lock_type = "WRITE"
    1542        elif self._match_text_seq("CHECKSUM"):
    1543            lock_type = "CHECKSUM"
    1544        else:
    1545            lock_type = None
    1546
    1547        override = self._match_text_seq("OVERRIDE")
    1548
    1549        return self.expression(
    1550            exp.LockingProperty,
    1551            this=this,
    1552            kind=kind,
    1553            for_or_in=for_or_in,
    1554            lock_type=lock_type,
    1555            override=override,
    1556        )
    1557
    1558    def _parse_partition_by(self) -> t.List[t.Optional[exp.Expression]]:
    1559        if self._match(TokenType.PARTITION_BY):
    1560            return self._parse_csv(self._parse_conjunction)
    1561        return []
    1562
    1563    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    1564        self._match(TokenType.EQ)
    1565        return self.expression(
    1566            exp.PartitionedByProperty,
    1567            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    1568        )
    1569
    1570    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    1571        if self._match_text_seq("AND", "STATISTICS"):
    1572            statistics = True
    1573        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    1574            statistics = False
    1575        else:
    1576            statistics = None
    1577
    1578        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    1579
    1580    def _parse_no_property(self) -> t.Optional[exp.NoPrimaryIndexProperty]:
    1581        if self._match_text_seq("PRIMARY", "INDEX"):
    1582            return exp.NoPrimaryIndexProperty()
    1583        return None
    1584
    1585    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    1586        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    1587            return exp.OnCommitProperty()
    1588        elif self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    1589            return exp.OnCommitProperty(delete=True)
    1590        return None
    1591
    1592    def _parse_distkey(self) -> exp.DistKeyProperty:
    1593        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    1594
    1595    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    1596        table = self._parse_table(schema=True)
    1597
    1598        options = []
    1599        while self._match_texts(("INCLUDING", "EXCLUDING")):
    1600            this = self._prev.text.upper()
    1601
    1602            id_var = self._parse_id_var()
    1603            if not id_var:
    1604                return None
    1605
    1606            options.append(
    1607                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    1608            )
    1609
    1610        return self.expression(exp.LikeProperty, this=table, expressions=options)
    1611
    1612    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    1613        return self.expression(
    1614            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    1615        )
    1616
    1617    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    1618        self._match(TokenType.EQ)
    1619        return self.expression(
    1620            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    1621        )
    1622
    1623    def _parse_returns(self) -> exp.ReturnsProperty:
    1624        value: t.Optional[exp.Expression]
    1625        is_table = self._match(TokenType.TABLE)
    1626
    1627        if is_table:
    1628            if self._match(TokenType.LT):
    1629                value = self.expression(
    1630                    exp.Schema,
    1631                    this="TABLE",
    1632                    expressions=self._parse_csv(self._parse_struct_types),
    1633                )
    1634                if not self._match(TokenType.GT):
    1635                    self.raise_error("Expecting >")
    1636            else:
    1637                value = self._parse_schema(exp.var("TABLE"))
    1638        else:
    1639            value = self._parse_types()
    1640
    1641        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
    1642
    1643    def _parse_describe(self) -> exp.Describe:
    1644        kind = self._match_set(self.CREATABLES) and self._prev.text
    1645        this = self._parse_table()
    1646        return self.expression(exp.Describe, this=this, kind=kind)
    1647
    1648    def _parse_insert(self) -> exp.Insert:
    1649        overwrite = self._match(TokenType.OVERWRITE)
    1650        local = self._match_text_seq("LOCAL")
    1651        alternative = None
    1652
    1653        if self._match_text_seq("DIRECTORY"):
    1654            this: t.Optional[exp.Expression] = self.expression(
    1655                exp.Directory,
    1656                this=self._parse_var_or_string(),
    1657                local=local,
    1658                row_format=self._parse_row_format(match_row=True),
    1659            )
    1660        else:
    1661            if self._match(TokenType.OR):
    1662                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    1663
    1664            self._match(TokenType.INTO)
    1665            self._match(TokenType.TABLE)
    1666            this = self._parse_table(schema=True)
    1667
    1668        return self.expression(
    1669            exp.Insert,
    1670            this=this,
    1671            exists=self._parse_exists(),
    1672            partition=self._parse_partition(),
    1673            expression=self._parse_ddl_select(),
    1674            conflict=self._parse_on_conflict(),
    1675            returning=self._parse_returning(),
    1676            overwrite=overwrite,
    1677            alternative=alternative,
    1678        )
    1679
    1680    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    1681        conflict = self._match_text_seq("ON", "CONFLICT")
    1682        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    1683
    1684        if not conflict and not duplicate:
    1685            return None
    1686
    1687        nothing = None
    1688        expressions = None
    1689        key = None
    1690        constraint = None
    1691
    1692        if conflict:
    1693            if self._match_text_seq("ON", "CONSTRAINT"):
    1694                constraint = self._parse_id_var()
    1695            else:
    1696                key = self._parse_csv(self._parse_value)
    1697
    1698        self._match_text_seq("DO")
    1699        if self._match_text_seq("NOTHING"):
    1700            nothing = True
    1701        else:
    1702            self._match(TokenType.UPDATE)
    1703            expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    1704
    1705        return self.expression(
    1706            exp.OnConflict,
    1707            duplicate=duplicate,
    1708            expressions=expressions,
    1709            nothing=nothing,
    1710            key=key,
    1711            constraint=constraint,
    1712        )
    1713
    1714    def _parse_returning(self) -> t.Optional[exp.Returning]:
    1715        if not self._match(TokenType.RETURNING):
    1716            return None
    1717
    1718        return self.expression(exp.Returning, expressions=self._parse_csv(self._parse_column))
    1719
    1720    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    1721        if not self._match(TokenType.FORMAT):
    1722            return None
    1723        return self._parse_row_format()
    1724
    1725    def _parse_row_format(
    1726        self, match_row: bool = False
    1727    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    1728        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    1729            return None
    1730
    1731        if self._match_text_seq("SERDE"):
    1732            return self.expression(exp.RowFormatSerdeProperty, this=self._parse_string())
    1733
    1734        self._match_text_seq("DELIMITED")
    1735
    1736        kwargs = {}
    1737
    1738        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    1739            kwargs["fields"] = self._parse_string()
    1740            if self._match_text_seq("ESCAPED", "BY"):
    1741                kwargs["escaped"] = self._parse_string()
    1742        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    1743            kwargs["collection_items"] = self._parse_string()
    1744        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    1745            kwargs["map_keys"] = self._parse_string()
    1746        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    1747            kwargs["lines"] = self._parse_string()
    1748        if self._match_text_seq("NULL", "DEFINED", "AS"):
    1749            kwargs["null"] = self._parse_string()
    1750
    1751        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    1752
    1753    def _parse_load(self) -> exp.LoadData | exp.Command:
    1754        if self._match_text_seq("DATA"):
    1755            local = self._match_text_seq("LOCAL")
    1756            self._match_text_seq("INPATH")
    1757            inpath = self._parse_string()
    1758            overwrite = self._match(TokenType.OVERWRITE)
    1759            self._match_pair(TokenType.INTO, TokenType.TABLE)
    1760
    1761            return self.expression(
    1762                exp.LoadData,
    1763                this=self._parse_table(schema=True),
    1764                local=local,
    1765                overwrite=overwrite,
    1766                inpath=inpath,
    1767                partition=self._parse_partition(),
    1768                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    1769                serde=self._match_text_seq("SERDE") and self._parse_string(),
    1770            )
    1771        return self._parse_as_command(self._prev)
    1772
    1773    def _parse_delete(self) -> exp.Delete:
    1774        self._match(TokenType.FROM)
    1775
    1776        return self.expression(
    1777            exp.Delete,
    1778            this=self._parse_table(),
    1779            using=self._parse_csv(lambda: self._match(TokenType.USING) and self._parse_table()),
    1780            where=self._parse_where(),
    1781            returning=self._parse_returning(),
    1782        )
    1783
    1784    def _parse_update(self) -> exp.Update:
    1785        return self.expression(
    1786            exp.Update,
    1787            **{  # type: ignore
    1788                "this": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),
    1789                "expressions": self._match(TokenType.SET) and self._parse_csv(self._parse_equality),
    1790                "from": self._parse_from(modifiers=True),
    1791                "where": self._parse_where(),
    1792                "returning": self._parse_returning(),
    1793            },
    1794        )
    1795
    1796    def _parse_uncache(self) -> exp.Uncache:
    1797        if not self._match(TokenType.TABLE):
    1798            self.raise_error("Expecting TABLE after UNCACHE")
    1799
    1800        return self.expression(
    1801            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    1802        )
    1803
    1804    def _parse_cache(self) -> exp.Cache:
    1805        lazy = self._match_text_seq("LAZY")
    1806        self._match(TokenType.TABLE)
    1807        table = self._parse_table(schema=True)
    1808
    1809        options = []
    1810        if self._match_text_seq("OPTIONS"):
    1811            self._match_l_paren()
    1812            k = self._parse_string()
    1813            self._match(TokenType.EQ)
    1814            v = self._parse_string()
    1815            options = [k, v]
    1816            self._match_r_paren()
    1817
    1818        self._match(TokenType.ALIAS)
    1819        return self.expression(
    1820            exp.Cache,
    1821            this=table,
    1822            lazy=lazy,
    1823            options=options,
    1824            expression=self._parse_select(nested=True),
    1825        )
    1826
    1827    def _parse_partition(self) -> t.Optional[exp.Partition]:
    1828        if not self._match(TokenType.PARTITION):
    1829            return None
    1830
    1831        return self.expression(
    1832            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
    1833        )
    1834
    1835    def _parse_value(self) -> exp.Tuple:
    1836        if self._match(TokenType.L_PAREN):
    1837            expressions = self._parse_csv(self._parse_conjunction)
    1838            self._match_r_paren()
    1839            return self.expression(exp.Tuple, expressions=expressions)
    1840
    1841        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
    1842        # Source: https://prestodb.io/docs/current/sql/values.html
    1843        return self.expression(exp.Tuple, expressions=[self._parse_conjunction()])
    1844
    1845    def _parse_select(
    1846        self, nested: bool = False, table: bool = False, parse_subquery_alias: bool = True
    1847    ) -> t.Optional[exp.Expression]:
    1848        cte = self._parse_with()
    1849        if cte:
    1850            this = self._parse_statement()
    1851
    1852            if not this:
    1853                self.raise_error("Failed to parse any statement following CTE")
    1854                return cte
    1855
    1856            if "with" in this.arg_types:
    1857                this.set("with", cte)
    1858            else:
    1859                self.raise_error(f"{this.key} does not support CTE")
    1860                this = cte
    1861        elif self._match(TokenType.SELECT):
    1862            comments = self._prev_comments
    1863
    1864            hint = self._parse_hint()
    1865            all_ = self._match(TokenType.ALL)
    1866            distinct = self._match(TokenType.DISTINCT)
    1867
    1868            kind = (
    1869                self._match(TokenType.ALIAS)
    1870                and self._match_texts(("STRUCT", "VALUE"))
    1871                and self._prev.text
    1872            )
    1873
    1874            if distinct:
    1875                distinct = self.expression(
    1876                    exp.Distinct,
    1877                    on=self._parse_value() if self._match(TokenType.ON) else None,
    1878                )
    1879
    1880            if all_ and distinct:
    1881                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    1882
    1883            limit = self._parse_limit(top=True)
    1884            expressions = self._parse_csv(self._parse_expression)
    1885
    1886            this = self.expression(
    1887                exp.Select,
    1888                kind=kind,
    1889                hint=hint,
    1890                distinct=distinct,
    1891                expressions=expressions,
    1892                limit=limit,
    1893            )
    1894            this.comments = comments
    1895
    1896            into = self._parse_into()
    1897            if into:
    1898                this.set("into", into)
    1899
    1900            from_ = self._parse_from()
    1901            if from_:
    1902                this.set("from", from_)
    1903
    1904            this = self._parse_query_modifiers(this)
    1905        elif (table or nested) and self._match(TokenType.L_PAREN):
    1906            if self._match(TokenType.PIVOT):
    1907                this = self._parse_simplified_pivot()
    1908            elif self._match(TokenType.FROM):
    1909                this = exp.select("*").from_(
    1910                    t.cast(exp.From, self._parse_from(skip_from_token=True))
    1911                )
    1912            else:
    1913                this = self._parse_table() if table else self._parse_select(nested=True)
    1914                this = self._parse_set_operations(self._parse_query_modifiers(this))
    1915
    1916            self._match_r_paren()
    1917
    1918            # early return so that subquery unions aren't parsed again
    1919            # SELECT * FROM (SELECT 1) UNION ALL SELECT 1
    1920            # Union ALL should be a property of the top select node, not the subquery
    1921            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    1922        elif self._match(TokenType.VALUES):
    1923            this = self.expression(
    1924                exp.Values,
    1925                expressions=self._parse_csv(self._parse_value),
    1926                alias=self._parse_table_alias(),
    1927            )
    1928        else:
    1929            this = None
    1930
    1931        return self._parse_set_operations(this)
    1932
    1933    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    1934        if not skip_with_token and not self._match(TokenType.WITH):
    1935            return None
    1936
    1937        comments = self._prev_comments
    1938        recursive = self._match(TokenType.RECURSIVE)
    1939
    1940        expressions = []
    1941        while True:
    1942            expressions.append(self._parse_cte())
    1943
    1944            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    1945                break
    1946            else:
    1947                self._match(TokenType.WITH)
    1948
    1949        return self.expression(
    1950            exp.With, comments=comments, expressions=expressions, recursive=recursive
    1951        )
    1952
    1953    def _parse_cte(self) -> exp.CTE:
    1954        alias = self._parse_table_alias()
    1955        if not alias or not alias.this:
    1956            self.raise_error("Expected CTE to have alias")
    1957
    1958        self._match(TokenType.ALIAS)
    1959        return self.expression(
    1960            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
    1961        )
    1962
    1963    def _parse_table_alias(
    1964        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    1965    ) -> t.Optional[exp.TableAlias]:
    1966        any_token = self._match(TokenType.ALIAS)
    1967        alias = (
    1968            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    1969            or self._parse_string_as_identifier()
    1970        )
    1971
    1972        index = self._index
    1973        if self._match(TokenType.L_PAREN):
    1974            columns = self._parse_csv(self._parse_function_parameter)
    1975            self._match_r_paren() if columns else self._retreat(index)
    1976        else:
    1977            columns = None
    1978
    1979        if not alias and not columns:
    1980            return None
    1981
    1982        return self.expression(exp.TableAlias, this=alias, columns=columns)
    1983
    1984    def _parse_subquery(
    1985        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    1986    ) -> t.Optional[exp.Subquery]:
    1987        if not this:
    1988            return None
    1989
    1990        return self.expression(
    1991            exp.Subquery,
    1992            this=this,
    1993            pivots=self._parse_pivots(),
    1994            alias=self._parse_table_alias() if parse_alias else None,
    1995        )
    1996
    1997    def _parse_query_modifiers(
    1998        self, this: t.Optional[exp.Expression]
    1999    ) -> t.Optional[exp.Expression]:
    2000        if isinstance(this, self.MODIFIABLES):
    2001            for key, parser in self.QUERY_MODIFIER_PARSERS.items():
    2002                expression = parser(self)
    2003
    2004                if expression:
    2005                    if key == "limit":
    2006                        offset = expression.args.pop("offset", None)
    2007                        if offset:
    2008                            this.set("offset", exp.Offset(expression=offset))
    2009                    this.set(key, expression)
    2010        return this
    2011
    2012    def _parse_hint(self) -> t.Optional[exp.Hint]:
    2013        if self._match(TokenType.HINT):
    2014            hints = self._parse_csv(self._parse_function)
    2015
    2016            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
    2017                self.raise_error("Expected */ after HINT")
    2018
    2019            return self.expression(exp.Hint, expressions=hints)
    2020
    2021        return None
    2022
    2023    def _parse_into(self) -> t.Optional[exp.Into]:
    2024        if not self._match(TokenType.INTO):
    2025            return None
    2026
    2027        temp = self._match(TokenType.TEMPORARY)
    2028        unlogged = self._match_text_seq("UNLOGGED")
    2029        self._match(TokenType.TABLE)
    2030
    2031        return self.expression(
    2032            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    2033        )
    2034
    2035    def _parse_from(
    2036        self, modifiers: bool = False, skip_from_token: bool = False
    2037    ) -> t.Optional[exp.From]:
    2038        if not skip_from_token and not self._match(TokenType.FROM):
    2039            return None
    2040
    2041        comments = self._prev_comments
    2042        this = self._parse_table()
    2043
    2044        return self.expression(
    2045            exp.From,
    2046            comments=comments,
    2047            this=self._parse_query_modifiers(this) if modifiers else this,
    2048        )
    2049
    2050    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    2051        if not self._match(TokenType.MATCH_RECOGNIZE):
    2052            return None
    2053
    2054        self._match_l_paren()
    2055
    2056        partition = self._parse_partition_by()
    2057        order = self._parse_order()
    2058        measures = (
    2059            self._parse_csv(self._parse_expression) if self._match_text_seq("MEASURES") else None
    2060        )
    2061
    2062        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    2063            rows = exp.var("ONE ROW PER MATCH")
    2064        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    2065            text = "ALL ROWS PER MATCH"
    2066            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    2067                text += f" SHOW EMPTY MATCHES"
    2068            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    2069                text += f" OMIT EMPTY MATCHES"
    2070            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    2071                text += f" WITH UNMATCHED ROWS"
    2072            rows = exp.var(text)
    2073        else:
    2074            rows = None
    2075
    2076        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    2077            text = "AFTER MATCH SKIP"
    2078            if self._match_text_seq("PAST", "LAST", "ROW"):
    2079                text += f" PAST LAST ROW"
    2080            elif self._match_text_seq("TO", "NEXT", "ROW"):
    2081                text += f" TO NEXT ROW"
    2082            elif self._match_text_seq("TO", "FIRST"):
    2083                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    2084            elif self._match_text_seq("TO", "LAST"):
    2085                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    2086            after = exp.var(text)
    2087        else:
    2088            after = None
    2089
    2090        if self._match_text_seq("PATTERN"):
    2091            self._match_l_paren()
    2092
    2093            if not self._curr:
    2094                self.raise_error("Expecting )", self._curr)
    2095
    2096            paren = 1
    2097            start = self._curr
    2098
    2099            while self._curr and paren > 0:
    2100                if self._curr.token_type == TokenType.L_PAREN:
    2101                    paren += 1
    2102                if self._curr.token_type == TokenType.R_PAREN:
    2103                    paren -= 1
    2104
    2105                end = self._prev
    2106                self._advance()
    2107
    2108            if paren > 0:
    2109                self.raise_error("Expecting )", self._curr)
    2110
    2111            pattern = exp.var(self._find_sql(start, end))
    2112        else:
    2113            pattern = None
    2114
    2115        define = (
    2116            self._parse_csv(
    2117                lambda: self.expression(
    2118                    exp.Alias,
    2119                    alias=self._parse_id_var(any_token=True),
    2120                    this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
    2121                )
    2122            )
    2123            if self._match_text_seq("DEFINE")
    2124            else None
    2125        )
    2126
    2127        self._match_r_paren()
    2128
    2129        return self.expression(
    2130            exp.MatchRecognize,
    2131            partition_by=partition,
    2132            order=order,
    2133            measures=measures,
    2134            rows=rows,
    2135            after=after,
    2136            pattern=pattern,
    2137            define=define,
    2138            alias=self._parse_table_alias(),
    2139        )
    2140
    2141    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    2142        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY)
    2143        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    2144
    2145        if outer_apply or cross_apply:
    2146            this = self._parse_select(table=True)
    2147            view = None
    2148            outer = not cross_apply
    2149        elif self._match(TokenType.LATERAL):
    2150            this = self._parse_select(table=True)
    2151            view = self._match(TokenType.VIEW)
    2152            outer = self._match(TokenType.OUTER)
    2153        else:
    2154            return None
    2155
    2156        if not this:
    2157            this = self._parse_function() or self._parse_id_var(any_token=False)
    2158            while self._match(TokenType.DOT):
    2159                this = exp.Dot(
    2160                    this=this,
    2161                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    2162                )
    2163
    2164        if view:
    2165            table = self._parse_id_var(any_token=False)
    2166            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    2167            table_alias: t.Optional[exp.TableAlias] = self.expression(
    2168                exp.TableAlias, this=table, columns=columns
    2169            )
    2170        elif isinstance(this, exp.Subquery) and this.alias:
    2171            # Ensures parity between the Subquery's and the Lateral's "alias" args
    2172            table_alias = this.args["alias"].copy()
    2173        else:
    2174            table_alias = self._parse_table_alias()
    2175
    2176        return self.expression(exp.Lateral, this=this, view=view, outer=outer, alias=table_alias)
    2177
    2178    def _parse_join_parts(
    2179        self,
    2180    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    2181        return (
    2182            self._match_set(self.JOIN_METHODS) and self._prev,
    2183            self._match_set(self.JOIN_SIDES) and self._prev,
    2184            self._match_set(self.JOIN_KINDS) and self._prev,
    2185        )
    2186
    2187    def _parse_join(self, skip_join_token: bool = False) -> t.Optional[exp.Join]:
    2188        if self._match(TokenType.COMMA):
    2189            return self.expression(exp.Join, this=self._parse_table())
    2190
    2191        index = self._index
    2192        method, side, kind = self._parse_join_parts()
    2193        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    2194        join = self._match(TokenType.JOIN)
    2195
    2196        if not skip_join_token and not join:
    2197            self._retreat(index)
    2198            kind = None
    2199            method = None
    2200            side = None
    2201
    2202        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    2203        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    2204
    2205        if not skip_join_token and not join and not outer_apply and not cross_apply:
    2206            return None
    2207
    2208        if outer_apply:
    2209            side = Token(TokenType.LEFT, "LEFT")
    2210
    2211        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table()}
    2212
    2213        if method:
    2214            kwargs["method"] = method.text
    2215        if side:
    2216            kwargs["side"] = side.text
    2217        if kind:
    2218            kwargs["kind"] = kind.text
    2219        if hint:
    2220            kwargs["hint"] = hint
    2221
    2222        if self._match(TokenType.ON):
    2223            kwargs["on"] = self._parse_conjunction()
    2224        elif self._match(TokenType.USING):
    2225            kwargs["using"] = self._parse_wrapped_id_vars()
    2226
    2227        return self.expression(exp.Join, **kwargs)
    2228
    2229    def _parse_index(
    2230        self,
    2231        index: t.Optional[exp.Expression] = None,
    2232    ) -> t.Optional[exp.Index]:
    2233        if index:
    2234            unique = None
    2235            primary = None
    2236            amp = None
    2237
    2238            self._match(TokenType.ON)
    2239            self._match(TokenType.TABLE)  # hive
    2240            table = self._parse_table_parts(schema=True)
    2241        else:
    2242            unique = self._match(TokenType.UNIQUE)
    2243            primary = self._match_text_seq("PRIMARY")
    2244            amp = self._match_text_seq("AMP")
    2245
    2246            if not self._match(TokenType.INDEX):
    2247                return None
    2248
    2249            index = self._parse_id_var()
    2250            table = None
    2251
    2252        using = self._parse_field() if self._match(TokenType.USING) else None
    2253
    2254        if self._match(TokenType.L_PAREN, advance=False):
    2255            columns = self._parse_wrapped_csv(self._parse_ordered)
    2256        else:
    2257            columns = None
    2258
    2259        return self.expression(
    2260            exp.Index,
    2261            this=index,
    2262            table=table,
    2263            using=using,
    2264            columns=columns,
    2265            unique=unique,
    2266            primary=primary,
    2267            amp=amp,
    2268            partition_by=self._parse_partition_by(),
    2269        )
    2270
    2271    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    2272        return (
    2273            (not schema and self._parse_function(optional_parens=False))
    2274            or self._parse_id_var(any_token=False)
    2275            or self._parse_string_as_identifier()
    2276            or self._parse_placeholder()
    2277        )
    2278
    2279    def _parse_table_parts(self, schema: bool = False) -> exp.Table:
    2280        catalog = None
    2281        db = None
    2282        table = self._parse_table_part(schema=schema)
    2283
    2284        while self._match(TokenType.DOT):
    2285            if catalog:
    2286                # This allows nesting the table in arbitrarily many dot expressions if needed
    2287                table = self.expression(
    2288                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    2289                )
    2290            else:
    2291                catalog = db
    2292                db = table
    2293                table = self._parse_table_part(schema=schema)
    2294
    2295        if not table:
    2296            self.raise_error(f"Expected table name but got {self._curr}")
    2297
    2298        return self.expression(
    2299            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
    2300        )
    2301
    2302    def _parse_table(
    2303        self, schema: bool = False, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    2304    ) -> t.Optional[exp.Expression]:
    2305        lateral = self._parse_lateral()
    2306        if lateral:
    2307            return lateral
    2308
    2309        unnest = self._parse_unnest()
    2310        if unnest:
    2311            return unnest
    2312
    2313        values = self._parse_derived_table_values()
    2314        if values:
    2315            return values
    2316
    2317        subquery = self._parse_select(table=True)
    2318        if subquery:
    2319            if not subquery.args.get("pivots"):
    2320                subquery.set("pivots", self._parse_pivots())
    2321            return subquery
    2322
    2323        this: exp.Expression = self._parse_table_parts(schema=schema)
    2324
    2325        if schema:
    2326            return self._parse_schema(this=this)
    2327
    2328        if self.ALIAS_POST_TABLESAMPLE:
    2329            table_sample = self._parse_table_sample()
    2330
    2331        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    2332        if alias:
    2333            this.set("alias", alias)
    2334
    2335        if not this.args.get("pivots"):
    2336            this.set("pivots", self._parse_pivots())
    2337
    2338        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    2339            this.set(
    2340                "hints",
    2341                self._parse_csv(lambda: self._parse_function() or self._parse_var(any_token=True)),
    2342            )
    2343            self._match_r_paren()
    2344
    2345        if not self.ALIAS_POST_TABLESAMPLE:
    2346            table_sample = self._parse_table_sample()
    2347
    2348        if table_sample:
    2349            table_sample.set("this", this)
    2350            this = table_sample
    2351
    2352        return this
    2353
    2354    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    2355        if not self._match(TokenType.UNNEST):
    2356            return None
    2357
    2358        expressions = self._parse_wrapped_csv(self._parse_type)
    2359        ordinality = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    2360
    2361        alias = self._parse_table_alias() if with_alias else None
    2362
    2363        if alias and self.UNNEST_COLUMN_ONLY:
    2364            if alias.args.get("columns"):
    2365                self.raise_error("Unexpected extra column alias in unnest.")
    2366
    2367            alias.set("columns", [alias.this])
    2368            alias.set("this", None)
    2369
    2370        offset = None
    2371        if self._match_pair(TokenType.WITH, TokenType.OFFSET):
    2372            self._match(TokenType.ALIAS)
    2373            offset = self._parse_id_var() or exp.to_identifier("offset")
    2374
    2375        return self.expression(
    2376            exp.Unnest, expressions=expressions, ordinality=ordinality, alias=alias, offset=offset
    2377        )
    2378
    2379    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    2380        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    2381        if not is_derived and not self._match(TokenType.VALUES):
    2382            return None
    2383
    2384        expressions = self._parse_csv(self._parse_value)
    2385        alias = self._parse_table_alias()
    2386
    2387        if is_derived:
    2388            self._match_r_paren()
    2389
    2390        return self.expression(
    2391            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    2392        )
    2393
    2394    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    2395        if not self._match(TokenType.TABLE_SAMPLE) and not (
    2396            as_modifier and self._match_text_seq("USING", "SAMPLE")
    2397        ):
    2398            return None
    2399
    2400        bucket_numerator = None
    2401        bucket_denominator = None
    2402        bucket_field = None
    2403        percent = None
    2404        rows = None
    2405        size = None
    2406        seed = None
    2407
    2408        kind = (
    2409            self._prev.text if self._prev.token_type == TokenType.TABLE_SAMPLE else "USING SAMPLE"
    2410        )
    2411        method = self._parse_var(tokens=(TokenType.ROW,))
    2412
    2413        self._match(TokenType.L_PAREN)
    2414
    2415        num = self._parse_number()
    2416
    2417        if self._match_text_seq("BUCKET"):
    2418            bucket_numerator = self._parse_number()
    2419            self._match_text_seq("OUT", "OF")
    2420            bucket_denominator = bucket_denominator = self._parse_number()
    2421            self._match(TokenType.ON)
    2422            bucket_field = self._parse_field()
    2423        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    2424            percent = num
    2425        elif self._match(TokenType.ROWS):
    2426            rows = num
    2427        else:
    2428            size = num
    2429
    2430        self._match(TokenType.R_PAREN)
    2431
    2432        if self._match(TokenType.L_PAREN):
    2433            method = self._parse_var()
    2434            seed = self._match(TokenType.COMMA) and self._parse_number()
    2435            self._match_r_paren()
    2436        elif self._match_texts(("SEED", "REPEATABLE")):
    2437            seed = self._parse_wrapped(self._parse_number)
    2438
    2439        return self.expression(
    2440            exp.TableSample,
    2441            method=method,
    2442            bucket_numerator=bucket_numerator,
    2443            bucket_denominator=bucket_denominator,
    2444            bucket_field=bucket_field,
    2445            percent=percent,
    2446            rows=rows,
    2447            size=size,
    2448            seed=seed,
    2449            kind=kind,
    2450        )
    2451
    2452    def _parse_pivots(self) -> t.List[t.Optional[exp.Expression]]:
    2453        return list(iter(self._parse_pivot, None))
    2454
    2455    # https://duckdb.org/docs/sql/statements/pivot
    2456    def _parse_simplified_pivot(self) -> exp.Pivot:
    2457        def _parse_on() -> t.Optional[exp.Expression]:
    2458            this = self._parse_bitwise()
    2459            return self._parse_in(this) if self._match(TokenType.IN) else this
    2460
    2461        this = self._parse_table()
    2462        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    2463        using = self._match(TokenType.USING) and self._parse_csv(
    2464            lambda: self._parse_alias(self._parse_function())
    2465        )
    2466        group = self._parse_group()
    2467        return self.expression(
    2468            exp.Pivot, this=this, expressions=expressions, using=using, group=group
    2469        )
    2470
    2471    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    2472        index = self._index
    2473
    2474        if self._match(TokenType.PIVOT):
    2475            unpivot = False
    2476        elif self._match(TokenType.UNPIVOT):
    2477            unpivot = True
    2478        else:
    2479            return None
    2480
    2481        expressions = []
    2482        field = None
    2483
    2484        if not self._match(TokenType.L_PAREN):
    2485            self._retreat(index)
    2486            return None
    2487
    2488        if unpivot:
    2489            expressions = self._parse_csv(self._parse_column)
    2490        else:
    2491            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    2492
    2493        if not expressions:
    2494            self.raise_error("Failed to parse PIVOT's aggregation list")
    2495
    2496        if not self._match(TokenType.FOR):
    2497            self.raise_error("Expecting FOR")
    2498
    2499        value = self._parse_column()
    2500
    2501        if not self._match(TokenType.IN):
    2502            self.raise_error("Expecting IN")
    2503
    2504        field = self._parse_in(value, alias=True)
    2505
    2506        self._match_r_paren()
    2507
    2508        pivot = self.expression(exp.Pivot, expressions=expressions, field=field, unpivot=unpivot)
    2509
    2510        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    2511            pivot.set("alias", self._parse_table_alias())
    2512
    2513        if not unpivot:
    2514            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    2515
    2516            columns: t.List[exp.Expression] = []
    2517            for fld in pivot.args["field"].expressions:
    2518                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    2519                for name in names:
    2520                    if self.PREFIXED_PIVOT_COLUMNS:
    2521                        name = f"{name}_{field_name}" if name else field_name
    2522                    else:
    2523                        name = f"{field_name}_{name}" if name else field_name
    2524
    2525                    columns.append(exp.to_identifier(name))
    2526
    2527            pivot.set("columns", columns)
    2528
    2529        return pivot
    2530
    2531    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    2532        return [agg.alias for agg in aggregations]
    2533
    2534    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    2535        if not skip_where_token and not self._match(TokenType.WHERE):
    2536            return None
    2537
    2538        return self.expression(
    2539            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
    2540        )
    2541
    2542    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    2543        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    2544            return None
    2545
    2546        elements = defaultdict(list)
    2547
    2548        while True:
    2549            expressions = self._parse_csv(self._parse_conjunction)
    2550            if expressions:
    2551                elements["expressions"].extend(expressions)
    2552
    2553            grouping_sets = self._parse_grouping_sets()
    2554            if grouping_sets:
    2555                elements["grouping_sets"].extend(grouping_sets)
    2556
    2557            rollup = None
    2558            cube = None
    2559            totals = None
    2560
    2561            with_ = self._match(TokenType.WITH)
    2562            if self._match(TokenType.ROLLUP):
    2563                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
    2564                elements["rollup"].extend(ensure_list(rollup))
    2565
    2566            if self._match(TokenType.CUBE):
    2567                cube = with_ or self._parse_wrapped_csv(self._parse_column)
    2568                elements["cube"].extend(ensure_list(cube))
    2569
    2570            if self._match_text_seq("TOTALS"):
    2571                totals = True
    2572                elements["totals"] = True  # type: ignore
    2573
    2574            if not (grouping_sets or rollup or cube or totals):
    2575                break
    2576
    2577        return self.expression(exp.Group, **elements)  # type: ignore
    2578
    2579    def _parse_grouping_sets(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    2580        if not self._match(TokenType.GROUPING_SETS):
    2581            return None
    2582
    2583        return self._parse_wrapped_csv(self._parse_grouping_set)
    2584
    2585    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    2586        if self._match(TokenType.L_PAREN):
    2587            grouping_set = self._parse_csv(self._parse_column)
    2588            self._match_r_paren()
    2589            return self.expression(exp.Tuple, expressions=grouping_set)
    2590
    2591        return self._parse_column()
    2592
    2593    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    2594        if not skip_having_token and not self._match(TokenType.HAVING):
    2595            return None
    2596        return self.expression(exp.Having, this=self._parse_conjunction())
    2597
    2598    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    2599        if not self._match(TokenType.QUALIFY):
    2600            return None
    2601        return self.expression(exp.Qualify, this=self._parse_conjunction())
    2602
    2603    def _parse_order(
    2604        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    2605    ) -> t.Optional[exp.Expression]:
    2606        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    2607            return this
    2608
    2609        return self.expression(
    2610            exp.Order, this=this, expressions=self._parse_csv(self._parse_ordered)
    2611        )
    2612
    2613    def _parse_sort(self, exp_class: t.Type[E], *texts: str) -> t.Optional[E]:
    2614        if not self._match_text_seq(*texts):
    2615            return None
    2616        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    2617
    2618    def _parse_ordered(self) -> exp.Ordered:
    2619        this = self._parse_conjunction()
    2620        self._match(TokenType.ASC)
    2621
    2622        is_desc = self._match(TokenType.DESC)
    2623        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    2624        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    2625        desc = is_desc or False
    2626        asc = not desc
    2627        nulls_first = is_nulls_first or False
    2628        explicitly_null_ordered = is_nulls_first or is_nulls_last
    2629
    2630        if (
    2631            not explicitly_null_ordered
    2632            and (
    2633                (asc and self.NULL_ORDERING == "nulls_are_small")
    2634                or (desc and self.NULL_ORDERING != "nulls_are_small")
    2635            )
    2636            and self.NULL_ORDERING != "nulls_are_last"
    2637        ):
    2638            nulls_first = True
    2639
    2640        return self.expression(exp.Ordered, this=this, desc=desc, nulls_first=nulls_first)
    2641
    2642    def _parse_limit(
    2643        self, this: t.Optional[exp.Expression] = None, top: bool = False
    2644    ) -> t.Optional[exp.Expression]:
    2645        if self._match(TokenType.TOP if top else TokenType.LIMIT):
    2646            limit_paren = self._match(TokenType.L_PAREN)
    2647            expression = self._parse_number() if top else self._parse_term()
    2648
    2649            if self._match(TokenType.COMMA):
    2650                offset = expression
    2651                expression = self._parse_term()
    2652            else:
    2653                offset = None
    2654
    2655            limit_exp = self.expression(exp.Limit, this=this, expression=expression, offset=offset)
    2656
    2657            if limit_paren:
    2658                self._match_r_paren()
    2659
    2660            return limit_exp
    2661
    2662        if self._match(TokenType.FETCH):
    2663            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    2664            direction = self._prev.text if direction else "FIRST"
    2665
    2666            count = self._parse_number()
    2667            percent = self._match(TokenType.PERCENT)
    2668
    2669            self._match_set((TokenType.ROW, TokenType.ROWS))
    2670
    2671            only = self._match_text_seq("ONLY")
    2672            with_ties = self._match_text_seq("WITH", "TIES")
    2673
    2674            if only and with_ties:
    2675                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
    2676
    2677            return self.expression(
    2678                exp.Fetch,
    2679                direction=direction,
    2680                count=count,
    2681                percent=percent,
    2682                with_ties=with_ties,
    2683            )
    2684
    2685        return this
    2686
    2687    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    2688        if not self._match(TokenType.OFFSET):
    2689            return this
    2690
    2691        count = self._parse_number()
    2692        self._match_set((TokenType.ROW, TokenType.ROWS))
    2693        return self.expression(exp.Offset, this=this, expression=count)
    2694
    2695    def _parse_locks(self) -> t.List[exp.Lock]:
    2696        locks = []
    2697        while True:
    2698            if self._match_text_seq("FOR", "UPDATE"):
    2699                update = True
    2700            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    2701                "LOCK", "IN", "SHARE", "MODE"
    2702            ):
    2703                update = False
    2704            else:
    2705                break
    2706
    2707            expressions = None
    2708            if self._match_text_seq("OF"):
    2709                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    2710
    2711            wait: t.Optional[bool | exp.Expression] = None
    2712            if self._match_text_seq("NOWAIT"):
    2713                wait = True
    2714            elif self._match_text_seq("WAIT"):
    2715                wait = self._parse_primary()
    2716            elif self._match_text_seq("SKIP", "LOCKED"):
    2717                wait = False
    2718
    2719            locks.append(
    2720                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    2721            )
    2722
    2723        return locks
    2724
    2725    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2726        if not self._match_set(self.SET_OPERATIONS):
    2727            return this
    2728
    2729        token_type = self._prev.token_type
    2730
    2731        if token_type == TokenType.UNION:
    2732            expression = exp.Union
    2733        elif token_type == TokenType.EXCEPT:
    2734            expression = exp.Except
    2735        else:
    2736            expression = exp.Intersect
    2737
    2738        return self.expression(
    2739            expression,
    2740            this=this,
    2741            distinct=self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL),
    2742            expression=self._parse_set_operations(self._parse_select(nested=True)),
    2743        )
    2744
    2745    def _parse_expression(self) -> t.Optional[exp.Expression]:
    2746        return self._parse_alias(self._parse_conjunction())
    2747
    2748    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    2749        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    2750
    2751    def _parse_equality(self) -> t.Optional[exp.Expression]:
    2752        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    2753
    2754    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    2755        return self._parse_tokens(self._parse_range, self.COMPARISON)
    2756
    2757    def _parse_range(self) -> t.Optional[exp.Expression]:
    2758        this = self._parse_bitwise()
    2759        negate = self._match(TokenType.NOT)
    2760
    2761        if self._match_set(self.RANGE_PARSERS):
    2762            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    2763            if not expression:
    2764                return this
    2765
    2766            this = expression
    2767        elif self._match(TokenType.ISNULL):
    2768            this = self.expression(exp.Is, this=this, expression=exp.Null())
    2769
    2770        # Postgres supports ISNULL and NOTNULL for conditions.
    2771        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    2772        if self._match(TokenType.NOTNULL):
    2773            this = self.expression(exp.Is, this=this, expression=exp.Null())
    2774            this = self.expression(exp.Not, this=this)
    2775
    2776        if negate:
    2777            this = self.expression(exp.Not, this=this)
    2778
    2779        if self._match(TokenType.IS):
    2780            this = self._parse_is(this)
    2781
    2782        return this
    2783
    2784    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2785        index = self._index - 1
    2786        negate = self._match(TokenType.NOT)
    2787
    2788        if self._match_text_seq("DISTINCT", "FROM"):
    2789            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    2790            return self.expression(klass, this=this, expression=self._parse_expression())
    2791
    2792        expression = self._parse_null() or self._parse_boolean()
    2793        if not expression:
    2794            self._retreat(index)
    2795            return None
    2796
    2797        this = self.expression(exp.Is, this=this, expression=expression)
    2798        return self.expression(exp.Not, this=this) if negate else this
    2799
    2800    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    2801        unnest = self._parse_unnest(with_alias=False)
    2802        if unnest:
    2803            this = self.expression(exp.In, this=this, unnest=unnest)
    2804        elif self._match(TokenType.L_PAREN):
    2805            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    2806
    2807            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
    2808                this = self.expression(exp.In, this=this, query=expressions[0])
    2809            else:
    2810                this = self.expression(exp.In, this=this, expressions=expressions)
    2811
    2812            self._match_r_paren(this)
    2813        else:
    2814            this = self.expression(exp.In, this=this, field=self._parse_field())
    2815
    2816        return this
    2817
    2818    def _parse_between(self, this: exp.Expression) -> exp.Between:
    2819        low = self._parse_bitwise()
    2820        self._match(TokenType.AND)
    2821        high = self._parse_bitwise()
    2822        return self.expression(exp.Between, this=this, low=low, high=high)
    2823
    2824    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2825        if not self._match(TokenType.ESCAPE):
    2826            return this
    2827        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    2828
    2829    def _parse_interval(self) -> t.Optional[exp.Interval]:
    2830        if not self._match(TokenType.INTERVAL):
    2831            return None
    2832
    2833        this = self._parse_primary() or self._parse_term()
    2834        unit = self._parse_function() or self._parse_var()
    2835
    2836        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    2837        # each INTERVAL expression into this canonical form so it's easy to transpile
    2838        if this and this.is_number:
    2839            this = exp.Literal.string(this.name)
    2840        elif this and this.is_string:
    2841            parts = this.name.split()
    2842
    2843            if len(parts) == 2:
    2844                if unit:
    2845                    # this is not actually a unit, it's something else
    2846                    unit = None
    2847                    self._retreat(self._index - 1)
    2848                else:
    2849                    this = exp.Literal.string(parts[0])
    2850                    unit = self.expression(exp.Var, this=parts[1])
    2851
    2852        return self.expression(exp.Interval, this=this, unit=unit)
    2853
    2854    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    2855        this = self._parse_term()
    2856
    2857        while True:
    2858            if self._match_set(self.BITWISE):
    2859                this = self.expression(
    2860                    self.BITWISE[self._prev.token_type], this=this, expression=self._parse_term()
    2861                )
    2862            elif self._match_pair(TokenType.LT, TokenType.LT):
    2863                this = self.expression(
    2864                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    2865                )
    2866            elif self._match_pair(TokenType.GT, TokenType.GT):
    2867                this = self.expression(
    2868                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    2869                )
    2870            else:
    2871                break
    2872
    2873        return this
    2874
    2875    def _parse_term(self) -> t.Optional[exp.Expression]:
    2876        return self._parse_tokens(self._parse_factor, self.TERM)
    2877
    2878    def _parse_factor(self) -> t.Optional[exp.Expression]:
    2879        return self._parse_tokens(self._parse_unary, self.FACTOR)
    2880
    2881    def _parse_unary(self) -> t.Optional[exp.Expression]:
    2882        if self._match_set(self.UNARY_PARSERS):
    2883            return self.UNARY_PARSERS[self._prev.token_type](self)
    2884        return self._parse_at_time_zone(self._parse_type())
    2885
    2886    def _parse_type(self) -> t.Optional[exp.Expression]:
    2887        interval = self._parse_interval()
    2888        if interval:
    2889            return interval
    2890
    2891        index = self._index
    2892        data_type = self._parse_types(check_func=True)
    2893        this = self._parse_column()
    2894
    2895        if data_type:
    2896            if isinstance(this, exp.Literal):
    2897                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    2898                if parser:
    2899                    return parser(self, this, data_type)
    2900                return self.expression(exp.Cast, this=this, to=data_type)
    2901            if not data_type.expressions:
    2902                self._retreat(index)
    2903                return self._parse_column()
    2904            return self._parse_column_ops(data_type)
    2905
    2906        return this
    2907
    2908    def _parse_type_size(self) -> t.Optional[exp.DataTypeSize]:
    2909        this = self._parse_type()
    2910        if not this:
    2911            return None
    2912
    2913        return self.expression(
    2914            exp.DataTypeSize, this=this, expression=self._parse_var(any_token=True)
    2915        )
    2916
    2917    def _parse_types(
    2918        self, check_func: bool = False, schema: bool = False
    2919    ) -> t.Optional[exp.Expression]:
    2920        index = self._index
    2921
    2922        prefix = self._match_text_seq("SYSUDTLIB", ".")
    2923
    2924        if not self._match_set(self.TYPE_TOKENS):
    2925            return None
    2926
    2927        type_token = self._prev.token_type
    2928
    2929        if type_token == TokenType.PSEUDO_TYPE:
    2930            return self.expression(exp.PseudoType, this=self._prev.text)
    2931
    2932        nested = type_token in self.NESTED_TYPE_TOKENS
    2933        is_struct = type_token == TokenType.STRUCT
    2934        expressions = None
    2935        maybe_func = False
    2936
    2937        if self._match(TokenType.L_PAREN):
    2938            if is_struct:
    2939                expressions = self._parse_csv(self._parse_struct_types)
    2940            elif nested:
    2941                expressions = self._parse_csv(
    2942                    lambda: self._parse_types(check_func=check_func, schema=schema)
    2943                )
    2944            elif type_token in self.ENUM_TYPE_TOKENS:
    2945                expressions = self._parse_csv(self._parse_primary)
    2946            else:
    2947                expressions = self._parse_csv(self._parse_type_size)
    2948
    2949            if not expressions or not self._match(TokenType.R_PAREN):
    2950                self._retreat(index)
    2951                return None
    2952
    2953            maybe_func = True
    2954
    2955        if self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
    2956            this = exp.DataType(
    2957                this=exp.DataType.Type.ARRAY,
    2958                expressions=[exp.DataType.build(type_token.value, expressions=expressions)],
    2959                nested=True,
    2960            )
    2961
    2962            while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
    2963                this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
    2964
    2965            return this
    2966
    2967        if self._match(TokenType.L_BRACKET):
    2968            self._retreat(index)
    2969            return None
    2970
    2971        values: t.Optional[t.List[t.Optional[exp.Expression]]] = None
    2972        if nested and self._match(TokenType.LT):
    2973            if is_struct:
    2974                expressions = self._parse_csv(self._parse_struct_types)
    2975            else:
    2976                expressions = self._parse_csv(
    2977                    lambda: self._parse_types(check_func=check_func, schema=schema)
    2978                )
    2979
    2980            if not self._match(TokenType.GT):
    2981                self.raise_error("Expecting >")
    2982
    2983            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    2984                values = self._parse_csv(self._parse_conjunction)
    2985                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    2986
    2987        value: t.Optional[exp.Expression] = None
    2988        if type_token in self.TIMESTAMPS:
    2989            if self._match_text_seq("WITH", "TIME", "ZONE"):
    2990                maybe_func = False
    2991                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPTZ, expressions=expressions)
    2992            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    2993                maybe_func = False
    2994                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    2995            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    2996                maybe_func = False
    2997        elif type_token == TokenType.INTERVAL:
    2998            unit = self._parse_var()
    2999
    3000            if not unit:
    3001                value = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    3002            else:
    3003                value = self.expression(exp.Interval, unit=unit)
    3004
    3005        if maybe_func and check_func:
    3006            index2 = self._index
    3007            peek = self._parse_string()
    3008
    3009            if not peek:
    3010                self._retreat(index)
    3011                return None
    3012
    3013            self._retreat(index2)
    3014
    3015        if value:
    3016            return value
    3017
    3018        return exp.DataType(
    3019            this=exp.DataType.Type[type_token.value.upper()],
    3020            expressions=expressions,
    3021            nested=nested,
    3022            values=values,
    3023            prefix=prefix,
    3024        )
    3025
    3026    def _parse_struct_types(self) -> t.Optional[exp.Expression]:
    3027        this = self._parse_type() or self._parse_id_var()
    3028        self._match(TokenType.COLON)
    3029        return self._parse_column_def(this)
    3030
    3031    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3032        if not self._match_text_seq("AT", "TIME", "ZONE"):
    3033            return this
    3034        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    3035
    3036    def _parse_column(self) -> t.Optional[exp.Expression]:
    3037        this = self._parse_field()
    3038        if isinstance(this, exp.Identifier):
    3039            this = self.expression(exp.Column, this=this)
    3040        elif not this:
    3041            return self._parse_bracket(this)
    3042        return self._parse_column_ops(this)
    3043
    3044    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3045        this = self._parse_bracket(this)
    3046
    3047        while self._match_set(self.COLUMN_OPERATORS):
    3048            op_token = self._prev.token_type
    3049            op = self.COLUMN_OPERATORS.get(op_token)
    3050
    3051            if op_token == TokenType.DCOLON:
    3052                field = self._parse_types()
    3053                if not field:
    3054                    self.raise_error("Expected type")
    3055            elif op and self._curr:
    3056                self._advance()
    3057                value = self._prev.text
    3058                field = (
    3059                    exp.Literal.number(value)
    3060                    if self._prev.token_type == TokenType.NUMBER
    3061                    else exp.Literal.string(value)
    3062                )
    3063            else:
    3064                field = self._parse_field(anonymous_func=True, any_token=True)
    3065
    3066            if isinstance(field, exp.Func):
    3067                # bigquery allows function calls like x.y.count(...)
    3068                # SAFE.SUBSTR(...)
    3069                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    3070                this = self._replace_columns_with_dots(this)
    3071
    3072            if op:
    3073                this = op(self, this, field)
    3074            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    3075                this = self.expression(
    3076                    exp.Column,
    3077                    this=field,
    3078                    table=this.this,
    3079                    db=this.args.get("table"),
    3080                    catalog=this.args.get("db"),
    3081                )
    3082            else:
    3083                this = self.expression(exp.Dot, this=this, expression=field)
    3084            this = self._parse_bracket(this)
    3085        return this
    3086
    3087    def _parse_primary(self) -> t.Optional[exp.Expression]:
    3088        if self._match_set(self.PRIMARY_PARSERS):
    3089            token_type = self._prev.token_type
    3090            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    3091
    3092            if token_type == TokenType.STRING:
    3093                expressions = [primary]
    3094                while self._match(TokenType.STRING):
    3095                    expressions.append(exp.Literal.string(self._prev.text))
    3096
    3097                if len(expressions) > 1:
    3098                    return self.expression(exp.Concat, expressions=expressions)
    3099
    3100            return primary
    3101
    3102        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    3103            return exp.Literal.number(f"0.{self._prev.text}")
    3104
    3105        if self._match(TokenType.L_PAREN):
    3106            comments = self._prev_comments
    3107            query = self._parse_select()
    3108
    3109            if query:
    3110                expressions = [query]
    3111            else:
    3112                expressions = self._parse_csv(self._parse_expression)
    3113
    3114            this = self._parse_query_modifiers(seq_get(expressions, 0))
    3115
    3116            if isinstance(this, exp.Subqueryable):
    3117                this = self._parse_set_operations(
    3118                    self._parse_subquery(this=this, parse_alias=False)
    3119                )
    3120            elif len(expressions) > 1:
    3121                this = self.expression(exp.Tuple, expressions=expressions)
    3122            else:
    3123                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
    3124
    3125            if this:
    3126                this.add_comments(comments)
    3127
    3128            self._match_r_paren(expression=this)
    3129            return this
    3130
    3131        return None
    3132
    3133    def _parse_field(
    3134        self,
    3135        any_token: bool = False,
    3136        tokens: t.Optional[t.Collection[TokenType]] = None,
    3137        anonymous_func: bool = False,
    3138    ) -> t.Optional[exp.Expression]:
    3139        return (
    3140            self._parse_primary()
    3141            or self._parse_function(anonymous=anonymous_func)
    3142            or self._parse_id_var(any_token=any_token, tokens=tokens)
    3143        )
    3144
    3145    def _parse_function(
    3146        self,
    3147        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    3148        anonymous: bool = False,
    3149        optional_parens: bool = True,
    3150    ) -> t.Optional[exp.Expression]:
    3151        if not self._curr:
    3152            return None
    3153
    3154        token_type = self._curr.token_type
    3155
    3156        if optional_parens and self._match_set(self.NO_PAREN_FUNCTION_PARSERS):
    3157            return self.NO_PAREN_FUNCTION_PARSERS[token_type](self)
    3158
    3159        if not self._next or self._next.token_type != TokenType.L_PAREN:
    3160            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    3161                self._advance()
    3162                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    3163
    3164            return None
    3165
    3166        if token_type not in self.FUNC_TOKENS:
    3167            return None
    3168
    3169        this = self._curr.text
    3170        upper = this.upper()
    3171        self._advance(2)
    3172
    3173        parser = self.FUNCTION_PARSERS.get(upper)
    3174
    3175        if parser and not anonymous:
    3176            this = parser(self)
    3177        else:
    3178            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    3179
    3180            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    3181                this = self.expression(subquery_predicate, this=self._parse_select())
    3182                self._match_r_paren()
    3183                return this
    3184
    3185            if functions is None:
    3186                functions = self.FUNCTIONS
    3187
    3188            function = functions.get(upper)
    3189
    3190            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    3191            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    3192
    3193            if function and not anonymous:
    3194                this = self.validate_expression(function(args), args)
    3195            else:
    3196                this = self.expression(exp.Anonymous, this=this, expressions=args)
    3197
    3198        self._match_r_paren(this)
    3199        return self._parse_window(this)
    3200
    3201    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    3202        return self._parse_column_def(self._parse_id_var())
    3203
    3204    def _parse_user_defined_function(
    3205        self, kind: t.Optional[TokenType] = None
    3206    ) -> t.Optional[exp.Expression]:
    3207        this = self._parse_id_var()
    3208
    3209        while self._match(TokenType.DOT):
    3210            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    3211
    3212        if not self._match(TokenType.L_PAREN):
    3213            return this
    3214
    3215        expressions = self._parse_csv(self._parse_function_parameter)
    3216        self._match_r_paren()
    3217        return self.expression(
    3218            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    3219        )
    3220
    3221    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    3222        literal = self._parse_primary()
    3223        if literal:
    3224            return self.expression(exp.Introducer, this=token.text, expression=literal)
    3225
    3226        return self.expression(exp.Identifier, this=token.text)
    3227
    3228    def _parse_session_parameter(self) -> exp.SessionParameter:
    3229        kind = None
    3230        this = self._parse_id_var() or self._parse_primary()
    3231
    3232        if this and self._match(TokenType.DOT):
    3233            kind = this.name
    3234            this = self._parse_var() or self._parse_primary()
    3235
    3236        return self.expression(exp.SessionParameter, this=this, kind=kind)
    3237
    3238    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    3239        index = self._index
    3240
    3241        if self._match(TokenType.L_PAREN):
    3242            expressions = self._parse_csv(self._parse_id_var)
    3243
    3244            if not self._match(TokenType.R_PAREN):
    3245                self._retreat(index)
    3246        else:
    3247            expressions = [self._parse_id_var()]
    3248
    3249        if self._match_set(self.LAMBDAS):
    3250            return self.LAMBDAS[self._prev.token_type](self, expressions)
    3251
    3252        self._retreat(index)
    3253
    3254        this: t.Optional[exp.Expression]
    3255
    3256        if self._match(TokenType.DISTINCT):
    3257            this = self.expression(
    3258                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
    3259            )
    3260        else:
    3261            this = self._parse_select_or_expression(alias=alias)
    3262
    3263            if isinstance(this, exp.EQ):
    3264                left = this.this
    3265                if isinstance(left, exp.Column):
    3266                    left.replace(exp.var(left.text("this")))
    3267
    3268        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
    3269
    3270    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    3271        index = self._index
    3272
    3273        if not self.errors:
    3274            try:
    3275                if self._parse_select(nested=True):
    3276                    return this
    3277            except ParseError:
    3278                pass
    3279            finally:
    3280                self.errors.clear()
    3281                self._retreat(index)
    3282
    3283        if not self._match(TokenType.L_PAREN):
    3284            return this
    3285
    3286        args = self._parse_csv(
    3287            lambda: self._parse_constraint()
    3288            or self._parse_column_def(self._parse_field(any_token=True))
    3289        )
    3290
    3291        self._match_r_paren()
    3292        return self.expression(exp.Schema, this=this, expressions=args)
    3293
    3294    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3295        # column defs are not really columns, they're identifiers
    3296        if isinstance(this, exp.Column):
    3297            this = this.this
    3298
    3299        kind = self._parse_types(schema=True)
    3300
    3301        if self._match_text_seq("FOR", "ORDINALITY"):
    3302            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    3303
    3304        constraints = []
    3305        while True:
    3306            constraint = self._parse_column_constraint()
    3307            if not constraint:
    3308                break
    3309            constraints.append(constraint)
    3310
    3311        if not kind and not constraints:
    3312            return this
    3313
    3314        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    3315
    3316    def _parse_auto_increment(
    3317        self,
    3318    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    3319        start = None
    3320        increment = None
    3321
    3322        if self._match(TokenType.L_PAREN, advance=False):
    3323            args = self._parse_wrapped_csv(self._parse_bitwise)
    3324            start = seq_get(args, 0)
    3325            increment = seq_get(args, 1)
    3326        elif self._match_text_seq("START"):
    3327            start = self._parse_bitwise()
    3328            self._match_text_seq("INCREMENT")
    3329            increment = self._parse_bitwise()
    3330
    3331        if start and increment:
    3332            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    3333
    3334        return exp.AutoIncrementColumnConstraint()
    3335
    3336    def _parse_compress(self) -> exp.CompressColumnConstraint:
    3337        if self._match(TokenType.L_PAREN, advance=False):
    3338            return self.expression(
    3339                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    3340            )
    3341
    3342        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    3343
    3344    def _parse_generated_as_identity(self) -> exp.GeneratedAsIdentityColumnConstraint:
    3345        if self._match_text_seq("BY", "DEFAULT"):
    3346            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    3347            this = self.expression(
    3348                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    3349            )
    3350        else:
    3351            self._match_text_seq("ALWAYS")
    3352            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    3353
    3354        self._match(TokenType.ALIAS)
    3355        identity = self._match_text_seq("IDENTITY")
    3356
    3357        if self._match(TokenType.L_PAREN):
    3358            if self._match_text_seq("START", "WITH"):
    3359                this.set("start", self._parse_bitwise())
    3360            if self._match_text_seq("INCREMENT", "BY"):
    3361                this.set("increment", self._parse_bitwise())
    3362            if self._match_text_seq("MINVALUE"):
    3363                this.set("minvalue", self._parse_bitwise())
    3364            if self._match_text_seq("MAXVALUE"):
    3365                this.set("maxvalue", self._parse_bitwise())
    3366
    3367            if self._match_text_seq("CYCLE"):
    3368                this.set("cycle", True)
    3369            elif self._match_text_seq("NO", "CYCLE"):
    3370                this.set("cycle", False)
    3371
    3372            if not identity:
    3373                this.set("expression", self._parse_bitwise())
    3374
    3375            self._match_r_paren()
    3376
    3377        return this
    3378
    3379    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    3380        self._match_text_seq("LENGTH")
    3381        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    3382
    3383    def _parse_not_constraint(
    3384        self,
    3385    ) -> t.Optional[exp.NotNullColumnConstraint | exp.CaseSpecificColumnConstraint]:
    3386        if self._match_text_seq("NULL"):
    3387            return self.expression(exp.NotNullColumnConstraint)
    3388        if self._match_text_seq("CASESPECIFIC"):
    3389            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    3390        return None
    3391
    3392    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    3393        if self._match(TokenType.CONSTRAINT):
    3394            this = self._parse_id_var()
    3395        else:
    3396            this = None
    3397
    3398        if self._match_texts(self.CONSTRAINT_PARSERS):
    3399            return self.expression(
    3400                exp.ColumnConstraint,
    3401                this=this,
    3402                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    3403            )
    3404
    3405        return this
    3406
    3407    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    3408        if not self._match(TokenType.CONSTRAINT):
    3409            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    3410
    3411        this = self._parse_id_var()
    3412        expressions = []
    3413
    3414        while True:
    3415            constraint = self._parse_unnamed_constraint() or self._parse_function()
    3416            if not constraint:
    3417                break
    3418            expressions.append(constraint)
    3419
    3420        return self.expression(exp.Constraint, this=this, expressions=expressions)
    3421
    3422    def _parse_unnamed_constraint(
    3423        self, constraints: t.Optional[t.Collection[str]] = None
    3424    ) -> t.Optional[exp.Expression]:
    3425        if not self._match_texts(constraints or self.CONSTRAINT_PARSERS):
    3426            return None
    3427
    3428        constraint = self._prev.text.upper()
    3429        if constraint not in self.CONSTRAINT_PARSERS:
    3430            self.raise_error(f"No parser found for schema constraint {constraint}.")
    3431
    3432        return self.CONSTRAINT_PARSERS[constraint](self)
    3433
    3434    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    3435        self._match_text_seq("KEY")
    3436        return self.expression(
    3437            exp.UniqueColumnConstraint, this=self._parse_schema(self._parse_id_var(any_token=False))
    3438        )
    3439
    3440    def _parse_key_constraint_options(self) -> t.List[str]:
    3441        options = []
    3442        while True:
    3443            if not self._curr:
    3444                break
    3445
    3446            if self._match(TokenType.ON):
    3447                action = None
    3448                on = self._advance_any() and self._prev.text
    3449
    3450                if self._match_text_seq("NO", "ACTION"):
    3451                    action = "NO ACTION"
    3452                elif self._match_text_seq("CASCADE"):
    3453                    action = "CASCADE"
    3454                elif self._match_pair(TokenType.SET, TokenType.NULL):
    3455                    action = "SET NULL"
    3456                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    3457                    action = "SET DEFAULT"
    3458                else:
    3459                    self.raise_error("Invalid key constraint")
    3460
    3461                options.append(f"ON {on} {action}")
    3462            elif self._match_text_seq("NOT", "ENFORCED"):
    3463                options.append("NOT ENFORCED")
    3464            elif self._match_text_seq("DEFERRABLE"):
    3465                options.append("DEFERRABLE")
    3466            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    3467                options.append("INITIALLY DEFERRED")
    3468            elif self._match_text_seq("NORELY"):
    3469                options.append("NORELY")
    3470            elif self._match_text_seq("MATCH", "FULL"):
    3471                options.append("MATCH FULL")
    3472            else:
    3473                break
    3474
    3475        return options
    3476
    3477    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    3478        if match and not self._match(TokenType.REFERENCES):
    3479            return None
    3480
    3481        expressions = None
    3482        this = self._parse_id_var()
    3483
    3484        if self._match(TokenType.L_PAREN, advance=False):
    3485            expressions = self._parse_wrapped_id_vars()
    3486
    3487        options = self._parse_key_constraint_options()
    3488        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    3489
    3490    def _parse_foreign_key(self) -> exp.ForeignKey:
    3491        expressions = self._parse_wrapped_id_vars()
    3492        reference = self._parse_references()
    3493        options = {}
    3494
    3495        while self._match(TokenType.ON):
    3496            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    3497                self.raise_error("Expected DELETE or UPDATE")
    3498
    3499            kind = self._prev.text.lower()
    3500
    3501            if self._match_text_seq("NO", "ACTION"):
    3502                action = "NO ACTION"
    3503            elif self._match(TokenType.SET):
    3504                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    3505                action = "SET " + self._prev.text.upper()
    3506            else:
    3507                self._advance()
    3508                action = self._prev.text.upper()
    3509
    3510            options[kind] = action
    3511
    3512        return self.expression(
    3513            exp.ForeignKey, expressions=expressions, reference=reference, **options  # type: ignore
    3514        )
    3515
    3516    def _parse_primary_key(
    3517        self, wrapped_optional: bool = False, in_props: bool = False
    3518    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    3519        desc = (
    3520            self._match_set((TokenType.ASC, TokenType.DESC))
    3521            and self._prev.token_type == TokenType.DESC
    3522        )
    3523
    3524        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    3525            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    3526
    3527        expressions = self._parse_wrapped_csv(self._parse_field, optional=wrapped_optional)
    3528        options = self._parse_key_constraint_options()
    3529        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    3530
    3531    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3532        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    3533            return this
    3534
    3535        bracket_kind = self._prev.token_type
    3536
    3537        if self._match(TokenType.COLON):
    3538            expressions: t.List[t.Optional[exp.Expression]] = [
    3539                self.expression(exp.Slice, expression=self._parse_conjunction())
    3540            ]
    3541        else:
    3542            expressions = self._parse_csv(lambda: self._parse_slice(self._parse_conjunction()))
    3543
    3544        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    3545        if bracket_kind == TokenType.L_BRACE:
    3546            this = self.expression(exp.Struct, expressions=expressions)
    3547        elif not this or this.name.upper() == "ARRAY":
    3548            this = self.expression(exp.Array, expressions=expressions)
    3549        else:
    3550            expressions = apply_index_offset(this, expressions, -self.INDEX_OFFSET)
    3551            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    3552
    3553        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
    3554            self.raise_error("Expected ]")
    3555        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
    3556            self.raise_error("Expected }")
    3557
    3558        self._add_comments(this)
    3559        return self._parse_bracket(this)
    3560
    3561    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3562        if self._match(TokenType.COLON):
    3563            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
    3564        return this
    3565
    3566    def _parse_case(self) -> t.Optional[exp.Expression]:
    3567        ifs = []
    3568        default = None
    3569
    3570        expression = self._parse_conjunction()
    3571
    3572        while self._match(TokenType.WHEN):
    3573            this = self._parse_conjunction()
    3574            self._match(TokenType.THEN)
    3575            then = self._parse_conjunction()
    3576            ifs.append(self.expression(exp.If, this=this, true=then))
    3577
    3578        if self._match(TokenType.ELSE):
    3579            default = self._parse_conjunction()
    3580
    3581        if not self._match(TokenType.END):
    3582            self.raise_error("Expected END after CASE", self._prev)
    3583
    3584        return self._parse_window(
    3585            self.expression(exp.Case, this=expression, ifs=ifs, default=default)
    3586        )
    3587
    3588    def _parse_if(self) -> t.Optional[exp.Expression]:
    3589        if self._match(TokenType.L_PAREN):
    3590            args = self._parse_csv(self._parse_conjunction)
    3591            this = self.validate_expression(exp.If.from_arg_list(args), args)
    3592            self._match_r_paren()
    3593        else:
    3594            index = self._index - 1
    3595            condition = self._parse_conjunction()
    3596
    3597            if not condition:
    3598                self._retreat(index)
    3599                return None
    3600
    3601            self._match(TokenType.THEN)
    3602            true = self._parse_conjunction()
    3603            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
    3604            self._match(TokenType.END)
    3605            this = self.expression(exp.If, this=condition, true=true, false=false)
    3606
    3607        return self._parse_window(this)
    3608
    3609    def _parse_extract(self) -> exp.Extract:
    3610        this = self._parse_function() or self._parse_var() or self._parse_type()
    3611
    3612        if self._match(TokenType.FROM):
    3613            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    3614
    3615        if not self._match(TokenType.COMMA):
    3616            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    3617
    3618        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    3619
    3620    def _parse_cast(self, strict: bool) -> exp.Expression:
    3621        this = self._parse_conjunction()
    3622
    3623        if not self._match(TokenType.ALIAS):
    3624            if self._match(TokenType.COMMA):
    3625                return self.expression(
    3626                    exp.CastToStrType, this=this, expression=self._parse_string()
    3627                )
    3628            else:
    3629                self.raise_error("Expected AS after CAST")
    3630
    3631        to = self._parse_types()
    3632
    3633        if not to:
    3634            self.raise_error("Expected TYPE after CAST")
    3635        elif to.this == exp.DataType.Type.CHAR:
    3636            if self._match(TokenType.CHARACTER_SET):
    3637                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    3638        elif to.this in exp.DataType.TEMPORAL_TYPES and self._match(TokenType.FORMAT):
    3639            fmt = self._parse_string()
    3640
    3641            return self.expression(
    3642                exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    3643                this=this,
    3644                format=exp.Literal.string(
    3645                    format_time(
    3646                        fmt.this if fmt else "",
    3647                        self.FORMAT_MAPPING or self.TIME_MAPPING,
    3648                        self.FORMAT_TRIE or self.TIME_TRIE,
    3649                    )
    3650                ),
    3651            )
    3652
    3653        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
    3654
    3655    def _parse_concat(self) -> t.Optional[exp.Expression]:
    3656        args = self._parse_csv(self._parse_conjunction)
    3657        if self.CONCAT_NULL_OUTPUTS_STRING:
    3658            args = [exp.func("COALESCE", arg, exp.Literal.string("")) for arg in args]
    3659
    3660        # Some dialects (e.g. Trino) don't allow a single-argument CONCAT call, so when
    3661        # we find such a call we replace it with its argument.
    3662        if len(args) == 1:
    3663            return args[0]
    3664
    3665        return self.expression(
    3666            exp.Concat if self.STRICT_STRING_CONCAT else exp.SafeConcat, expressions=args
    3667        )
    3668
    3669    def _parse_string_agg(self) -> exp.Expression:
    3670        expression: t.Optional[exp.Expression]
    3671
    3672        if self._match(TokenType.DISTINCT):
    3673            args = self._parse_csv(self._parse_conjunction)
    3674            expression = self.expression(exp.Distinct, expressions=[seq_get(args, 0)])
    3675        else:
    3676            args = self._parse_csv(self._parse_conjunction)
    3677            expression = seq_get(args, 0)
    3678
    3679        index = self._index
    3680        if not self._match(TokenType.R_PAREN):
    3681            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    3682            order = self._parse_order(this=expression)
    3683            return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    3684
    3685        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    3686        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    3687        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    3688        if not self._match_text_seq("WITHIN", "GROUP"):
    3689            self._retreat(index)
    3690            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    3691
    3692        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    3693        order = self._parse_order(this=expression)
    3694        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    3695
    3696    def _parse_convert(self, strict: bool) -> t.Optional[exp.Expression]:
    3697        to: t.Optional[exp.Expression]
    3698        this = self._parse_bitwise()
    3699
    3700        if self._match(TokenType.USING):
    3701            to = self.expression(exp.CharacterSet, this=self._parse_var())
    3702        elif self._match(TokenType.COMMA):
    3703            to = self._parse_bitwise()
    3704        else:
    3705            to = None
    3706
    3707        # Swap the argument order if needed to produce the correct AST
    3708        if self.CONVERT_TYPE_FIRST:
    3709            this, to = to, this
    3710
    3711        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
    3712
    3713    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    3714        """
    3715        There are generally two variants of the DECODE function:
    3716
    3717        - DECODE(bin, charset)
    3718        - DECODE(expression, search, result [, search, result] ... [, default])
    3719
    3720        The second variant will always be parsed into a CASE expression. Note that NULL
    3721        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    3722        instead of relying on pattern matching.
    3723        """
    3724        args = self._parse_csv(self._parse_conjunction)
    3725
    3726        if len(args) < 3:
    3727            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    3728
    3729        expression, *expressions = args
    3730        if not expression:
    3731            return None
    3732
    3733        ifs = []
    3734        for search, result in zip(expressions[::2], expressions[1::2]):
    3735            if not search or not result:
    3736                return None
    3737
    3738            if isinstance(search, exp.Literal):
    3739                ifs.append(
    3740                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    3741                )
    3742            elif isinstance(search, exp.Null):
    3743                ifs.append(
    3744                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    3745                )
    3746            else:
    3747                cond = exp.or_(
    3748                    exp.EQ(this=expression.copy(), expression=search),
    3749                    exp.and_(
    3750                        exp.Is(this=expression.copy(), expression=exp.Null()),
    3751                        exp.Is(this=search.copy(), expression=exp.Null()),
    3752                        copy=False,
    3753                    ),
    3754                    copy=False,
    3755                )
    3756                ifs.append(exp.If(this=cond, true=result))
    3757
    3758        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    3759
    3760    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    3761        self._match_text_seq("KEY")
    3762        key = self._parse_field()
    3763        self._match(TokenType.COLON)
    3764        self._match_text_seq("VALUE")
    3765        value = self._parse_field()
    3766
    3767        if not key and not value:
    3768            return None
    3769        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    3770
    3771    def _parse_json_object(self) -> exp.JSONObject:
    3772        star = self._parse_star()
    3773        expressions = [star] if star else self._parse_csv(self._parse_json_key_value)
    3774
    3775        null_handling = None
    3776        if self._match_text_seq("NULL", "ON", "NULL"):
    3777            null_handling = "NULL ON NULL"
    3778        elif self._match_text_seq("ABSENT", "ON", "NULL"):
    3779            null_handling = "ABSENT ON NULL"
    3780
    3781        unique_keys = None
    3782        if self._match_text_seq("WITH", "UNIQUE"):
    3783            unique_keys = True
    3784        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    3785            unique_keys = False
    3786
    3787        self._match_text_seq("KEYS")
    3788
    3789        return_type = self._match_text_seq("RETURNING") and self._parse_type()
    3790        format_json = self._match_text_seq("FORMAT", "JSON")
    3791        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    3792
    3793        return self.expression(
    3794            exp.JSONObject,
    3795            expressions=expressions,
    3796            null_handling=null_handling,
    3797            unique_keys=unique_keys,
    3798            return_type=return_type,
    3799            format_json=format_json,
    3800            encoding=encoding,
    3801        )
    3802
    3803    def _parse_logarithm(self) -> exp.Func:
    3804        # Default argument order is base, expression
    3805        args = self._parse_csv(self._parse_range)
    3806
    3807        if len(args) > 1:
    3808            if not self.LOG_BASE_FIRST:
    3809                args.reverse()
    3810            return exp.Log.from_arg_list(args)
    3811
    3812        return self.expression(
    3813            exp.Ln if self.LOG_DEFAULTS_TO_LN else exp.Log, this=seq_get(args, 0)
    3814        )
    3815
    3816    def _parse_match_against(self) -> exp.MatchAgainst:
    3817        expressions = self._parse_csv(self._parse_column)
    3818
    3819        self._match_text_seq(")", "AGAINST", "(")
    3820
    3821        this = self._parse_string()
    3822
    3823        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    3824            modifier = "IN NATURAL LANGUAGE MODE"
    3825            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    3826                modifier = f"{modifier} WITH QUERY EXPANSION"
    3827        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    3828            modifier = "IN BOOLEAN MODE"
    3829        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    3830            modifier = "WITH QUERY EXPANSION"
    3831        else:
    3832            modifier = None
    3833
    3834        return self.expression(
    3835            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    3836        )
    3837
    3838    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    3839    def _parse_open_json(self) -> exp.OpenJSON:
    3840        this = self._parse_bitwise()
    3841        path = self._match(TokenType.COMMA) and self._parse_string()
    3842
    3843        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    3844            this = self._parse_field(any_token=True)
    3845            kind = self._parse_types()
    3846            path = self._parse_string()
    3847            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    3848
    3849            return self.expression(
    3850                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    3851            )
    3852
    3853        expressions = None
    3854        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    3855            self._match_l_paren()
    3856            expressions = self._parse_csv(_parse_open_json_column_def)
    3857
    3858        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    3859
    3860    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    3861        args = self._parse_csv(self._parse_bitwise)
    3862
    3863        if self._match(TokenType.IN):
    3864            return self.expression(
    3865                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    3866            )
    3867
    3868        if haystack_first:
    3869            haystack = seq_get(args, 0)
    3870            needle = seq_get(args, 1)
    3871        else:
    3872            needle = seq_get(args, 0)
    3873            haystack = seq_get(args, 1)
    3874
    3875        return self.expression(
    3876            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    3877        )
    3878
    3879    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    3880        args = self._parse_csv(self._parse_table)
    3881        return exp.JoinHint(this=func_name.upper(), expressions=args)
    3882
    3883    def _parse_substring(self) -> exp.Substring:
    3884        # Postgres supports the form: substring(string [from int] [for int])
    3885        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    3886
    3887        args = self._parse_csv(self._parse_bitwise)
    3888
    3889        if self._match(TokenType.FROM):
    3890            args.append(self._parse_bitwise())
    3891            if self._match(TokenType.FOR):
    3892                args.append(self._parse_bitwise())
    3893
    3894        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    3895
    3896    def _parse_trim(self) -> exp.Trim:
    3897        # https://www.w3resource.com/sql/character-functions/trim.php
    3898        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    3899
    3900        position = None
    3901        collation = None
    3902
    3903        if self._match_texts(self.TRIM_TYPES):
    3904            position = self._prev.text.upper()
    3905
    3906        expression = self._parse_bitwise()
    3907        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    3908            this = self._parse_bitwise()
    3909        else:
    3910            this = expression
    3911            expression = None
    3912
    3913        if self._match(TokenType.COLLATE):
    3914            collation = self._parse_bitwise()
    3915
    3916        return self.expression(
    3917            exp.Trim, this=this, position=position, expression=expression, collation=collation
    3918        )
    3919
    3920    def _parse_window_clause(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    3921        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    3922
    3923    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    3924        return self._parse_window(self._parse_id_var(), alias=True)
    3925
    3926    def _parse_respect_or_ignore_nulls(
    3927        self, this: t.Optional[exp.Expression]
    3928    ) -> t.Optional[exp.Expression]:
    3929        if self._match_text_seq("IGNORE", "NULLS"):
    3930            return self.expression(exp.IgnoreNulls, this=this)
    3931        if self._match_text_seq("RESPECT", "NULLS"):
    3932            return self.expression(exp.RespectNulls, this=this)
    3933        return this
    3934
    3935    def _parse_window(
    3936        self, this: t.Optional[exp.Expression], alias: bool = False
    3937    ) -> t.Optional[exp.Expression]:
    3938        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    3939            this = self.expression(exp.Filter, this=this, expression=self._parse_where())
    3940            self._match_r_paren()
    3941
    3942        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    3943        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    3944        if self._match_text_seq("WITHIN", "GROUP"):
    3945            order = self._parse_wrapped(self._parse_order)
    3946            this = self.expression(exp.WithinGroup, this=this, expression=order)
    3947
    3948        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    3949        # Some dialects choose to implement and some do not.
    3950        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    3951
    3952        # There is some code above in _parse_lambda that handles
    3953        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    3954
    3955        # The below changes handle
    3956        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    3957
    3958        # Oracle allows both formats
    3959        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    3960        #   and Snowflake chose to do the same for familiarity
    3961        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    3962        this = self._parse_respect_or_ignore_nulls(this)
    3963
    3964        # bigquery select from window x AS (partition by ...)
    3965        if alias:
    3966            over = None
    3967            self._match(TokenType.ALIAS)
    3968        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    3969            return this
    3970        else:
    3971            over = self._prev.text.upper()
    3972
    3973        if not self._match(TokenType.L_PAREN):
    3974            return self.expression(
    3975                exp.Window, this=this, alias=self._parse_id_var(False), over=over
    3976            )
    3977
    3978        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    3979
    3980        first = self._match(TokenType.FIRST)
    3981        if self._match_text_seq("LAST"):
    3982            first = False
    3983
    3984        partition = self._parse_partition_by()
    3985        order = self._parse_order()
    3986        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    3987
    3988        if kind:
    3989            self._match(TokenType.BETWEEN)
    3990            start = self._parse_window_spec()
    3991            self._match(TokenType.AND)
    3992            end = self._parse_window_spec()
    3993
    3994            spec = self.expression(
    3995                exp.WindowSpec,
    3996                kind=kind,
    3997                start=start["value"],
    3998                start_side=start["side"],
    3999                end=end["value"],
    4000                end_side=end["side"],
    4001            )
    4002        else:
    4003            spec = None
    4004
    4005        self._match_r_paren()
    4006
    4007        return self.expression(
    4008            exp.Window,
    4009            this=this,
    4010            partition_by=partition,
    4011            order=order,
    4012            spec=spec,
    4013            alias=window_alias,
    4014            over=over,
    4015            first=first,
    4016        )
    4017
    4018    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    4019        self._match(TokenType.BETWEEN)
    4020
    4021        return {
    4022            "value": (
    4023                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    4024                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    4025                or self._parse_bitwise()
    4026            ),
    4027            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    4028        }
    4029
    4030    def _parse_alias(
    4031        self, this: t.Optional[exp.Expression], explicit: bool = False
    4032    ) -> t.Optional[exp.Expression]:
    4033        any_token = self._match(TokenType.ALIAS)
    4034
    4035        if explicit and not any_token:
    4036            return this
    4037
    4038        if self._match(TokenType.L_PAREN):
    4039            aliases = self.expression(
    4040                exp.Aliases,
    4041                this=this,
    4042                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    4043            )
    4044            self._match_r_paren(aliases)
    4045            return aliases
    4046
    4047        alias = self._parse_id_var(any_token)
    4048
    4049        if alias:
    4050            return self.expression(exp.Alias, this=this, alias=alias)
    4051
    4052        return this
    4053
    4054    def _parse_id_var(
    4055        self,
    4056        any_token: bool = True,
    4057        tokens: t.Optional[t.Collection[TokenType]] = None,
    4058    ) -> t.Optional[exp.Expression]:
    4059        identifier = self._parse_identifier()
    4060
    4061        if identifier:
    4062            return identifier
    4063
    4064        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
    4065            quoted = self._prev.token_type == TokenType.STRING
    4066            return exp.Identifier(this=self._prev.text, quoted=quoted)
    4067
    4068        return None
    4069
    4070    def _parse_string(self) -> t.Optional[exp.Expression]:
    4071        if self._match(TokenType.STRING):
    4072            return self.PRIMARY_PARSERS[TokenType.STRING](self, self._prev)
    4073        return self._parse_placeholder()
    4074
    4075    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    4076        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    4077
    4078    def _parse_number(self) -> t.Optional[exp.Expression]:
    4079        if self._match(TokenType.NUMBER):
    4080            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
    4081        return self._parse_placeholder()
    4082
    4083    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    4084        if self._match(TokenType.IDENTIFIER):
    4085            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    4086        return self._parse_placeholder()
    4087
    4088    def _parse_var(
    4089        self, any_token: bool = False, tokens: t.Optional[t.Collection[TokenType]] = None
    4090    ) -> t.Optional[exp.Expression]:
    4091        if (
    4092            (any_token and self._advance_any())
    4093            or self._match(TokenType.VAR)
    4094            or (self._match_set(tokens) if tokens else False)
    4095        ):
    4096            return self.expression(exp.Var, this=self._prev.text)
    4097        return self._parse_placeholder()
    4098
    4099    def _advance_any(self) -> t.Optional[Token]:
    4100        if self._curr and self._curr.token_type not in self.RESERVED_KEYWORDS:
    4101            self._advance()
    4102            return self._prev
    4103        return None
    4104
    4105    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    4106        return self._parse_var() or self._parse_string()
    4107
    4108    def _parse_null(self) -> t.Optional[exp.Expression]:
    4109        if self._match(TokenType.NULL):
    4110            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    4111        return None
    4112
    4113    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    4114        if self._match(TokenType.TRUE):
    4115            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    4116        if self._match(TokenType.FALSE):
    4117            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    4118        return None
    4119
    4120    def _parse_star(self) -> t.Optional[exp.Expression]:
    4121        if self._match(TokenType.STAR):
    4122            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    4123        return None
    4124
    4125    def _parse_parameter(self) -> exp.Parameter:
    4126        wrapped = self._match(TokenType.L_BRACE)
    4127        this = self._parse_var() or self._parse_identifier() or self._parse_primary()
    4128        self._match(TokenType.R_BRACE)
    4129        return self.expression(exp.Parameter, this=this, wrapped=wrapped)
    4130
    4131    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    4132        if self._match_set(self.PLACEHOLDER_PARSERS):
    4133            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    4134            if placeholder:
    4135                return placeholder
    4136            self._advance(-1)
    4137        return None
    4138
    4139    def _parse_except(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    4140        if not self._match(TokenType.EXCEPT):
    4141            return None
    4142        if self._match(TokenType.L_PAREN, advance=False):
    4143            return self._parse_wrapped_csv(self._parse_column)
    4144        return self._parse_csv(self._parse_column)
    4145
    4146    def _parse_replace(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    4147        if not self._match(TokenType.REPLACE):
    4148            return None
    4149        if self._match(TokenType.L_PAREN, advance=False):
    4150            return self._parse_wrapped_csv(self._parse_expression)
    4151        return self._parse_csv(self._parse_expression)
    4152
    4153    def _parse_csv(
    4154        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    4155    ) -> t.List[t.Optional[exp.Expression]]:
    4156        parse_result = parse_method()
    4157        items = [parse_result] if parse_result is not None else []
    4158
    4159        while self._match(sep):
    4160            self._add_comments(parse_result)
    4161            parse_result = parse_method()
    4162            if parse_result is not None:
    4163                items.append(parse_result)
    4164
    4165        return items
    4166
    4167    def _parse_tokens(
    4168        self, parse_method: t.Callable, expressions: t.Dict
    4169    ) -> t.Optional[exp.Expression]:
    4170        this = parse_method()
    4171
    4172        while self._match_set(expressions):
    4173            this = self.expression(
    4174                expressions[self._prev.token_type],
    4175                this=this,
    4176                comments=self._prev_comments,
    4177                expression=parse_method(),
    4178            )
    4179
    4180        return this
    4181
    4182    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[t.Optional[exp.Expression]]:
    4183        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    4184
    4185    def _parse_wrapped_csv(
    4186        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    4187    ) -> t.List[t.Optional[exp.Expression]]:
    4188        return self._parse_wrapped(
    4189            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    4190        )
    4191
    4192    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    4193        wrapped = self._match(TokenType.L_PAREN)
    4194        if not wrapped and not optional:
    4195            self.raise_error("Expecting (")
    4196        parse_result = parse_method()
    4197        if wrapped:
    4198            self._match_r_paren()
    4199        return parse_result
    4200
    4201    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4202        return self._parse_select() or self._parse_set_operations(
    4203            self._parse_expression() if alias else self._parse_conjunction()
    4204        )
    4205
    4206    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    4207        return self._parse_query_modifiers(
    4208            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    4209        )
    4210
    4211    def _parse_transaction(self) -> exp.Transaction:
    4212        this = None
    4213        if self._match_texts(self.TRANSACTION_KIND):
    4214            this = self._prev.text
    4215
    4216        self._match_texts({"TRANSACTION", "WORK"})
    4217
    4218        modes = []
    4219        while True:
    4220            mode = []
    4221            while self._match(TokenType.VAR):
    4222                mode.append(self._prev.text)
    4223
    4224            if mode:
    4225                modes.append(" ".join(mode))
    4226            if not self._match(TokenType.COMMA):
    4227                break
    4228
    4229        return self.expression(exp.Transaction, this=this, modes=modes)
    4230
    4231    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    4232        chain = None
    4233        savepoint = None
    4234        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    4235
    4236        self._match_texts({"TRANSACTION", "WORK"})
    4237
    4238        if self._match_text_seq("TO"):
    4239            self._match_text_seq("SAVEPOINT")
    4240            savepoint = self._parse_id_var()
    4241
    4242        if self._match(TokenType.AND):
    4243            chain = not self._match_text_seq("NO")
    4244            self._match_text_seq("CHAIN")
    4245
    4246        if is_rollback:
    4247            return self.expression(exp.Rollback, savepoint=savepoint)
    4248
    4249        return self.expression(exp.Commit, chain=chain)
    4250
    4251    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    4252        if not self._match_text_seq("ADD"):
    4253            return None
    4254
    4255        self._match(TokenType.COLUMN)
    4256        exists_column = self._parse_exists(not_=True)
    4257        expression = self._parse_column_def(self._parse_field(any_token=True))
    4258
    4259        if expression:
    4260            expression.set("exists", exists_column)
    4261
    4262            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    4263            if self._match_texts(("FIRST", "AFTER")):
    4264                position = self._prev.text
    4265                column_position = self.expression(
    4266                    exp.ColumnPosition, this=self._parse_column(), position=position
    4267                )
    4268                expression.set("position", column_position)
    4269
    4270        return expression
    4271
    4272    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    4273        drop = self._match(TokenType.DROP) and self._parse_drop()
    4274        if drop and not isinstance(drop, exp.Command):
    4275            drop.set("kind", drop.args.get("kind", "COLUMN"))
    4276        return drop
    4277
    4278    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    4279    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    4280        return self.expression(
    4281            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    4282        )
    4283
    4284    def _parse_add_constraint(self) -> exp.AddConstraint:
    4285        this = None
    4286        kind = self._prev.token_type
    4287
    4288        if kind == TokenType.CONSTRAINT:
    4289            this = self._parse_id_var()
    4290
    4291            if self._match_text_seq("CHECK"):
    4292                expression = self._parse_wrapped(self._parse_conjunction)
    4293                enforced = self._match_text_seq("ENFORCED")
    4294
    4295                return self.expression(
    4296                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
    4297                )
    4298
    4299        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
    4300            expression = self._parse_foreign_key()
    4301        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
    4302            expression = self._parse_primary_key()
    4303        else:
    4304            expression = None
    4305
    4306        return self.expression(exp.AddConstraint, this=this, expression=expression)
    4307
    4308    def _parse_alter_table_add(self) -> t.List[t.Optional[exp.Expression]]:
    4309        index = self._index - 1
    4310
    4311        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
    4312            return self._parse_csv(self._parse_add_constraint)
    4313
    4314        self._retreat(index)
    4315        return self._parse_csv(self._parse_add_column)
    4316
    4317    def _parse_alter_table_alter(self) -> exp.AlterColumn:
    4318        self._match(TokenType.COLUMN)
    4319        column = self._parse_field(any_token=True)
    4320
    4321        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    4322            return self.expression(exp.AlterColumn, this=column, drop=True)
    4323        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    4324            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
    4325
    4326        self._match_text_seq("SET", "DATA")
    4327        return self.expression(
    4328            exp.AlterColumn,
    4329            this=column,
    4330            dtype=self._match_text_seq("TYPE") and self._parse_types(),
    4331            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    4332            using=self._match(TokenType.USING) and self._parse_conjunction(),
    4333        )
    4334
    4335    def _parse_alter_table_drop(self) -> t.List[t.Optional[exp.Expression]]:
    4336        index = self._index - 1
    4337
    4338        partition_exists = self._parse_exists()
    4339        if self._match(TokenType.PARTITION, advance=False):
    4340            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    4341
    4342        self._retreat(index)
    4343        return self._parse_csv(self._parse_drop_column)
    4344
    4345    def _parse_alter_table_rename(self) -> exp.RenameTable:
    4346        self._match_text_seq("TO")
    4347        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    4348
    4349    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    4350        start = self._prev
    4351
    4352        if not self._match(TokenType.TABLE):
    4353            return self._parse_as_command(start)
    4354
    4355        exists = self._parse_exists()
    4356        this = self._parse_table(schema=True)
    4357
    4358        if self._next:
    4359            self._advance()
    4360        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    4361
    4362        if parser:
    4363            actions = ensure_list(parser(self))
    4364
    4365            if not self._curr:
    4366                return self.expression(
    4367                    exp.AlterTable,
    4368                    this=this,
    4369                    exists=exists,
    4370                    actions=actions,
    4371                )
    4372        return self._parse_as_command(start)
    4373
    4374    def _parse_merge(self) -> exp.Merge:
    4375        self._match(TokenType.INTO)
    4376        target = self._parse_table()
    4377
    4378        self._match(TokenType.USING)
    4379        using = self._parse_table()
    4380
    4381        self._match(TokenType.ON)
    4382        on = self._parse_conjunction()
    4383
    4384        whens = []
    4385        while self._match(TokenType.WHEN):
    4386            matched = not self._match(TokenType.NOT)
    4387            self._match_text_seq("MATCHED")
    4388            source = (
    4389                False
    4390                if self._match_text_seq("BY", "TARGET")
    4391                else self._match_text_seq("BY", "SOURCE")
    4392            )
    4393            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
    4394
    4395            self._match(TokenType.THEN)
    4396
    4397            if self._match(TokenType.INSERT):
    4398                _this = self._parse_star()
    4399                if _this:
    4400                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    4401                else:
    4402                    then = self.expression(
    4403                        exp.Insert,
    4404                        this=self._parse_value(),
    4405                        expression=self._match(TokenType.VALUES) and self._parse_value(),
    4406                    )
    4407            elif self._match(TokenType.UPDATE):
    4408                expressions = self._parse_star()
    4409                if expressions:
    4410                    then = self.expression(exp.Update, expressions=expressions)
    4411                else:
    4412                    then = self.expression(
    4413                        exp.Update,
    4414                        expressions=self._match(TokenType.SET)
    4415                        and self._parse_csv(self._parse_equality),
    4416                    )
    4417            elif self._match(TokenType.DELETE):
    4418                then = self.expression(exp.Var, this=self._prev.text)
    4419            else:
    4420                then = None
    4421
    4422            whens.append(
    4423                self.expression(
    4424                    exp.When,
    4425                    matched=matched,
    4426                    source=source,
    4427                    condition=condition,
    4428                    then=then,
    4429                )
    4430            )
    4431
    4432        return self.expression(
    4433            exp.Merge,
    4434            this=target,
    4435            using=using,
    4436            on=on,
    4437            expressions=whens,
    4438        )
    4439
    4440    def _parse_show(self) -> t.Optional[exp.Expression]:
    4441        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    4442        if parser:
    4443            return parser(self)
    4444        self._advance()
    4445        return self.expression(exp.Show, this=self._prev.text.upper())
    4446
    4447    def _parse_set_item_assignment(
    4448        self, kind: t.Optional[str] = None
    4449    ) -> t.Optional[exp.Expression]:
    4450        index = self._index
    4451
    4452        if kind in {"GLOBAL", "SESSION"} and self._match_text_seq("TRANSACTION"):
    4453            return self._parse_set_transaction(global_=kind == "GLOBAL")
    4454
    4455        left = self._parse_primary() or self._parse_id_var()
    4456
    4457        if not self._match_texts(("=", "TO")):
    4458            self._retreat(index)
    4459            return None
    4460
    4461        right = self._parse_statement() or self._parse_id_var()
    4462        this = self.expression(exp.EQ, this=left, expression=right)
    4463
    4464        return self.expression(exp.SetItem, this=this, kind=kind)
    4465
    4466    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    4467        self._match_text_seq("TRANSACTION")
    4468        characteristics = self._parse_csv(
    4469            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    4470        )
    4471        return self.expression(
    4472            exp.SetItem,
    4473            expressions=characteristics,
    4474            kind="TRANSACTION",
    4475            **{"global": global_},  # type: ignore
    4476        )
    4477
    4478    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    4479        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    4480        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    4481
    4482    def _parse_set(self) -> exp.Set | exp.Command:
    4483        index = self._index
    4484        set_ = self.expression(exp.Set, expressions=self._parse_csv(self._parse_set_item))
    4485
    4486        if self._curr:
    4487            self._retreat(index)
    4488            return self._parse_as_command(self._prev)
    4489
    4490        return set_
    4491
    4492    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
    4493        for option in options:
    4494            if self._match_text_seq(*option.split(" ")):
    4495                return exp.var(option)
    4496        return None
    4497
    4498    def _parse_as_command(self, start: Token) -> exp.Command:
    4499        while self._curr:
    4500            self._advance()
    4501        text = self._find_sql(start, self._prev)
    4502        size = len(start.text)
    4503        return exp.Command(this=text[:size], expression=text[size:])
    4504
    4505    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    4506        settings = []
    4507
    4508        self._match_l_paren()
    4509        kind = self._parse_id_var()
    4510
    4511        if self._match(TokenType.L_PAREN):
    4512            while True:
    4513                key = self._parse_id_var()
    4514                value = self._parse_primary()
    4515
    4516                if not key and value is None:
    4517                    break
    4518                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    4519            self._match(TokenType.R_PAREN)
    4520
    4521        self._match_r_paren()
    4522
    4523        return self.expression(
    4524            exp.DictProperty,
    4525            this=this,
    4526            kind=kind.this if kind else None,
    4527            settings=settings,
    4528        )
    4529
    4530    def _parse_dict_range(self, this: str) -> exp.DictRange:
    4531        self._match_l_paren()
    4532        has_min = self._match_text_seq("MIN")
    4533        if has_min:
    4534            min = self._parse_var() or self._parse_primary()
    4535            self._match_text_seq("MAX")
    4536            max = self._parse_var() or self._parse_primary()
    4537        else:
    4538            max = self._parse_var() or self._parse_primary()
    4539            min = exp.Literal.number(0)
    4540        self._match_r_paren()
    4541        return self.expression(exp.DictRange, this=this, min=min, max=max)
    4542
    4543    def _find_parser(
    4544        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    4545    ) -> t.Optional[t.Callable]:
    4546        if not self._curr:
    4547            return None
    4548
    4549        index = self._index
    4550        this = []
    4551        while True:
    4552            # The current token might be multiple words
    4553            curr = self._curr.text.upper()
    4554            key = curr.split(" ")
    4555            this.append(curr)
    4556            self._advance()
    4557            result, trie = in_trie(trie, key)
    4558            if result == 0:
    4559                break
    4560            if result == 2:
    4561                subparser = parsers[" ".join(this)]
    4562                return subparser
    4563        self._retreat(index)
    4564        return None
    4565
    4566    def _match(self, token_type, advance=True, expression=None):
    4567        if not self._curr:
    4568            return None
    4569
    4570        if self._curr.token_type == token_type:
    4571            if advance:
    4572                self._advance()
    4573            self._add_comments(expression)
    4574            return True
    4575
    4576        return None
    4577
    4578    def _match_set(self, types, advance=True):
    4579        if not self._curr:
    4580            return None
    4581
    4582        if self._curr.token_type in types:
    4583            if advance:
    4584                self._advance()
    4585            return True
    4586
    4587        return None
    4588
    4589    def _match_pair(self, token_type_a, token_type_b, advance=True):
    4590        if not self._curr or not self._next:
    4591            return None
    4592
    4593        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    4594            if advance:
    4595                self._advance(2)
    4596            return True
    4597
    4598        return None
    4599
    4600    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    4601        if not self._match(TokenType.L_PAREN, expression=expression):
    4602            self.raise_error("Expecting (")
    4603
    4604    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    4605        if not self._match(TokenType.R_PAREN, expression=expression):
    4606            self.raise_error("Expecting )")
    4607
    4608    def _match_texts(self, texts, advance=True):
    4609        if self._curr and self._curr.text.upper() in texts:
    4610            if advance:
    4611                self._advance()
    4612            return True
    4613        return False
    4614
    4615    def _match_text_seq(self, *texts, advance=True):
    4616        index = self._index
    4617        for text in texts:
    4618            if self._curr and self._curr.text.upper() == text:
    4619                self._advance()
    4620            else:
    4621                self._retreat(index)
    4622                return False
    4623
    4624        if not advance:
    4625            self._retreat(index)
    4626
    4627        return True
    4628
    4629    @t.overload
    4630    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
    4631        ...
    4632
    4633    @t.overload
    4634    def _replace_columns_with_dots(
    4635        self, this: t.Optional[exp.Expression]
    4636    ) -> t.Optional[exp.Expression]:
    4637        ...
    4638
    4639    def _replace_columns_with_dots(self, this):
    4640        if isinstance(this, exp.Dot):
    4641            exp.replace_children(this, self._replace_columns_with_dots)
    4642        elif isinstance(this, exp.Column):
    4643            exp.replace_children(this, self._replace_columns_with_dots)
    4644            table = this.args.get("table")
    4645            this = (
    4646                self.expression(exp.Dot, this=table, expression=this.this)
    4647                if table
    4648                else self.expression(exp.Var, this=this.name)
    4649            )
    4650        elif isinstance(this, exp.Identifier):
    4651            this = self.expression(exp.Var, this=this.name)
    4652
    4653        return this
    4654
    4655    def _replace_lambda(
    4656        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
    4657    ) -> t.Optional[exp.Expression]:
    4658        if not node:
    4659            return node
    4660
    4661        for column in node.find_all(exp.Column):
    4662            if column.parts[0].name in lambda_variables:
    4663                dot_or_id = column.to_dot() if column.table else column.this
    4664                parent = column.parent
    4665
    4666                while isinstance(parent, exp.Dot):
    4667                    if not isinstance(parent.parent, exp.Dot):
    4668                        parent.replace(dot_or_id)
    4669                        break
    4670                    parent = parent.parent
    4671                else:
    4672                    if column is node:
    4673                        node = dot_or_id
    4674                    else:
    4675                        column.replace(dot_or_id)
    4676        return node

def parse_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

    21def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    22    if len(args) == 1 and args[0].is_star:
    23        return exp.StarMap(this=args[0])
    24
    25    keys = []
    26    values = []
    27    for i in range(0, len(args), 2):
    28        keys.append(args[i])
    29        values.append(args[i + 1])
    30
    31    return exp.VarMap(
    32        keys=exp.Array(expressions=keys),
    33        values=exp.Array(expressions=values),
    34    )

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

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

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

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

class Parser: View Source

      60class Parser(metaclass=_Parser):
      61    """
      62    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
      63
      64    Args:
      65        error_level: The desired error level.
      66            Default: ErrorLevel.IMMEDIATE
      67        error_message_context: Determines the amount of context to capture from a
      68            query string when displaying the error message (in number of characters).
      69            Default: 100
      70        max_errors: Maximum number of error messages to include in a raised ParseError.
      71            This is only relevant if error_level is ErrorLevel.RAISE.
      72            Default: 3
      73    """
      74
      75    FUNCTIONS: t.Dict[str, t.Callable] = {
      76        **{name: f.from_arg_list for f in exp.ALL_FUNCTIONS for name in f.sql_names()},
      77        "DATE_TO_DATE_STR": lambda args: exp.Cast(
      78            this=seq_get(args, 0),
      79            to=exp.DataType(this=exp.DataType.Type.TEXT),
      80        ),
      81        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
      82        "LIKE": parse_like,
      83        "TIME_TO_TIME_STR": lambda args: exp.Cast(
      84            this=seq_get(args, 0),
      85            to=exp.DataType(this=exp.DataType.Type.TEXT),
      86        ),
      87        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
      88            this=exp.Cast(
      89                this=seq_get(args, 0),
      90                to=exp.DataType(this=exp.DataType.Type.TEXT),
      91            ),
      92            start=exp.Literal.number(1),
      93            length=exp.Literal.number(10),
      94        ),
      95        "VAR_MAP": parse_var_map,
      96    }
      97
      98    NO_PAREN_FUNCTIONS = {
      99        TokenType.CURRENT_DATE: exp.CurrentDate,
     100        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     101        TokenType.CURRENT_TIME: exp.CurrentTime,
     102        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     103        TokenType.CURRENT_USER: exp.CurrentUser,
     104    }
     105
     106    NESTED_TYPE_TOKENS = {
     107        TokenType.ARRAY,
     108        TokenType.MAP,
     109        TokenType.NULLABLE,
     110        TokenType.STRUCT,
     111    }
     112
     113    ENUM_TYPE_TOKENS = {
     114        TokenType.ENUM,
     115    }
     116
     117    TYPE_TOKENS = {
     118        TokenType.BIT,
     119        TokenType.BOOLEAN,
     120        TokenType.TINYINT,
     121        TokenType.UTINYINT,
     122        TokenType.SMALLINT,
     123        TokenType.USMALLINT,
     124        TokenType.INT,
     125        TokenType.UINT,
     126        TokenType.BIGINT,
     127        TokenType.UBIGINT,
     128        TokenType.INT128,
     129        TokenType.UINT128,
     130        TokenType.INT256,
     131        TokenType.UINT256,
     132        TokenType.FLOAT,
     133        TokenType.DOUBLE,
     134        TokenType.CHAR,
     135        TokenType.NCHAR,
     136        TokenType.VARCHAR,
     137        TokenType.NVARCHAR,
     138        TokenType.TEXT,
     139        TokenType.MEDIUMTEXT,
     140        TokenType.LONGTEXT,
     141        TokenType.MEDIUMBLOB,
     142        TokenType.LONGBLOB,
     143        TokenType.BINARY,
     144        TokenType.VARBINARY,
     145        TokenType.JSON,
     146        TokenType.JSONB,
     147        TokenType.INTERVAL,
     148        TokenType.TIME,
     149        TokenType.TIMESTAMP,
     150        TokenType.TIMESTAMPTZ,
     151        TokenType.TIMESTAMPLTZ,
     152        TokenType.DATETIME,
     153        TokenType.DATETIME64,
     154        TokenType.DATE,
     155        TokenType.INT4RANGE,
     156        TokenType.INT4MULTIRANGE,
     157        TokenType.INT8RANGE,
     158        TokenType.INT8MULTIRANGE,
     159        TokenType.NUMRANGE,
     160        TokenType.NUMMULTIRANGE,
     161        TokenType.TSRANGE,
     162        TokenType.TSMULTIRANGE,
     163        TokenType.TSTZRANGE,
     164        TokenType.TSTZMULTIRANGE,
     165        TokenType.DATERANGE,
     166        TokenType.DATEMULTIRANGE,
     167        TokenType.DECIMAL,
     168        TokenType.BIGDECIMAL,
     169        TokenType.UUID,
     170        TokenType.GEOGRAPHY,
     171        TokenType.GEOMETRY,
     172        TokenType.HLLSKETCH,
     173        TokenType.HSTORE,
     174        TokenType.PSEUDO_TYPE,
     175        TokenType.SUPER,
     176        TokenType.SERIAL,
     177        TokenType.SMALLSERIAL,
     178        TokenType.BIGSERIAL,
     179        TokenType.XML,
     180        TokenType.UNIQUEIDENTIFIER,
     181        TokenType.MONEY,
     182        TokenType.SMALLMONEY,
     183        TokenType.ROWVERSION,
     184        TokenType.IMAGE,
     185        TokenType.VARIANT,
     186        TokenType.OBJECT,
     187        TokenType.INET,
     188        TokenType.ENUM,
     189        *NESTED_TYPE_TOKENS,
     190    }
     191
     192    SUBQUERY_PREDICATES = {
     193        TokenType.ANY: exp.Any,
     194        TokenType.ALL: exp.All,
     195        TokenType.EXISTS: exp.Exists,
     196        TokenType.SOME: exp.Any,
     197    }
     198
     199    RESERVED_KEYWORDS = {
     200        *Tokenizer.SINGLE_TOKENS.values(),
     201        TokenType.SELECT,
     202    }
     203
     204    DB_CREATABLES = {
     205        TokenType.DATABASE,
     206        TokenType.SCHEMA,
     207        TokenType.TABLE,
     208        TokenType.VIEW,
     209        TokenType.DICTIONARY,
     210    }
     211
     212    CREATABLES = {
     213        TokenType.COLUMN,
     214        TokenType.FUNCTION,
     215        TokenType.INDEX,
     216        TokenType.PROCEDURE,
     217        *DB_CREATABLES,
     218    }
     219
     220    # Tokens that can represent identifiers
     221    ID_VAR_TOKENS = {
     222        TokenType.VAR,
     223        TokenType.ANTI,
     224        TokenType.APPLY,
     225        TokenType.ASC,
     226        TokenType.AUTO_INCREMENT,
     227        TokenType.BEGIN,
     228        TokenType.CACHE,
     229        TokenType.CASE,
     230        TokenType.COLLATE,
     231        TokenType.COMMAND,
     232        TokenType.COMMENT,
     233        TokenType.COMMIT,
     234        TokenType.CONSTRAINT,
     235        TokenType.DEFAULT,
     236        TokenType.DELETE,
     237        TokenType.DESC,
     238        TokenType.DESCRIBE,
     239        TokenType.DICTIONARY,
     240        TokenType.DIV,
     241        TokenType.END,
     242        TokenType.EXECUTE,
     243        TokenType.ESCAPE,
     244        TokenType.FALSE,
     245        TokenType.FIRST,
     246        TokenType.FILTER,
     247        TokenType.FORMAT,
     248        TokenType.FULL,
     249        TokenType.IF,
     250        TokenType.IS,
     251        TokenType.ISNULL,
     252        TokenType.INTERVAL,
     253        TokenType.KEEP,
     254        TokenType.LEFT,
     255        TokenType.LOAD,
     256        TokenType.MERGE,
     257        TokenType.NATURAL,
     258        TokenType.NEXT,
     259        TokenType.OFFSET,
     260        TokenType.ORDINALITY,
     261        TokenType.OVERWRITE,
     262        TokenType.PARTITION,
     263        TokenType.PERCENT,
     264        TokenType.PIVOT,
     265        TokenType.PRAGMA,
     266        TokenType.RANGE,
     267        TokenType.REFERENCES,
     268        TokenType.RIGHT,
     269        TokenType.ROW,
     270        TokenType.ROWS,
     271        TokenType.SEMI,
     272        TokenType.SET,
     273        TokenType.SETTINGS,
     274        TokenType.SHOW,
     275        TokenType.TEMPORARY,
     276        TokenType.TOP,
     277        TokenType.TRUE,
     278        TokenType.UNIQUE,
     279        TokenType.UNPIVOT,
     280        TokenType.UPDATE,
     281        TokenType.VOLATILE,
     282        TokenType.WINDOW,
     283        *CREATABLES,
     284        *SUBQUERY_PREDICATES,
     285        *TYPE_TOKENS,
     286        *NO_PAREN_FUNCTIONS,
     287    }
     288
     289    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
     290
     291    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     292        TokenType.APPLY,
     293        TokenType.ASOF,
     294        TokenType.FULL,
     295        TokenType.LEFT,
     296        TokenType.LOCK,
     297        TokenType.NATURAL,
     298        TokenType.OFFSET,
     299        TokenType.RIGHT,
     300        TokenType.WINDOW,
     301    }
     302
     303    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     304
     305    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     306
     307    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     308
     309    FUNC_TOKENS = {
     310        TokenType.COMMAND,
     311        TokenType.CURRENT_DATE,
     312        TokenType.CURRENT_DATETIME,
     313        TokenType.CURRENT_TIMESTAMP,
     314        TokenType.CURRENT_TIME,
     315        TokenType.CURRENT_USER,
     316        TokenType.FILTER,
     317        TokenType.FIRST,
     318        TokenType.FORMAT,
     319        TokenType.GLOB,
     320        TokenType.IDENTIFIER,
     321        TokenType.INDEX,
     322        TokenType.ISNULL,
     323        TokenType.ILIKE,
     324        TokenType.LIKE,
     325        TokenType.MERGE,
     326        TokenType.OFFSET,
     327        TokenType.PRIMARY_KEY,
     328        TokenType.RANGE,
     329        TokenType.REPLACE,
     330        TokenType.ROW,
     331        TokenType.UNNEST,
     332        TokenType.VAR,
     333        TokenType.LEFT,
     334        TokenType.RIGHT,
     335        TokenType.DATE,
     336        TokenType.DATETIME,
     337        TokenType.TABLE,
     338        TokenType.TIMESTAMP,
     339        TokenType.TIMESTAMPTZ,
     340        TokenType.WINDOW,
     341        *TYPE_TOKENS,
     342        *SUBQUERY_PREDICATES,
     343    }
     344
     345    CONJUNCTION = {
     346        TokenType.AND: exp.And,
     347        TokenType.OR: exp.Or,
     348    }
     349
     350    EQUALITY = {
     351        TokenType.EQ: exp.EQ,
     352        TokenType.NEQ: exp.NEQ,
     353        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     354    }
     355
     356    COMPARISON = {
     357        TokenType.GT: exp.GT,
     358        TokenType.GTE: exp.GTE,
     359        TokenType.LT: exp.LT,
     360        TokenType.LTE: exp.LTE,
     361    }
     362
     363    BITWISE = {
     364        TokenType.AMP: exp.BitwiseAnd,
     365        TokenType.CARET: exp.BitwiseXor,
     366        TokenType.PIPE: exp.BitwiseOr,
     367        TokenType.DPIPE: exp.DPipe,
     368    }
     369
     370    TERM = {
     371        TokenType.DASH: exp.Sub,
     372        TokenType.PLUS: exp.Add,
     373        TokenType.MOD: exp.Mod,
     374        TokenType.COLLATE: exp.Collate,
     375    }
     376
     377    FACTOR = {
     378        TokenType.DIV: exp.IntDiv,
     379        TokenType.LR_ARROW: exp.Distance,
     380        TokenType.SLASH: exp.Div,
     381        TokenType.STAR: exp.Mul,
     382    }
     383
     384    TIMESTAMPS = {
     385        TokenType.TIME,
     386        TokenType.TIMESTAMP,
     387        TokenType.TIMESTAMPTZ,
     388        TokenType.TIMESTAMPLTZ,
     389    }
     390
     391    SET_OPERATIONS = {
     392        TokenType.UNION,
     393        TokenType.INTERSECT,
     394        TokenType.EXCEPT,
     395    }
     396
     397    JOIN_METHODS = {
     398        TokenType.NATURAL,
     399        TokenType.ASOF,
     400    }
     401
     402    JOIN_SIDES = {
     403        TokenType.LEFT,
     404        TokenType.RIGHT,
     405        TokenType.FULL,
     406    }
     407
     408    JOIN_KINDS = {
     409        TokenType.INNER,
     410        TokenType.OUTER,
     411        TokenType.CROSS,
     412        TokenType.SEMI,
     413        TokenType.ANTI,
     414    }
     415
     416    JOIN_HINTS: t.Set[str] = set()
     417
     418    LAMBDAS = {
     419        TokenType.ARROW: lambda self, expressions: self.expression(
     420            exp.Lambda,
     421            this=self._replace_lambda(
     422                self._parse_conjunction(),
     423                {node.name for node in expressions},
     424            ),
     425            expressions=expressions,
     426        ),
     427        TokenType.FARROW: lambda self, expressions: self.expression(
     428            exp.Kwarg,
     429            this=exp.var(expressions[0].name),
     430            expression=self._parse_conjunction(),
     431        ),
     432    }
     433
     434    COLUMN_OPERATORS = {
     435        TokenType.DOT: None,
     436        TokenType.DCOLON: lambda self, this, to: self.expression(
     437            exp.Cast if self.STRICT_CAST else exp.TryCast,
     438            this=this,
     439            to=to,
     440        ),
     441        TokenType.ARROW: lambda self, this, path: self.expression(
     442            exp.JSONExtract,
     443            this=this,
     444            expression=path,
     445        ),
     446        TokenType.DARROW: lambda self, this, path: self.expression(
     447            exp.JSONExtractScalar,
     448            this=this,
     449            expression=path,
     450        ),
     451        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     452            exp.JSONBExtract,
     453            this=this,
     454            expression=path,
     455        ),
     456        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     457            exp.JSONBExtractScalar,
     458            this=this,
     459            expression=path,
     460        ),
     461        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     462            exp.JSONBContains,
     463            this=this,
     464            expression=key,
     465        ),
     466    }
     467
     468    EXPRESSION_PARSERS = {
     469        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, "CLUSTER", "BY"),
     470        exp.Column: lambda self: self._parse_column(),
     471        exp.Condition: lambda self: self._parse_conjunction(),
     472        exp.DataType: lambda self: self._parse_types(),
     473        exp.Expression: lambda self: self._parse_statement(),
     474        exp.From: lambda self: self._parse_from(),
     475        exp.Group: lambda self: self._parse_group(),
     476        exp.Having: lambda self: self._parse_having(),
     477        exp.Identifier: lambda self: self._parse_id_var(),
     478        exp.Join: lambda self: self._parse_join(),
     479        exp.Lambda: lambda self: self._parse_lambda(),
     480        exp.Lateral: lambda self: self._parse_lateral(),
     481        exp.Limit: lambda self: self._parse_limit(),
     482        exp.Offset: lambda self: self._parse_offset(),
     483        exp.Order: lambda self: self._parse_order(),
     484        exp.Ordered: lambda self: self._parse_ordered(),
     485        exp.Properties: lambda self: self._parse_properties(),
     486        exp.Qualify: lambda self: self._parse_qualify(),
     487        exp.Returning: lambda self: self._parse_returning(),
     488        exp.Sort: lambda self: self._parse_sort(exp.Sort, "SORT", "BY"),
     489        exp.Table: lambda self: self._parse_table_parts(),
     490        exp.TableAlias: lambda self: self._parse_table_alias(),
     491        exp.Where: lambda self: self._parse_where(),
     492        exp.Window: lambda self: self._parse_named_window(),
     493        exp.With: lambda self: self._parse_with(),
     494        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     495    }
     496
     497    STATEMENT_PARSERS = {
     498        TokenType.ALTER: lambda self: self._parse_alter(),
     499        TokenType.BEGIN: lambda self: self._parse_transaction(),
     500        TokenType.CACHE: lambda self: self._parse_cache(),
     501        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     502        TokenType.COMMENT: lambda self: self._parse_comment(),
     503        TokenType.CREATE: lambda self: self._parse_create(),
     504        TokenType.DELETE: lambda self: self._parse_delete(),
     505        TokenType.DESC: lambda self: self._parse_describe(),
     506        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     507        TokenType.DROP: lambda self: self._parse_drop(),
     508        TokenType.END: lambda self: self._parse_commit_or_rollback(),
     509        TokenType.FROM: lambda self: exp.select("*").from_(
     510            t.cast(exp.From, self._parse_from(skip_from_token=True))
     511        ),
     512        TokenType.INSERT: lambda self: self._parse_insert(),
     513        TokenType.LOAD: lambda self: self._parse_load(),
     514        TokenType.MERGE: lambda self: self._parse_merge(),
     515        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     516        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     517        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     518        TokenType.SET: lambda self: self._parse_set(),
     519        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     520        TokenType.UPDATE: lambda self: self._parse_update(),
     521        TokenType.USE: lambda self: self.expression(
     522            exp.Use,
     523            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
     524            and exp.var(self._prev.text),
     525            this=self._parse_table(schema=False),
     526        ),
     527    }
     528
     529    UNARY_PARSERS = {
     530        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     531        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     532        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     533        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     534    }
     535
     536    PRIMARY_PARSERS = {
     537        TokenType.STRING: lambda self, token: self.expression(
     538            exp.Literal, this=token.text, is_string=True
     539        ),
     540        TokenType.NUMBER: lambda self, token: self.expression(
     541            exp.Literal, this=token.text, is_string=False
     542        ),
     543        TokenType.STAR: lambda self, _: self.expression(
     544            exp.Star,
     545            **{"except": self._parse_except(), "replace": self._parse_replace()},
     546        ),
     547        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     548        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     549        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     550        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     551        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
     552        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     553        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     554        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     555            exp.National, this=token.text
     556        ),
     557        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     558        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     559    }
     560
     561    PLACEHOLDER_PARSERS = {
     562        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     563        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     564        TokenType.COLON: lambda self: self.expression(exp.Placeholder, this=self._prev.text)
     565        if self._match_set((TokenType.NUMBER, TokenType.VAR))
     566        else None,
     567    }
     568
     569    RANGE_PARSERS = {
     570        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     571        TokenType.GLOB: binary_range_parser(exp.Glob),
     572        TokenType.ILIKE: binary_range_parser(exp.ILike),
     573        TokenType.IN: lambda self, this: self._parse_in(this),
     574        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     575        TokenType.IS: lambda self, this: self._parse_is(this),
     576        TokenType.LIKE: binary_range_parser(exp.Like),
     577        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     578        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     579        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     580    }
     581
     582    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     583        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     584        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     585        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     586        "CHARACTER SET": lambda self: self._parse_character_set(),
     587        "CHECKSUM": lambda self: self._parse_checksum(),
     588        "CLUSTER": lambda self: self._parse_cluster(),
     589        "COLLATE": lambda self: self._parse_property_assignment(exp.CollateProperty),
     590        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     591        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     592        "DEFINER": lambda self: self._parse_definer(),
     593        "DETERMINISTIC": lambda self: self.expression(
     594            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     595        ),
     596        "DISTKEY": lambda self: self._parse_distkey(),
     597        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     598        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     599        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     600        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     601        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     602        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     603        "FREESPACE": lambda self: self._parse_freespace(),
     604        "IMMUTABLE": lambda self: self.expression(
     605            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     606        ),
     607        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     608        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     609        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     610        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     611        "LIKE": lambda self: self._parse_create_like(),
     612        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     613        "LOCK": lambda self: self._parse_locking(),
     614        "LOCKING": lambda self: self._parse_locking(),
     615        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     616        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     617        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     618        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     619        "NO": lambda self: self._parse_no_property(),
     620        "ON": lambda self: self._parse_on_property(),
     621        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     622        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     623        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     624        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     625        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     626        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     627        "RETURNS": lambda self: self._parse_returns(),
     628        "ROW": lambda self: self._parse_row(),
     629        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     630        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
     631        "SETTINGS": lambda self: self.expression(
     632            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
     633        ),
     634        "SORTKEY": lambda self: self._parse_sortkey(),
     635        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
     636        "STABLE": lambda self: self.expression(
     637            exp.StabilityProperty, this=exp.Literal.string("STABLE")
     638        ),
     639        "STORED": lambda self: self._parse_stored(),
     640        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
     641        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
     642        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
     643        "TO": lambda self: self._parse_to_table(),
     644        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
     645        "TTL": lambda self: self._parse_ttl(),
     646        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     647        "VOLATILE": lambda self: self._parse_volatile_property(),
     648        "WITH": lambda self: self._parse_with_property(),
     649    }
     650
     651    CONSTRAINT_PARSERS = {
     652        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
     653        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
     654        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
     655        "CHARACTER SET": lambda self: self.expression(
     656            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
     657        ),
     658        "CHECK": lambda self: self.expression(
     659            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
     660        ),
     661        "COLLATE": lambda self: self.expression(
     662            exp.CollateColumnConstraint, this=self._parse_var()
     663        ),
     664        "COMMENT": lambda self: self.expression(
     665            exp.CommentColumnConstraint, this=self._parse_string()
     666        ),
     667        "COMPRESS": lambda self: self._parse_compress(),
     668        "DEFAULT": lambda self: self.expression(
     669            exp.DefaultColumnConstraint, this=self._parse_bitwise()
     670        ),
     671        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
     672        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
     673        "FORMAT": lambda self: self.expression(
     674            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
     675        ),
     676        "GENERATED": lambda self: self._parse_generated_as_identity(),
     677        "IDENTITY": lambda self: self._parse_auto_increment(),
     678        "INLINE": lambda self: self._parse_inline(),
     679        "LIKE": lambda self: self._parse_create_like(),
     680        "NOT": lambda self: self._parse_not_constraint(),
     681        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
     682        "ON": lambda self: self._match(TokenType.UPDATE)
     683        and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function()),
     684        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
     685        "PRIMARY KEY": lambda self: self._parse_primary_key(),
     686        "REFERENCES": lambda self: self._parse_references(match=False),
     687        "TITLE": lambda self: self.expression(
     688            exp.TitleColumnConstraint, this=self._parse_var_or_string()
     689        ),
     690        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
     691        "UNIQUE": lambda self: self._parse_unique(),
     692        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
     693    }
     694
     695    ALTER_PARSERS = {
     696        "ADD": lambda self: self._parse_alter_table_add(),
     697        "ALTER": lambda self: self._parse_alter_table_alter(),
     698        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
     699        "DROP": lambda self: self._parse_alter_table_drop(),
     700        "RENAME": lambda self: self._parse_alter_table_rename(),
     701    }
     702
     703    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE"}
     704
     705    NO_PAREN_FUNCTION_PARSERS = {
     706        TokenType.ANY: lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
     707        TokenType.CASE: lambda self: self._parse_case(),
     708        TokenType.IF: lambda self: self._parse_if(),
     709        TokenType.NEXT_VALUE_FOR: lambda self: self.expression(
     710            exp.NextValueFor,
     711            this=self._parse_column(),
     712            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
     713        ),
     714    }
     715
     716    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
     717
     718    FUNCTION_PARSERS: t.Dict[str, t.Callable] = {
     719        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
     720        "CONCAT": lambda self: self._parse_concat(),
     721        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
     722        "DECODE": lambda self: self._parse_decode(),
     723        "EXTRACT": lambda self: self._parse_extract(),
     724        "JSON_OBJECT": lambda self: self._parse_json_object(),
     725        "LOG": lambda self: self._parse_logarithm(),
     726        "MATCH": lambda self: self._parse_match_against(),
     727        "OPENJSON": lambda self: self._parse_open_json(),
     728        "POSITION": lambda self: self._parse_position(),
     729        "SAFE_CAST": lambda self: self._parse_cast(False),
     730        "STRING_AGG": lambda self: self._parse_string_agg(),
     731        "SUBSTRING": lambda self: self._parse_substring(),
     732        "TRIM": lambda self: self._parse_trim(),
     733        "TRY_CAST": lambda self: self._parse_cast(False),
     734        "TRY_CONVERT": lambda self: self._parse_convert(False),
     735    }
     736
     737    QUERY_MODIFIER_PARSERS = {
     738        "joins": lambda self: list(iter(self._parse_join, None)),
     739        "laterals": lambda self: list(iter(self._parse_lateral, None)),
     740        "match": lambda self: self._parse_match_recognize(),
     741        "where": lambda self: self._parse_where(),
     742        "group": lambda self: self._parse_group(),
     743        "having": lambda self: self._parse_having(),
     744        "qualify": lambda self: self._parse_qualify(),
     745        "windows": lambda self: self._parse_window_clause(),
     746        "order": lambda self: self._parse_order(),
     747        "limit": lambda self: self._parse_limit(),
     748        "offset": lambda self: self._parse_offset(),
     749        "locks": lambda self: self._parse_locks(),
     750        "sample": lambda self: self._parse_table_sample(as_modifier=True),
     751    }
     752
     753    SET_PARSERS = {
     754        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
     755        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
     756        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
     757        "TRANSACTION": lambda self: self._parse_set_transaction(),
     758    }
     759
     760    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
     761
     762    TYPE_LITERAL_PARSERS: t.Dict[exp.DataType.Type, t.Callable] = {}
     763
     764    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
     765
     766    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
     767
     768    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
     769
     770    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
     771    TRANSACTION_CHARACTERISTICS = {
     772        "ISOLATION LEVEL REPEATABLE READ",
     773        "ISOLATION LEVEL READ COMMITTED",
     774        "ISOLATION LEVEL READ UNCOMMITTED",
     775        "ISOLATION LEVEL SERIALIZABLE",
     776        "READ WRITE",
     777        "READ ONLY",
     778    }
     779
     780    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
     781
     782    CLONE_KINDS = {"TIMESTAMP", "OFFSET", "STATEMENT"}
     783
     784    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
     785    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
     786    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
     787
     788    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
     789
     790    STRICT_CAST = True
     791
     792    CONCAT_NULL_OUTPUTS_STRING = False  # A NULL arg in CONCAT yields NULL by default
     793
     794    CONVERT_TYPE_FIRST = False
     795
     796    PREFIXED_PIVOT_COLUMNS = False
     797    IDENTIFY_PIVOT_STRINGS = False
     798
     799    LOG_BASE_FIRST = True
     800    LOG_DEFAULTS_TO_LN = False
     801
     802    __slots__ = (
     803        "error_level",
     804        "error_message_context",
     805        "max_errors",
     806        "sql",
     807        "errors",
     808        "_tokens",
     809        "_index",
     810        "_curr",
     811        "_next",
     812        "_prev",
     813        "_prev_comments",
     814    )
     815
     816    # Autofilled
     817    INDEX_OFFSET: int = 0
     818    UNNEST_COLUMN_ONLY: bool = False
     819    ALIAS_POST_TABLESAMPLE: bool = False
     820    STRICT_STRING_CONCAT = False
     821    NULL_ORDERING: str = "nulls_are_small"
     822    SHOW_TRIE: t.Dict = {}
     823    SET_TRIE: t.Dict = {}
     824    FORMAT_MAPPING: t.Dict[str, str] = {}
     825    FORMAT_TRIE: t.Dict = {}
     826    TIME_MAPPING: t.Dict[str, str] = {}
     827    TIME_TRIE: t.Dict = {}
     828
     829    def __init__(
     830        self,
     831        error_level: t.Optional[ErrorLevel] = None,
     832        error_message_context: int = 100,
     833        max_errors: int = 3,
     834    ):
     835        self.error_level = error_level or ErrorLevel.IMMEDIATE
     836        self.error_message_context = error_message_context
     837        self.max_errors = max_errors
     838        self.reset()
     839
     840    def reset(self):
     841        self.sql = ""
     842        self.errors = []
     843        self._tokens = []
     844        self._index = 0
     845        self._curr = None
     846        self._next = None
     847        self._prev = None
     848        self._prev_comments = None
     849
     850    def parse(
     851        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
     852    ) -> t.List[t.Optional[exp.Expression]]:
     853        """
     854        Parses a list of tokens and returns a list of syntax trees, one tree
     855        per parsed SQL statement.
     856
     857        Args:
     858            raw_tokens: The list of tokens.
     859            sql: The original SQL string, used to produce helpful debug messages.
     860
     861        Returns:
     862            The list of the produced syntax trees.
     863        """
     864        return self._parse(
     865            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
     866        )
     867
     868    def parse_into(
     869        self,
     870        expression_types: exp.IntoType,
     871        raw_tokens: t.List[Token],
     872        sql: t.Optional[str] = None,
     873    ) -> t.List[t.Optional[exp.Expression]]:
     874        """
     875        Parses a list of tokens into a given Expression type. If a collection of Expression
     876        types is given instead, this method will try to parse the token list into each one
     877        of them, stopping at the first for which the parsing succeeds.
     878
     879        Args:
     880            expression_types: The expression type(s) to try and parse the token list into.
     881            raw_tokens: The list of tokens.
     882            sql: The original SQL string, used to produce helpful debug messages.
     883
     884        Returns:
     885            The target Expression.
     886        """
     887        errors = []
     888        for expression_type in ensure_list(expression_types):
     889            parser = self.EXPRESSION_PARSERS.get(expression_type)
     890            if not parser:
     891                raise TypeError(f"No parser registered for {expression_type}")
     892
     893            try:
     894                return self._parse(parser, raw_tokens, sql)
     895            except ParseError as e:
     896                e.errors[0]["into_expression"] = expression_type
     897                errors.append(e)
     898
     899        raise ParseError(
     900            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
     901            errors=merge_errors(errors),
     902        ) from errors[-1]
     903
     904    def _parse(
     905        self,
     906        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
     907        raw_tokens: t.List[Token],
     908        sql: t.Optional[str] = None,
     909    ) -> t.List[t.Optional[exp.Expression]]:
     910        self.reset()
     911        self.sql = sql or ""
     912
     913        total = len(raw_tokens)
     914        chunks: t.List[t.List[Token]] = [[]]
     915
     916        for i, token in enumerate(raw_tokens):
     917            if token.token_type == TokenType.SEMICOLON:
     918                if i < total - 1:
     919                    chunks.append([])
     920            else:
     921                chunks[-1].append(token)
     922
     923        expressions = []
     924
     925        for tokens in chunks:
     926            self._index = -1
     927            self._tokens = tokens
     928            self._advance()
     929
     930            expressions.append(parse_method(self))
     931
     932            if self._index < len(self._tokens):
     933                self.raise_error("Invalid expression / Unexpected token")
     934
     935            self.check_errors()
     936
     937        return expressions
     938
     939    def check_errors(self) -> None:
     940        """Logs or raises any found errors, depending on the chosen error level setting."""
     941        if self.error_level == ErrorLevel.WARN:
     942            for error in self.errors:
     943                logger.error(str(error))
     944        elif self.error_level == ErrorLevel.RAISE and self.errors:
     945            raise ParseError(
     946                concat_messages(self.errors, self.max_errors),
     947                errors=merge_errors(self.errors),
     948            )
     949
     950    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
     951        """
     952        Appends an error in the list of recorded errors or raises it, depending on the chosen
     953        error level setting.
     954        """
     955        token = token or self._curr or self._prev or Token.string("")
     956        start = token.start
     957        end = token.end + 1
     958        start_context = self.sql[max(start - self.error_message_context, 0) : start]
     959        highlight = self.sql[start:end]
     960        end_context = self.sql[end : end + self.error_message_context]
     961
     962        error = ParseError.new(
     963            f"{message}. Line {token.line}, Col: {token.col}.\n"
     964            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
     965            description=message,
     966            line=token.line,
     967            col=token.col,
     968            start_context=start_context,
     969            highlight=highlight,
     970            end_context=end_context,
     971        )
     972
     973        if self.error_level == ErrorLevel.IMMEDIATE:
     974            raise error
     975
     976        self.errors.append(error)
     977
     978    def expression(
     979        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
     980    ) -> E:
     981        """
     982        Creates a new, validated Expression.
     983
     984        Args:
     985            exp_class: The expression class to instantiate.
     986            comments: An optional list of comments to attach to the expression.
     987            kwargs: The arguments to set for the expression along with their respective values.
     988
     989        Returns:
     990            The target expression.
     991        """
     992        instance = exp_class(**kwargs)
     993        instance.add_comments(comments) if comments else self._add_comments(instance)
     994        return self.validate_expression(instance)
     995
     996    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
     997        if expression and self._prev_comments:
     998            expression.add_comments(self._prev_comments)
     999            self._prev_comments = None
    1000
    1001    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1002        """
    1003        Validates an Expression, making sure that all its mandatory arguments are set.
    1004
    1005        Args:
    1006            expression: The expression to validate.
    1007            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1008
    1009        Returns:
    1010            The validated expression.
    1011        """
    1012        if self.error_level != ErrorLevel.IGNORE:
    1013            for error_message in expression.error_messages(args):
    1014                self.raise_error(error_message)
    1015
    1016        return expression
    1017
    1018    def _find_sql(self, start: Token, end: Token) -> str:
    1019        return self.sql[start.start : end.end + 1]
    1020
    1021    def _advance(self, times: int = 1) -> None:
    1022        self._index += times
    1023        self._curr = seq_get(self._tokens, self._index)
    1024        self._next = seq_get(self._tokens, self._index + 1)
    1025
    1026        if self._index > 0:
    1027            self._prev = self._tokens[self._index - 1]
    1028            self._prev_comments = self._prev.comments
    1029        else:
    1030            self._prev = None
    1031            self._prev_comments = None
    1032
    1033    def _retreat(self, index: int) -> None:
    1034        if index != self._index:
    1035            self._advance(index - self._index)
    1036
    1037    def _parse_command(self) -> exp.Command:
    1038        return self.expression(exp.Command, this=self._prev.text, expression=self._parse_string())
    1039
    1040    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1041        start = self._prev
    1042        exists = self._parse_exists() if allow_exists else None
    1043
    1044        self._match(TokenType.ON)
    1045
    1046        kind = self._match_set(self.CREATABLES) and self._prev
    1047        if not kind:
    1048            return self._parse_as_command(start)
    1049
    1050        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1051            this = self._parse_user_defined_function(kind=kind.token_type)
    1052        elif kind.token_type == TokenType.TABLE:
    1053            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1054        elif kind.token_type == TokenType.COLUMN:
    1055            this = self._parse_column()
    1056        else:
    1057            this = self._parse_id_var()
    1058
    1059        self._match(TokenType.IS)
    1060
    1061        return self.expression(
    1062            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
    1063        )
    1064
    1065    def _parse_to_table(
    1066        self,
    1067    ) -> exp.ToTableProperty:
    1068        table = self._parse_table_parts(schema=True)
    1069        return self.expression(exp.ToTableProperty, this=table)
    1070
    1071    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1072    def _parse_ttl(self) -> exp.Expression:
    1073        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1074            this = self._parse_bitwise()
    1075
    1076            if self._match_text_seq("DELETE"):
    1077                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1078            if self._match_text_seq("RECOMPRESS"):
    1079                return self.expression(
    1080                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1081                )
    1082            if self._match_text_seq("TO", "DISK"):
    1083                return self.expression(
    1084                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1085                )
    1086            if self._match_text_seq("TO", "VOLUME"):
    1087                return self.expression(
    1088                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1089                )
    1090
    1091            return this
    1092
    1093        expressions = self._parse_csv(_parse_ttl_action)
    1094        where = self._parse_where()
    1095        group = self._parse_group()
    1096
    1097        aggregates = None
    1098        if group and self._match(TokenType.SET):
    1099            aggregates = self._parse_csv(self._parse_set_item)
    1100
    1101        return self.expression(
    1102            exp.MergeTreeTTL,
    1103            expressions=expressions,
    1104            where=where,
    1105            group=group,
    1106            aggregates=aggregates,
    1107        )
    1108
    1109    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1110        if self._curr is None:
    1111            return None
    1112
    1113        if self._match_set(self.STATEMENT_PARSERS):
    1114            return self.STATEMENT_PARSERS[self._prev.token_type](self)
    1115
    1116        if self._match_set(Tokenizer.COMMANDS):
    1117            return self._parse_command()
    1118
    1119        expression = self._parse_expression()
    1120        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1121        return self._parse_query_modifiers(expression)
    1122
    1123    def _parse_drop(self) -> exp.Drop | exp.Command:
    1124        start = self._prev
    1125        temporary = self._match(TokenType.TEMPORARY)
    1126        materialized = self._match_text_seq("MATERIALIZED")
    1127
    1128        kind = self._match_set(self.CREATABLES) and self._prev.text
    1129        if not kind:
    1130            return self._parse_as_command(start)
    1131
    1132        return self.expression(
    1133            exp.Drop,
    1134            exists=self._parse_exists(),
    1135            this=self._parse_table(schema=True),
    1136            kind=kind,
    1137            temporary=temporary,
    1138            materialized=materialized,
    1139            cascade=self._match_text_seq("CASCADE"),
    1140            constraints=self._match_text_seq("CONSTRAINTS"),
    1141            purge=self._match_text_seq("PURGE"),
    1142        )
    1143
    1144    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1145        return (
    1146            self._match(TokenType.IF)
    1147            and (not not_ or self._match(TokenType.NOT))
    1148            and self._match(TokenType.EXISTS)
    1149        )
    1150
    1151    def _parse_create(self) -> exp.Create | exp.Command:
    1152        # Note: this can't be None because we've matched a statement parser
    1153        start = self._prev
    1154        replace = start.text.upper() == "REPLACE" or self._match_pair(
    1155            TokenType.OR, TokenType.REPLACE
    1156        )
    1157        unique = self._match(TokenType.UNIQUE)
    1158
    1159        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1160            self._advance()
    1161
    1162        properties = None
    1163        create_token = self._match_set(self.CREATABLES) and self._prev
    1164
    1165        if not create_token:
    1166            # exp.Properties.Location.POST_CREATE
    1167            properties = self._parse_properties()
    1168            create_token = self._match_set(self.CREATABLES) and self._prev
    1169
    1170            if not properties or not create_token:
    1171                return self._parse_as_command(start)
    1172
    1173        exists = self._parse_exists(not_=True)
    1174        this = None
    1175        expression = None
    1176        indexes = None
    1177        no_schema_binding = None
    1178        begin = None
    1179        clone = None
    1180
    1181        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1182            nonlocal properties
    1183            if properties and temp_props:
    1184                properties.expressions.extend(temp_props.expressions)
    1185            elif temp_props:
    1186                properties = temp_props
    1187
    1188        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1189            this = self._parse_user_defined_function(kind=create_token.token_type)
    1190
    1191            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1192            extend_props(self._parse_properties())
    1193
    1194            self._match(TokenType.ALIAS)
    1195            begin = self._match(TokenType.BEGIN)
    1196            return_ = self._match_text_seq("RETURN")
    1197            expression = self._parse_statement()
    1198
    1199            if return_:
    1200                expression = self.expression(exp.Return, this=expression)
    1201        elif create_token.token_type == TokenType.INDEX:
    1202            this = self._parse_index(index=self._parse_id_var())
    1203        elif create_token.token_type in self.DB_CREATABLES:
    1204            table_parts = self._parse_table_parts(schema=True)
    1205
    1206            # exp.Properties.Location.POST_NAME
    1207            self._match(TokenType.COMMA)
    1208            extend_props(self._parse_properties(before=True))
    1209
    1210            this = self._parse_schema(this=table_parts)
    1211
    1212            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1213            extend_props(self._parse_properties())
    1214
    1215            self._match(TokenType.ALIAS)
    1216            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1217                # exp.Properties.Location.POST_ALIAS
    1218                extend_props(self._parse_properties())
    1219
    1220            expression = self._parse_ddl_select()
    1221
    1222            if create_token.token_type == TokenType.TABLE:
    1223                indexes = []
    1224                while True:
    1225                    index = self._parse_index()
    1226
    1227                    # exp.Properties.Location.POST_EXPRESSION and POST_INDEX
    1228                    extend_props(self._parse_properties())
    1229
    1230                    if not index:
    1231                        break
    1232                    else:
    1233                        self._match(TokenType.COMMA)
    1234                        indexes.append(index)
    1235            elif create_token.token_type == TokenType.VIEW:
    1236                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1237                    no_schema_binding = True
    1238
    1239            if self._match_text_seq("CLONE"):
    1240                clone = self._parse_table(schema=True)
    1241                when = self._match_texts({"AT", "BEFORE"}) and self._prev.text.upper()
    1242                clone_kind = (
    1243                    self._match(TokenType.L_PAREN)
    1244                    and self._match_texts(self.CLONE_KINDS)
    1245                    and self._prev.text.upper()
    1246                )
    1247                clone_expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    1248                self._match(TokenType.R_PAREN)
    1249                clone = self.expression(
    1250                    exp.Clone, this=clone, when=when, kind=clone_kind, expression=clone_expression
    1251                )
    1252
    1253        return self.expression(
    1254            exp.Create,
    1255            this=this,
    1256            kind=create_token.text,
    1257            replace=replace,
    1258            unique=unique,
    1259            expression=expression,
    1260            exists=exists,
    1261            properties=properties,
    1262            indexes=indexes,
    1263            no_schema_binding=no_schema_binding,
    1264            begin=begin,
    1265            clone=clone,
    1266        )
    1267
    1268    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    1269        # only used for teradata currently
    1270        self._match(TokenType.COMMA)
    1271
    1272        kwargs = {
    1273            "no": self._match_text_seq("NO"),
    1274            "dual": self._match_text_seq("DUAL"),
    1275            "before": self._match_text_seq("BEFORE"),
    1276            "default": self._match_text_seq("DEFAULT"),
    1277            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    1278            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    1279            "after": self._match_text_seq("AFTER"),
    1280            "minimum": self._match_texts(("MIN", "MINIMUM")),
    1281            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    1282        }
    1283
    1284        if self._match_texts(self.PROPERTY_PARSERS):
    1285            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    1286            try:
    1287                return parser(self, **{k: v for k, v in kwargs.items() if v})
    1288            except TypeError:
    1289                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    1290
    1291        return None
    1292
    1293    def _parse_property(self) -> t.Optional[exp.Expression]:
    1294        if self._match_texts(self.PROPERTY_PARSERS):
    1295            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    1296
    1297        if self._match_pair(TokenType.DEFAULT, TokenType.CHARACTER_SET):
    1298            return self._parse_character_set(default=True)
    1299
    1300        if self._match_text_seq("COMPOUND", "SORTKEY"):
    1301            return self._parse_sortkey(compound=True)
    1302
    1303        if self._match_text_seq("SQL", "SECURITY"):
    1304            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    1305
    1306        assignment = self._match_pair(
    1307            TokenType.VAR, TokenType.EQ, advance=False
    1308        ) or self._match_pair(TokenType.STRING, TokenType.EQ, advance=False)
    1309
    1310        if assignment:
    1311            key = self._parse_var_or_string()
    1312            self._match(TokenType.EQ)
    1313            return self.expression(exp.Property, this=key, value=self._parse_column())
    1314
    1315        return None
    1316
    1317    def _parse_stored(self) -> exp.FileFormatProperty:
    1318        self._match(TokenType.ALIAS)
    1319
    1320        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    1321        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    1322
    1323        return self.expression(
    1324            exp.FileFormatProperty,
    1325            this=self.expression(
    1326                exp.InputOutputFormat, input_format=input_format, output_format=output_format
    1327            )
    1328            if input_format or output_format
    1329            else self._parse_var_or_string() or self._parse_number() or self._parse_id_var(),
    1330        )
    1331
    1332    def _parse_property_assignment(self, exp_class: t.Type[E]) -> E:
    1333        self._match(TokenType.EQ)
    1334        self._match(TokenType.ALIAS)
    1335        return self.expression(exp_class, this=self._parse_field())
    1336
    1337    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    1338        properties = []
    1339        while True:
    1340            if before:
    1341                prop = self._parse_property_before()
    1342            else:
    1343                prop = self._parse_property()
    1344
    1345            if not prop:
    1346                break
    1347            for p in ensure_list(prop):
    1348                properties.append(p)
    1349
    1350        if properties:
    1351            return self.expression(exp.Properties, expressions=properties)
    1352
    1353        return None
    1354
    1355    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    1356        return self.expression(
    1357            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    1358        )
    1359
    1360    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    1361        if self._index >= 2:
    1362            pre_volatile_token = self._tokens[self._index - 2]
    1363        else:
    1364            pre_volatile_token = None
    1365
    1366        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    1367            return exp.VolatileProperty()
    1368
    1369        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    1370
    1371    def _parse_with_property(
    1372        self,
    1373    ) -> t.Optional[exp.Expression] | t.List[t.Optional[exp.Expression]]:
    1374        self._match(TokenType.WITH)
    1375        if self._match(TokenType.L_PAREN, advance=False):
    1376            return self._parse_wrapped_csv(self._parse_property)
    1377
    1378        if self._match_text_seq("JOURNAL"):
    1379            return self._parse_withjournaltable()
    1380
    1381        if self._match_text_seq("DATA"):
    1382            return self._parse_withdata(no=False)
    1383        elif self._match_text_seq("NO", "DATA"):
    1384            return self._parse_withdata(no=True)
    1385
    1386        if not self._next:
    1387            return None
    1388
    1389        return self._parse_withisolatedloading()
    1390
    1391    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    1392    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    1393        self._match(TokenType.EQ)
    1394
    1395        user = self._parse_id_var()
    1396        self._match(TokenType.PARAMETER)
    1397        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    1398
    1399        if not user or not host:
    1400            return None
    1401
    1402        return exp.DefinerProperty(this=f"{user}@{host}")
    1403
    1404    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    1405        self._match(TokenType.TABLE)
    1406        self._match(TokenType.EQ)
    1407        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    1408
    1409    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    1410        return self.expression(exp.LogProperty, no=no)
    1411
    1412    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    1413        return self.expression(exp.JournalProperty, **kwargs)
    1414
    1415    def _parse_checksum(self) -> exp.ChecksumProperty:
    1416        self._match(TokenType.EQ)
    1417
    1418        on = None
    1419        if self._match(TokenType.ON):
    1420            on = True
    1421        elif self._match_text_seq("OFF"):
    1422            on = False
    1423
    1424        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    1425
    1426    def _parse_cluster(self) -> t.Optional[exp.Cluster]:
    1427        if not self._match_text_seq("BY"):
    1428            self._retreat(self._index - 1)
    1429            return None
    1430
    1431        return self.expression(exp.Cluster, expressions=self._parse_csv(self._parse_ordered))
    1432
    1433    def _parse_freespace(self) -> exp.FreespaceProperty:
    1434        self._match(TokenType.EQ)
    1435        return self.expression(
    1436            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    1437        )
    1438
    1439    def _parse_mergeblockratio(
    1440        self, no: bool = False, default: bool = False
    1441    ) -> exp.MergeBlockRatioProperty:
    1442        if self._match(TokenType.EQ):
    1443            return self.expression(
    1444                exp.MergeBlockRatioProperty,
    1445                this=self._parse_number(),
    1446                percent=self._match(TokenType.PERCENT),
    1447            )
    1448
    1449        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    1450
    1451    def _parse_datablocksize(
    1452        self,
    1453        default: t.Optional[bool] = None,
    1454        minimum: t.Optional[bool] = None,
    1455        maximum: t.Optional[bool] = None,
    1456    ) -> exp.DataBlocksizeProperty:
    1457        self._match(TokenType.EQ)
    1458        size = self._parse_number()
    1459
    1460        units = None
    1461        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    1462            units = self._prev.text
    1463
    1464        return self.expression(
    1465            exp.DataBlocksizeProperty,
    1466            size=size,
    1467            units=units,
    1468            default=default,
    1469            minimum=minimum,
    1470            maximum=maximum,
    1471        )
    1472
    1473    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    1474        self._match(TokenType.EQ)
    1475        always = self._match_text_seq("ALWAYS")
    1476        manual = self._match_text_seq("MANUAL")
    1477        never = self._match_text_seq("NEVER")
    1478        default = self._match_text_seq("DEFAULT")
    1479
    1480        autotemp = None
    1481        if self._match_text_seq("AUTOTEMP"):
    1482            autotemp = self._parse_schema()
    1483
    1484        return self.expression(
    1485            exp.BlockCompressionProperty,
    1486            always=always,
    1487            manual=manual,
    1488            never=never,
    1489            default=default,
    1490            autotemp=autotemp,
    1491        )
    1492
    1493    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
    1494        no = self._match_text_seq("NO")
    1495        concurrent = self._match_text_seq("CONCURRENT")
    1496        self._match_text_seq("ISOLATED", "LOADING")
    1497        for_all = self._match_text_seq("FOR", "ALL")
    1498        for_insert = self._match_text_seq("FOR", "INSERT")
    1499        for_none = self._match_text_seq("FOR", "NONE")
    1500        return self.expression(
    1501            exp.IsolatedLoadingProperty,
    1502            no=no,
    1503            concurrent=concurrent,
    1504            for_all=for_all,
    1505            for_insert=for_insert,
    1506            for_none=for_none,
    1507        )
    1508
    1509    def _parse_locking(self) -> exp.LockingProperty:
    1510        if self._match(TokenType.TABLE):
    1511            kind = "TABLE"
    1512        elif self._match(TokenType.VIEW):
    1513            kind = "VIEW"
    1514        elif self._match(TokenType.ROW):
    1515            kind = "ROW"
    1516        elif self._match_text_seq("DATABASE"):
    1517            kind = "DATABASE"
    1518        else:
    1519            kind = None
    1520
    1521        if kind in ("DATABASE", "TABLE", "VIEW"):
    1522            this = self._parse_table_parts()
    1523        else:
    1524            this = None
    1525
    1526        if self._match(TokenType.FOR):
    1527            for_or_in = "FOR"
    1528        elif self._match(TokenType.IN):
    1529            for_or_in = "IN"
    1530        else:
    1531            for_or_in = None
    1532
    1533        if self._match_text_seq("ACCESS"):
    1534            lock_type = "ACCESS"
    1535        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    1536            lock_type = "EXCLUSIVE"
    1537        elif self._match_text_seq("SHARE"):
    1538            lock_type = "SHARE"
    1539        elif self._match_text_seq("READ"):
    1540            lock_type = "READ"
    1541        elif self._match_text_seq("WRITE"):
    1542            lock_type = "WRITE"
    1543        elif self._match_text_seq("CHECKSUM"):
    1544            lock_type = "CHECKSUM"
    1545        else:
    1546            lock_type = None
    1547
    1548        override = self._match_text_seq("OVERRIDE")
    1549
    1550        return self.expression(
    1551            exp.LockingProperty,
    1552            this=this,
    1553            kind=kind,
    1554            for_or_in=for_or_in,
    1555            lock_type=lock_type,
    1556            override=override,
    1557        )
    1558
    1559    def _parse_partition_by(self) -> t.List[t.Optional[exp.Expression]]:
    1560        if self._match(TokenType.PARTITION_BY):
    1561            return self._parse_csv(self._parse_conjunction)
    1562        return []
    1563
    1564    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    1565        self._match(TokenType.EQ)
    1566        return self.expression(
    1567            exp.PartitionedByProperty,
    1568            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    1569        )
    1570
    1571    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    1572        if self._match_text_seq("AND", "STATISTICS"):
    1573            statistics = True
    1574        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    1575            statistics = False
    1576        else:
    1577            statistics = None
    1578
    1579        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    1580
    1581    def _parse_no_property(self) -> t.Optional[exp.NoPrimaryIndexProperty]:
    1582        if self._match_text_seq("PRIMARY", "INDEX"):
    1583            return exp.NoPrimaryIndexProperty()
    1584        return None
    1585
    1586    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    1587        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    1588            return exp.OnCommitProperty()
    1589        elif self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    1590            return exp.OnCommitProperty(delete=True)
    1591        return None
    1592
    1593    def _parse_distkey(self) -> exp.DistKeyProperty:
    1594        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    1595
    1596    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    1597        table = self._parse_table(schema=True)
    1598
    1599        options = []
    1600        while self._match_texts(("INCLUDING", "EXCLUDING")):
    1601            this = self._prev.text.upper()
    1602
    1603            id_var = self._parse_id_var()
    1604            if not id_var:
    1605                return None
    1606
    1607            options.append(
    1608                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    1609            )
    1610
    1611        return self.expression(exp.LikeProperty, this=table, expressions=options)
    1612
    1613    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    1614        return self.expression(
    1615            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    1616        )
    1617
    1618    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    1619        self._match(TokenType.EQ)
    1620        return self.expression(
    1621            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    1622        )
    1623
    1624    def _parse_returns(self) -> exp.ReturnsProperty:
    1625        value: t.Optional[exp.Expression]
    1626        is_table = self._match(TokenType.TABLE)
    1627
    1628        if is_table:
    1629            if self._match(TokenType.LT):
    1630                value = self.expression(
    1631                    exp.Schema,
    1632                    this="TABLE",
    1633                    expressions=self._parse_csv(self._parse_struct_types),
    1634                )
    1635                if not self._match(TokenType.GT):
    1636                    self.raise_error("Expecting >")
    1637            else:
    1638                value = self._parse_schema(exp.var("TABLE"))
    1639        else:
    1640            value = self._parse_types()
    1641
    1642        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
    1643
    1644    def _parse_describe(self) -> exp.Describe:
    1645        kind = self._match_set(self.CREATABLES) and self._prev.text
    1646        this = self._parse_table()
    1647        return self.expression(exp.Describe, this=this, kind=kind)
    1648
    1649    def _parse_insert(self) -> exp.Insert:
    1650        overwrite = self._match(TokenType.OVERWRITE)
    1651        local = self._match_text_seq("LOCAL")
    1652        alternative = None
    1653
    1654        if self._match_text_seq("DIRECTORY"):
    1655            this: t.Optional[exp.Expression] = self.expression(
    1656                exp.Directory,
    1657                this=self._parse_var_or_string(),
    1658                local=local,
    1659                row_format=self._parse_row_format(match_row=True),
    1660            )
    1661        else:
    1662            if self._match(TokenType.OR):
    1663                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    1664
    1665            self._match(TokenType.INTO)
    1666            self._match(TokenType.TABLE)
    1667            this = self._parse_table(schema=True)
    1668
    1669        return self.expression(
    1670            exp.Insert,
    1671            this=this,
    1672            exists=self._parse_exists(),
    1673            partition=self._parse_partition(),
    1674            expression=self._parse_ddl_select(),
    1675            conflict=self._parse_on_conflict(),
    1676            returning=self._parse_returning(),
    1677            overwrite=overwrite,
    1678            alternative=alternative,
    1679        )
    1680
    1681    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    1682        conflict = self._match_text_seq("ON", "CONFLICT")
    1683        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    1684
    1685        if not conflict and not duplicate:
    1686            return None
    1687
    1688        nothing = None
    1689        expressions = None
    1690        key = None
    1691        constraint = None
    1692
    1693        if conflict:
    1694            if self._match_text_seq("ON", "CONSTRAINT"):
    1695                constraint = self._parse_id_var()
    1696            else:
    1697                key = self._parse_csv(self._parse_value)
    1698
    1699        self._match_text_seq("DO")
    1700        if self._match_text_seq("NOTHING"):
    1701            nothing = True
    1702        else:
    1703            self._match(TokenType.UPDATE)
    1704            expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    1705
    1706        return self.expression(
    1707            exp.OnConflict,
    1708            duplicate=duplicate,
    1709            expressions=expressions,
    1710            nothing=nothing,
    1711            key=key,
    1712            constraint=constraint,
    1713        )
    1714
    1715    def _parse_returning(self) -> t.Optional[exp.Returning]:
    1716        if not self._match(TokenType.RETURNING):
    1717            return None
    1718
    1719        return self.expression(exp.Returning, expressions=self._parse_csv(self._parse_column))
    1720
    1721    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    1722        if not self._match(TokenType.FORMAT):
    1723            return None
    1724        return self._parse_row_format()
    1725
    1726    def _parse_row_format(
    1727        self, match_row: bool = False
    1728    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    1729        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    1730            return None
    1731
    1732        if self._match_text_seq("SERDE"):
    1733            return self.expression(exp.RowFormatSerdeProperty, this=self._parse_string())
    1734
    1735        self._match_text_seq("DELIMITED")
    1736
    1737        kwargs = {}
    1738
    1739        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    1740            kwargs["fields"] = self._parse_string()
    1741            if self._match_text_seq("ESCAPED", "BY"):
    1742                kwargs["escaped"] = self._parse_string()
    1743        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    1744            kwargs["collection_items"] = self._parse_string()
    1745        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    1746            kwargs["map_keys"] = self._parse_string()
    1747        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    1748            kwargs["lines"] = self._parse_string()
    1749        if self._match_text_seq("NULL", "DEFINED", "AS"):
    1750            kwargs["null"] = self._parse_string()
    1751
    1752        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    1753
    1754    def _parse_load(self) -> exp.LoadData | exp.Command:
    1755        if self._match_text_seq("DATA"):
    1756            local = self._match_text_seq("LOCAL")
    1757            self._match_text_seq("INPATH")
    1758            inpath = self._parse_string()
    1759            overwrite = self._match(TokenType.OVERWRITE)
    1760            self._match_pair(TokenType.INTO, TokenType.TABLE)
    1761
    1762            return self.expression(
    1763                exp.LoadData,
    1764                this=self._parse_table(schema=True),
    1765                local=local,
    1766                overwrite=overwrite,
    1767                inpath=inpath,
    1768                partition=self._parse_partition(),
    1769                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    1770                serde=self._match_text_seq("SERDE") and self._parse_string(),
    1771            )
    1772        return self._parse_as_command(self._prev)
    1773
    1774    def _parse_delete(self) -> exp.Delete:
    1775        self._match(TokenType.FROM)
    1776
    1777        return self.expression(
    1778            exp.Delete,
    1779            this=self._parse_table(),
    1780            using=self._parse_csv(lambda: self._match(TokenType.USING) and self._parse_table()),
    1781            where=self._parse_where(),
    1782            returning=self._parse_returning(),
    1783        )
    1784
    1785    def _parse_update(self) -> exp.Update:
    1786        return self.expression(
    1787            exp.Update,
    1788            **{  # type: ignore
    1789                "this": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),
    1790                "expressions": self._match(TokenType.SET) and self._parse_csv(self._parse_equality),
    1791                "from": self._parse_from(modifiers=True),
    1792                "where": self._parse_where(),
    1793                "returning": self._parse_returning(),
    1794            },
    1795        )
    1796
    1797    def _parse_uncache(self) -> exp.Uncache:
    1798        if not self._match(TokenType.TABLE):
    1799            self.raise_error("Expecting TABLE after UNCACHE")
    1800
    1801        return self.expression(
    1802            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    1803        )
    1804
    1805    def _parse_cache(self) -> exp.Cache:
    1806        lazy = self._match_text_seq("LAZY")
    1807        self._match(TokenType.TABLE)
    1808        table = self._parse_table(schema=True)
    1809
    1810        options = []
    1811        if self._match_text_seq("OPTIONS"):
    1812            self._match_l_paren()
    1813            k = self._parse_string()
    1814            self._match(TokenType.EQ)
    1815            v = self._parse_string()
    1816            options = [k, v]
    1817            self._match_r_paren()
    1818
    1819        self._match(TokenType.ALIAS)
    1820        return self.expression(
    1821            exp.Cache,
    1822            this=table,
    1823            lazy=lazy,
    1824            options=options,
    1825            expression=self._parse_select(nested=True),
    1826        )
    1827
    1828    def _parse_partition(self) -> t.Optional[exp.Partition]:
    1829        if not self._match(TokenType.PARTITION):
    1830            return None
    1831
    1832        return self.expression(
    1833            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
    1834        )
    1835
    1836    def _parse_value(self) -> exp.Tuple:
    1837        if self._match(TokenType.L_PAREN):
    1838            expressions = self._parse_csv(self._parse_conjunction)
    1839            self._match_r_paren()
    1840            return self.expression(exp.Tuple, expressions=expressions)
    1841
    1842        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
    1843        # Source: https://prestodb.io/docs/current/sql/values.html
    1844        return self.expression(exp.Tuple, expressions=[self._parse_conjunction()])
    1845
    1846    def _parse_select(
    1847        self, nested: bool = False, table: bool = False, parse_subquery_alias: bool = True
    1848    ) -> t.Optional[exp.Expression]:
    1849        cte = self._parse_with()
    1850        if cte:
    1851            this = self._parse_statement()
    1852
    1853            if not this:
    1854                self.raise_error("Failed to parse any statement following CTE")
    1855                return cte
    1856
    1857            if "with" in this.arg_types:
    1858                this.set("with", cte)
    1859            else:
    1860                self.raise_error(f"{this.key} does not support CTE")
    1861                this = cte
    1862        elif self._match(TokenType.SELECT):
    1863            comments = self._prev_comments
    1864
    1865            hint = self._parse_hint()
    1866            all_ = self._match(TokenType.ALL)
    1867            distinct = self._match(TokenType.DISTINCT)
    1868
    1869            kind = (
    1870                self._match(TokenType.ALIAS)
    1871                and self._match_texts(("STRUCT", "VALUE"))
    1872                and self._prev.text
    1873            )
    1874
    1875            if distinct:
    1876                distinct = self.expression(
    1877                    exp.Distinct,
    1878                    on=self._parse_value() if self._match(TokenType.ON) else None,
    1879                )
    1880
    1881            if all_ and distinct:
    1882                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    1883
    1884            limit = self._parse_limit(top=True)
    1885            expressions = self._parse_csv(self._parse_expression)
    1886
    1887            this = self.expression(
    1888                exp.Select,
    1889                kind=kind,
    1890                hint=hint,
    1891                distinct=distinct,
    1892                expressions=expressions,
    1893                limit=limit,
    1894            )
    1895            this.comments = comments
    1896
    1897            into = self._parse_into()
    1898            if into:
    1899                this.set("into", into)
    1900
    1901            from_ = self._parse_from()
    1902            if from_:
    1903                this.set("from", from_)
    1904
    1905            this = self._parse_query_modifiers(this)
    1906        elif (table or nested) and self._match(TokenType.L_PAREN):
    1907            if self._match(TokenType.PIVOT):
    1908                this = self._parse_simplified_pivot()
    1909            elif self._match(TokenType.FROM):
    1910                this = exp.select("*").from_(
    1911                    t.cast(exp.From, self._parse_from(skip_from_token=True))
    1912                )
    1913            else:
    1914                this = self._parse_table() if table else self._parse_select(nested=True)
    1915                this = self._parse_set_operations(self._parse_query_modifiers(this))
    1916
    1917            self._match_r_paren()
    1918
    1919            # early return so that subquery unions aren't parsed again
    1920            # SELECT * FROM (SELECT 1) UNION ALL SELECT 1
    1921            # Union ALL should be a property of the top select node, not the subquery
    1922            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    1923        elif self._match(TokenType.VALUES):
    1924            this = self.expression(
    1925                exp.Values,
    1926                expressions=self._parse_csv(self._parse_value),
    1927                alias=self._parse_table_alias(),
    1928            )
    1929        else:
    1930            this = None
    1931
    1932        return self._parse_set_operations(this)
    1933
    1934    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    1935        if not skip_with_token and not self._match(TokenType.WITH):
    1936            return None
    1937
    1938        comments = self._prev_comments
    1939        recursive = self._match(TokenType.RECURSIVE)
    1940
    1941        expressions = []
    1942        while True:
    1943            expressions.append(self._parse_cte())
    1944
    1945            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    1946                break
    1947            else:
    1948                self._match(TokenType.WITH)
    1949
    1950        return self.expression(
    1951            exp.With, comments=comments, expressions=expressions, recursive=recursive
    1952        )
    1953
    1954    def _parse_cte(self) -> exp.CTE:
    1955        alias = self._parse_table_alias()
    1956        if not alias or not alias.this:
    1957            self.raise_error("Expected CTE to have alias")
    1958
    1959        self._match(TokenType.ALIAS)
    1960        return self.expression(
    1961            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
    1962        )
    1963
    1964    def _parse_table_alias(
    1965        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    1966    ) -> t.Optional[exp.TableAlias]:
    1967        any_token = self._match(TokenType.ALIAS)
    1968        alias = (
    1969            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    1970            or self._parse_string_as_identifier()
    1971        )
    1972
    1973        index = self._index
    1974        if self._match(TokenType.L_PAREN):
    1975            columns = self._parse_csv(self._parse_function_parameter)
    1976            self._match_r_paren() if columns else self._retreat(index)
    1977        else:
    1978            columns = None
    1979
    1980        if not alias and not columns:
    1981            return None
    1982
    1983        return self.expression(exp.TableAlias, this=alias, columns=columns)
    1984
    1985    def _parse_subquery(
    1986        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    1987    ) -> t.Optional[exp.Subquery]:
    1988        if not this:
    1989            return None
    1990
    1991        return self.expression(
    1992            exp.Subquery,
    1993            this=this,
    1994            pivots=self._parse_pivots(),
    1995            alias=self._parse_table_alias() if parse_alias else None,
    1996        )
    1997
    1998    def _parse_query_modifiers(
    1999        self, this: t.Optional[exp.Expression]
    2000    ) -> t.Optional[exp.Expression]:
    2001        if isinstance(this, self.MODIFIABLES):
    2002            for key, parser in self.QUERY_MODIFIER_PARSERS.items():
    2003                expression = parser(self)
    2004
    2005                if expression:
    2006                    if key == "limit":
    2007                        offset = expression.args.pop("offset", None)
    2008                        if offset:
    2009                            this.set("offset", exp.Offset(expression=offset))
    2010                    this.set(key, expression)
    2011        return this
    2012
    2013    def _parse_hint(self) -> t.Optional[exp.Hint]:
    2014        if self._match(TokenType.HINT):
    2015            hints = self._parse_csv(self._parse_function)
    2016
    2017            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
    2018                self.raise_error("Expected */ after HINT")
    2019
    2020            return self.expression(exp.Hint, expressions=hints)
    2021
    2022        return None
    2023
    2024    def _parse_into(self) -> t.Optional[exp.Into]:
    2025        if not self._match(TokenType.INTO):
    2026            return None
    2027
    2028        temp = self._match(TokenType.TEMPORARY)
    2029        unlogged = self._match_text_seq("UNLOGGED")
    2030        self._match(TokenType.TABLE)
    2031
    2032        return self.expression(
    2033            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    2034        )
    2035
    2036    def _parse_from(
    2037        self, modifiers: bool = False, skip_from_token: bool = False
    2038    ) -> t.Optional[exp.From]:
    2039        if not skip_from_token and not self._match(TokenType.FROM):
    2040            return None
    2041
    2042        comments = self._prev_comments
    2043        this = self._parse_table()
    2044
    2045        return self.expression(
    2046            exp.From,
    2047            comments=comments,
    2048            this=self._parse_query_modifiers(this) if modifiers else this,
    2049        )
    2050
    2051    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    2052        if not self._match(TokenType.MATCH_RECOGNIZE):
    2053            return None
    2054
    2055        self._match_l_paren()
    2056
    2057        partition = self._parse_partition_by()
    2058        order = self._parse_order()
    2059        measures = (
    2060            self._parse_csv(self._parse_expression) if self._match_text_seq("MEASURES") else None
    2061        )
    2062
    2063        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    2064            rows = exp.var("ONE ROW PER MATCH")
    2065        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    2066            text = "ALL ROWS PER MATCH"
    2067            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    2068                text += f" SHOW EMPTY MATCHES"
    2069            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    2070                text += f" OMIT EMPTY MATCHES"
    2071            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    2072                text += f" WITH UNMATCHED ROWS"
    2073            rows = exp.var(text)
    2074        else:
    2075            rows = None
    2076
    2077        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    2078            text = "AFTER MATCH SKIP"
    2079            if self._match_text_seq("PAST", "LAST", "ROW"):
    2080                text += f" PAST LAST ROW"
    2081            elif self._match_text_seq("TO", "NEXT", "ROW"):
    2082                text += f" TO NEXT ROW"
    2083            elif self._match_text_seq("TO", "FIRST"):
    2084                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    2085            elif self._match_text_seq("TO", "LAST"):
    2086                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    2087            after = exp.var(text)
    2088        else:
    2089            after = None
    2090
    2091        if self._match_text_seq("PATTERN"):
    2092            self._match_l_paren()
    2093
    2094            if not self._curr:
    2095                self.raise_error("Expecting )", self._curr)
    2096
    2097            paren = 1
    2098            start = self._curr
    2099
    2100            while self._curr and paren > 0:
    2101                if self._curr.token_type == TokenType.L_PAREN:
    2102                    paren += 1
    2103                if self._curr.token_type == TokenType.R_PAREN:
    2104                    paren -= 1
    2105
    2106                end = self._prev
    2107                self._advance()
    2108
    2109            if paren > 0:
    2110                self.raise_error("Expecting )", self._curr)
    2111
    2112            pattern = exp.var(self._find_sql(start, end))
    2113        else:
    2114            pattern = None
    2115
    2116        define = (
    2117            self._parse_csv(
    2118                lambda: self.expression(
    2119                    exp.Alias,
    2120                    alias=self._parse_id_var(any_token=True),
    2121                    this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
    2122                )
    2123            )
    2124            if self._match_text_seq("DEFINE")
    2125            else None
    2126        )
    2127
    2128        self._match_r_paren()
    2129
    2130        return self.expression(
    2131            exp.MatchRecognize,
    2132            partition_by=partition,
    2133            order=order,
    2134            measures=measures,
    2135            rows=rows,
    2136            after=after,
    2137            pattern=pattern,
    2138            define=define,
    2139            alias=self._parse_table_alias(),
    2140        )
    2141
    2142    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    2143        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY)
    2144        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    2145
    2146        if outer_apply or cross_apply:
    2147            this = self._parse_select(table=True)
    2148            view = None
    2149            outer = not cross_apply
    2150        elif self._match(TokenType.LATERAL):
    2151            this = self._parse_select(table=True)
    2152            view = self._match(TokenType.VIEW)
    2153            outer = self._match(TokenType.OUTER)
    2154        else:
    2155            return None
    2156
    2157        if not this:
    2158            this = self._parse_function() or self._parse_id_var(any_token=False)
    2159            while self._match(TokenType.DOT):
    2160                this = exp.Dot(
    2161                    this=this,
    2162                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    2163                )
    2164
    2165        if view:
    2166            table = self._parse_id_var(any_token=False)
    2167            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    2168            table_alias: t.Optional[exp.TableAlias] = self.expression(
    2169                exp.TableAlias, this=table, columns=columns
    2170            )
    2171        elif isinstance(this, exp.Subquery) and this.alias:
    2172            # Ensures parity between the Subquery's and the Lateral's "alias" args
    2173            table_alias = this.args["alias"].copy()
    2174        else:
    2175            table_alias = self._parse_table_alias()
    2176
    2177        return self.expression(exp.Lateral, this=this, view=view, outer=outer, alias=table_alias)
    2178
    2179    def _parse_join_parts(
    2180        self,
    2181    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    2182        return (
    2183            self._match_set(self.JOIN_METHODS) and self._prev,
    2184            self._match_set(self.JOIN_SIDES) and self._prev,
    2185            self._match_set(self.JOIN_KINDS) and self._prev,
    2186        )
    2187
    2188    def _parse_join(self, skip_join_token: bool = False) -> t.Optional[exp.Join]:
    2189        if self._match(TokenType.COMMA):
    2190            return self.expression(exp.Join, this=self._parse_table())
    2191
    2192        index = self._index
    2193        method, side, kind = self._parse_join_parts()
    2194        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    2195        join = self._match(TokenType.JOIN)
    2196
    2197        if not skip_join_token and not join:
    2198            self._retreat(index)
    2199            kind = None
    2200            method = None
    2201            side = None
    2202
    2203        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    2204        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    2205
    2206        if not skip_join_token and not join and not outer_apply and not cross_apply:
    2207            return None
    2208
    2209        if outer_apply:
    2210            side = Token(TokenType.LEFT, "LEFT")
    2211
    2212        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table()}
    2213
    2214        if method:
    2215            kwargs["method"] = method.text
    2216        if side:
    2217            kwargs["side"] = side.text
    2218        if kind:
    2219            kwargs["kind"] = kind.text
    2220        if hint:
    2221            kwargs["hint"] = hint
    2222
    2223        if self._match(TokenType.ON):
    2224            kwargs["on"] = self._parse_conjunction()
    2225        elif self._match(TokenType.USING):
    2226            kwargs["using"] = self._parse_wrapped_id_vars()
    2227
    2228        return self.expression(exp.Join, **kwargs)
    2229
    2230    def _parse_index(
    2231        self,
    2232        index: t.Optional[exp.Expression] = None,
    2233    ) -> t.Optional[exp.Index]:
    2234        if index:
    2235            unique = None
    2236            primary = None
    2237            amp = None
    2238
    2239            self._match(TokenType.ON)
    2240            self._match(TokenType.TABLE)  # hive
    2241            table = self._parse_table_parts(schema=True)
    2242        else:
    2243            unique = self._match(TokenType.UNIQUE)
    2244            primary = self._match_text_seq("PRIMARY")
    2245            amp = self._match_text_seq("AMP")
    2246
    2247            if not self._match(TokenType.INDEX):
    2248                return None
    2249
    2250            index = self._parse_id_var()
    2251            table = None
    2252
    2253        using = self._parse_field() if self._match(TokenType.USING) else None
    2254
    2255        if self._match(TokenType.L_PAREN, advance=False):
    2256            columns = self._parse_wrapped_csv(self._parse_ordered)
    2257        else:
    2258            columns = None
    2259
    2260        return self.expression(
    2261            exp.Index,
    2262            this=index,
    2263            table=table,
    2264            using=using,
    2265            columns=columns,
    2266            unique=unique,
    2267            primary=primary,
    2268            amp=amp,
    2269            partition_by=self._parse_partition_by(),
    2270        )
    2271
    2272    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    2273        return (
    2274            (not schema and self._parse_function(optional_parens=False))
    2275            or self._parse_id_var(any_token=False)
    2276            or self._parse_string_as_identifier()
    2277            or self._parse_placeholder()
    2278        )
    2279
    2280    def _parse_table_parts(self, schema: bool = False) -> exp.Table:
    2281        catalog = None
    2282        db = None
    2283        table = self._parse_table_part(schema=schema)
    2284
    2285        while self._match(TokenType.DOT):
    2286            if catalog:
    2287                # This allows nesting the table in arbitrarily many dot expressions if needed
    2288                table = self.expression(
    2289                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    2290                )
    2291            else:
    2292                catalog = db
    2293                db = table
    2294                table = self._parse_table_part(schema=schema)
    2295
    2296        if not table:
    2297            self.raise_error(f"Expected table name but got {self._curr}")
    2298
    2299        return self.expression(
    2300            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
    2301        )
    2302
    2303    def _parse_table(
    2304        self, schema: bool = False, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    2305    ) -> t.Optional[exp.Expression]:
    2306        lateral = self._parse_lateral()
    2307        if lateral:
    2308            return lateral
    2309
    2310        unnest = self._parse_unnest()
    2311        if unnest:
    2312            return unnest
    2313
    2314        values = self._parse_derived_table_values()
    2315        if values:
    2316            return values
    2317
    2318        subquery = self._parse_select(table=True)
    2319        if subquery:
    2320            if not subquery.args.get("pivots"):
    2321                subquery.set("pivots", self._parse_pivots())
    2322            return subquery
    2323
    2324        this: exp.Expression = self._parse_table_parts(schema=schema)
    2325
    2326        if schema:
    2327            return self._parse_schema(this=this)
    2328
    2329        if self.ALIAS_POST_TABLESAMPLE:
    2330            table_sample = self._parse_table_sample()
    2331
    2332        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    2333        if alias:
    2334            this.set("alias", alias)
    2335
    2336        if not this.args.get("pivots"):
    2337            this.set("pivots", self._parse_pivots())
    2338
    2339        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    2340            this.set(
    2341                "hints",
    2342                self._parse_csv(lambda: self._parse_function() or self._parse_var(any_token=True)),
    2343            )
    2344            self._match_r_paren()
    2345
    2346        if not self.ALIAS_POST_TABLESAMPLE:
    2347            table_sample = self._parse_table_sample()
    2348
    2349        if table_sample:
    2350            table_sample.set("this", this)
    2351            this = table_sample
    2352
    2353        return this
    2354
    2355    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    2356        if not self._match(TokenType.UNNEST):
    2357            return None
    2358
    2359        expressions = self._parse_wrapped_csv(self._parse_type)
    2360        ordinality = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    2361
    2362        alias = self._parse_table_alias() if with_alias else None
    2363
    2364        if alias and self.UNNEST_COLUMN_ONLY:
    2365            if alias.args.get("columns"):
    2366                self.raise_error("Unexpected extra column alias in unnest.")
    2367
    2368            alias.set("columns", [alias.this])
    2369            alias.set("this", None)
    2370
    2371        offset = None
    2372        if self._match_pair(TokenType.WITH, TokenType.OFFSET):
    2373            self._match(TokenType.ALIAS)
    2374            offset = self._parse_id_var() or exp.to_identifier("offset")
    2375
    2376        return self.expression(
    2377            exp.Unnest, expressions=expressions, ordinality=ordinality, alias=alias, offset=offset
    2378        )
    2379
    2380    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    2381        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    2382        if not is_derived and not self._match(TokenType.VALUES):
    2383            return None
    2384
    2385        expressions = self._parse_csv(self._parse_value)
    2386        alias = self._parse_table_alias()
    2387
    2388        if is_derived:
    2389            self._match_r_paren()
    2390
    2391        return self.expression(
    2392            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    2393        )
    2394
    2395    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    2396        if not self._match(TokenType.TABLE_SAMPLE) and not (
    2397            as_modifier and self._match_text_seq("USING", "SAMPLE")
    2398        ):
    2399            return None
    2400
    2401        bucket_numerator = None
    2402        bucket_denominator = None
    2403        bucket_field = None
    2404        percent = None
    2405        rows = None
    2406        size = None
    2407        seed = None
    2408
    2409        kind = (
    2410            self._prev.text if self._prev.token_type == TokenType.TABLE_SAMPLE else "USING SAMPLE"
    2411        )
    2412        method = self._parse_var(tokens=(TokenType.ROW,))
    2413
    2414        self._match(TokenType.L_PAREN)
    2415
    2416        num = self._parse_number()
    2417
    2418        if self._match_text_seq("BUCKET"):
    2419            bucket_numerator = self._parse_number()
    2420            self._match_text_seq("OUT", "OF")
    2421            bucket_denominator = bucket_denominator = self._parse_number()
    2422            self._match(TokenType.ON)
    2423            bucket_field = self._parse_field()
    2424        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    2425            percent = num
    2426        elif self._match(TokenType.ROWS):
    2427            rows = num
    2428        else:
    2429            size = num
    2430
    2431        self._match(TokenType.R_PAREN)
    2432
    2433        if self._match(TokenType.L_PAREN):
    2434            method = self._parse_var()
    2435            seed = self._match(TokenType.COMMA) and self._parse_number()
    2436            self._match_r_paren()
    2437        elif self._match_texts(("SEED", "REPEATABLE")):
    2438            seed = self._parse_wrapped(self._parse_number)
    2439
    2440        return self.expression(
    2441            exp.TableSample,
    2442            method=method,
    2443            bucket_numerator=bucket_numerator,
    2444            bucket_denominator=bucket_denominator,
    2445            bucket_field=bucket_field,
    2446            percent=percent,
    2447            rows=rows,
    2448            size=size,
    2449            seed=seed,
    2450            kind=kind,
    2451        )
    2452
    2453    def _parse_pivots(self) -> t.List[t.Optional[exp.Expression]]:
    2454        return list(iter(self._parse_pivot, None))
    2455
    2456    # https://duckdb.org/docs/sql/statements/pivot
    2457    def _parse_simplified_pivot(self) -> exp.Pivot:
    2458        def _parse_on() -> t.Optional[exp.Expression]:
    2459            this = self._parse_bitwise()
    2460            return self._parse_in(this) if self._match(TokenType.IN) else this
    2461
    2462        this = self._parse_table()
    2463        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    2464        using = self._match(TokenType.USING) and self._parse_csv(
    2465            lambda: self._parse_alias(self._parse_function())
    2466        )
    2467        group = self._parse_group()
    2468        return self.expression(
    2469            exp.Pivot, this=this, expressions=expressions, using=using, group=group
    2470        )
    2471
    2472    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    2473        index = self._index
    2474
    2475        if self._match(TokenType.PIVOT):
    2476            unpivot = False
    2477        elif self._match(TokenType.UNPIVOT):
    2478            unpivot = True
    2479        else:
    2480            return None
    2481
    2482        expressions = []
    2483        field = None
    2484
    2485        if not self._match(TokenType.L_PAREN):
    2486            self._retreat(index)
    2487            return None
    2488
    2489        if unpivot:
    2490            expressions = self._parse_csv(self._parse_column)
    2491        else:
    2492            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    2493
    2494        if not expressions:
    2495            self.raise_error("Failed to parse PIVOT's aggregation list")
    2496
    2497        if not self._match(TokenType.FOR):
    2498            self.raise_error("Expecting FOR")
    2499
    2500        value = self._parse_column()
    2501
    2502        if not self._match(TokenType.IN):
    2503            self.raise_error("Expecting IN")
    2504
    2505        field = self._parse_in(value, alias=True)
    2506
    2507        self._match_r_paren()
    2508
    2509        pivot = self.expression(exp.Pivot, expressions=expressions, field=field, unpivot=unpivot)
    2510
    2511        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    2512            pivot.set("alias", self._parse_table_alias())
    2513
    2514        if not unpivot:
    2515            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    2516
    2517            columns: t.List[exp.Expression] = []
    2518            for fld in pivot.args["field"].expressions:
    2519                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    2520                for name in names:
    2521                    if self.PREFIXED_PIVOT_COLUMNS:
    2522                        name = f"{name}_{field_name}" if name else field_name
    2523                    else:
    2524                        name = f"{field_name}_{name}" if name else field_name
    2525
    2526                    columns.append(exp.to_identifier(name))
    2527
    2528            pivot.set("columns", columns)
    2529
    2530        return pivot
    2531
    2532    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    2533        return [agg.alias for agg in aggregations]
    2534
    2535    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    2536        if not skip_where_token and not self._match(TokenType.WHERE):
    2537            return None
    2538
    2539        return self.expression(
    2540            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
    2541        )
    2542
    2543    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    2544        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    2545            return None
    2546
    2547        elements = defaultdict(list)
    2548
    2549        while True:
    2550            expressions = self._parse_csv(self._parse_conjunction)
    2551            if expressions:
    2552                elements["expressions"].extend(expressions)
    2553
    2554            grouping_sets = self._parse_grouping_sets()
    2555            if grouping_sets:
    2556                elements["grouping_sets"].extend(grouping_sets)
    2557
    2558            rollup = None
    2559            cube = None
    2560            totals = None
    2561
    2562            with_ = self._match(TokenType.WITH)
    2563            if self._match(TokenType.ROLLUP):
    2564                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
    2565                elements["rollup"].extend(ensure_list(rollup))
    2566
    2567            if self._match(TokenType.CUBE):
    2568                cube = with_ or self._parse_wrapped_csv(self._parse_column)
    2569                elements["cube"].extend(ensure_list(cube))
    2570
    2571            if self._match_text_seq("TOTALS"):
    2572                totals = True
    2573                elements["totals"] = True  # type: ignore
    2574
    2575            if not (grouping_sets or rollup or cube or totals):
    2576                break
    2577
    2578        return self.expression(exp.Group, **elements)  # type: ignore
    2579
    2580    def _parse_grouping_sets(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    2581        if not self._match(TokenType.GROUPING_SETS):
    2582            return None
    2583
    2584        return self._parse_wrapped_csv(self._parse_grouping_set)
    2585
    2586    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    2587        if self._match(TokenType.L_PAREN):
    2588            grouping_set = self._parse_csv(self._parse_column)
    2589            self._match_r_paren()
    2590            return self.expression(exp.Tuple, expressions=grouping_set)
    2591
    2592        return self._parse_column()
    2593
    2594    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    2595        if not skip_having_token and not self._match(TokenType.HAVING):
    2596            return None
    2597        return self.expression(exp.Having, this=self._parse_conjunction())
    2598
    2599    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    2600        if not self._match(TokenType.QUALIFY):
    2601            return None
    2602        return self.expression(exp.Qualify, this=self._parse_conjunction())
    2603
    2604    def _parse_order(
    2605        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    2606    ) -> t.Optional[exp.Expression]:
    2607        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    2608            return this
    2609
    2610        return self.expression(
    2611            exp.Order, this=this, expressions=self._parse_csv(self._parse_ordered)
    2612        )
    2613
    2614    def _parse_sort(self, exp_class: t.Type[E], *texts: str) -> t.Optional[E]:
    2615        if not self._match_text_seq(*texts):
    2616            return None
    2617        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    2618
    2619    def _parse_ordered(self) -> exp.Ordered:
    2620        this = self._parse_conjunction()
    2621        self._match(TokenType.ASC)
    2622
    2623        is_desc = self._match(TokenType.DESC)
    2624        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    2625        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    2626        desc = is_desc or False
    2627        asc = not desc
    2628        nulls_first = is_nulls_first or False
    2629        explicitly_null_ordered = is_nulls_first or is_nulls_last
    2630
    2631        if (
    2632            not explicitly_null_ordered
    2633            and (
    2634                (asc and self.NULL_ORDERING == "nulls_are_small")
    2635                or (desc and self.NULL_ORDERING != "nulls_are_small")
    2636            )
    2637            and self.NULL_ORDERING != "nulls_are_last"
    2638        ):
    2639            nulls_first = True
    2640
    2641        return self.expression(exp.Ordered, this=this, desc=desc, nulls_first=nulls_first)
    2642
    2643    def _parse_limit(
    2644        self, this: t.Optional[exp.Expression] = None, top: bool = False
    2645    ) -> t.Optional[exp.Expression]:
    2646        if self._match(TokenType.TOP if top else TokenType.LIMIT):
    2647            limit_paren = self._match(TokenType.L_PAREN)
    2648            expression = self._parse_number() if top else self._parse_term()
    2649
    2650            if self._match(TokenType.COMMA):
    2651                offset = expression
    2652                expression = self._parse_term()
    2653            else:
    2654                offset = None
    2655
    2656            limit_exp = self.expression(exp.Limit, this=this, expression=expression, offset=offset)
    2657
    2658            if limit_paren:
    2659                self._match_r_paren()
    2660
    2661            return limit_exp
    2662
    2663        if self._match(TokenType.FETCH):
    2664            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    2665            direction = self._prev.text if direction else "FIRST"
    2666
    2667            count = self._parse_number()
    2668            percent = self._match(TokenType.PERCENT)
    2669
    2670            self._match_set((TokenType.ROW, TokenType.ROWS))
    2671
    2672            only = self._match_text_seq("ONLY")
    2673            with_ties = self._match_text_seq("WITH", "TIES")
    2674
    2675            if only and with_ties:
    2676                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
    2677
    2678            return self.expression(
    2679                exp.Fetch,
    2680                direction=direction,
    2681                count=count,
    2682                percent=percent,
    2683                with_ties=with_ties,
    2684            )
    2685
    2686        return this
    2687
    2688    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    2689        if not self._match(TokenType.OFFSET):
    2690            return this
    2691
    2692        count = self._parse_number()
    2693        self._match_set((TokenType.ROW, TokenType.ROWS))
    2694        return self.expression(exp.Offset, this=this, expression=count)
    2695
    2696    def _parse_locks(self) -> t.List[exp.Lock]:
    2697        locks = []
    2698        while True:
    2699            if self._match_text_seq("FOR", "UPDATE"):
    2700                update = True
    2701            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    2702                "LOCK", "IN", "SHARE", "MODE"
    2703            ):
    2704                update = False
    2705            else:
    2706                break
    2707
    2708            expressions = None
    2709            if self._match_text_seq("OF"):
    2710                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    2711
    2712            wait: t.Optional[bool | exp.Expression] = None
    2713            if self._match_text_seq("NOWAIT"):
    2714                wait = True
    2715            elif self._match_text_seq("WAIT"):
    2716                wait = self._parse_primary()
    2717            elif self._match_text_seq("SKIP", "LOCKED"):
    2718                wait = False
    2719
    2720            locks.append(
    2721                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    2722            )
    2723
    2724        return locks
    2725
    2726    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2727        if not self._match_set(self.SET_OPERATIONS):
    2728            return this
    2729
    2730        token_type = self._prev.token_type
    2731
    2732        if token_type == TokenType.UNION:
    2733            expression = exp.Union
    2734        elif token_type == TokenType.EXCEPT:
    2735            expression = exp.Except
    2736        else:
    2737            expression = exp.Intersect
    2738
    2739        return self.expression(
    2740            expression,
    2741            this=this,
    2742            distinct=self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL),
    2743            expression=self._parse_set_operations(self._parse_select(nested=True)),
    2744        )
    2745
    2746    def _parse_expression(self) -> t.Optional[exp.Expression]:
    2747        return self._parse_alias(self._parse_conjunction())
    2748
    2749    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    2750        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    2751
    2752    def _parse_equality(self) -> t.Optional[exp.Expression]:
    2753        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    2754
    2755    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    2756        return self._parse_tokens(self._parse_range, self.COMPARISON)
    2757
    2758    def _parse_range(self) -> t.Optional[exp.Expression]:
    2759        this = self._parse_bitwise()
    2760        negate = self._match(TokenType.NOT)
    2761
    2762        if self._match_set(self.RANGE_PARSERS):
    2763            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    2764            if not expression:
    2765                return this
    2766
    2767            this = expression
    2768        elif self._match(TokenType.ISNULL):
    2769            this = self.expression(exp.Is, this=this, expression=exp.Null())
    2770
    2771        # Postgres supports ISNULL and NOTNULL for conditions.
    2772        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    2773        if self._match(TokenType.NOTNULL):
    2774            this = self.expression(exp.Is, this=this, expression=exp.Null())
    2775            this = self.expression(exp.Not, this=this)
    2776
    2777        if negate:
    2778            this = self.expression(exp.Not, this=this)
    2779
    2780        if self._match(TokenType.IS):
    2781            this = self._parse_is(this)
    2782
    2783        return this
    2784
    2785    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2786        index = self._index - 1
    2787        negate = self._match(TokenType.NOT)
    2788
    2789        if self._match_text_seq("DISTINCT", "FROM"):
    2790            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    2791            return self.expression(klass, this=this, expression=self._parse_expression())
    2792
    2793        expression = self._parse_null() or self._parse_boolean()
    2794        if not expression:
    2795            self._retreat(index)
    2796            return None
    2797
    2798        this = self.expression(exp.Is, this=this, expression=expression)
    2799        return self.expression(exp.Not, this=this) if negate else this
    2800
    2801    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    2802        unnest = self._parse_unnest(with_alias=False)
    2803        if unnest:
    2804            this = self.expression(exp.In, this=this, unnest=unnest)
    2805        elif self._match(TokenType.L_PAREN):
    2806            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    2807
    2808            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
    2809                this = self.expression(exp.In, this=this, query=expressions[0])
    2810            else:
    2811                this = self.expression(exp.In, this=this, expressions=expressions)
    2812
    2813            self._match_r_paren(this)
    2814        else:
    2815            this = self.expression(exp.In, this=this, field=self._parse_field())
    2816
    2817        return this
    2818
    2819    def _parse_between(self, this: exp.Expression) -> exp.Between:
    2820        low = self._parse_bitwise()
    2821        self._match(TokenType.AND)
    2822        high = self._parse_bitwise()
    2823        return self.expression(exp.Between, this=this, low=low, high=high)
    2824
    2825    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    2826        if not self._match(TokenType.ESCAPE):
    2827            return this
    2828        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    2829
    2830    def _parse_interval(self) -> t.Optional[exp.Interval]:
    2831        if not self._match(TokenType.INTERVAL):
    2832            return None
    2833
    2834        this = self._parse_primary() or self._parse_term()
    2835        unit = self._parse_function() or self._parse_var()
    2836
    2837        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    2838        # each INTERVAL expression into this canonical form so it's easy to transpile
    2839        if this and this.is_number:
    2840            this = exp.Literal.string(this.name)
    2841        elif this and this.is_string:
    2842            parts = this.name.split()
    2843
    2844            if len(parts) == 2:
    2845                if unit:
    2846                    # this is not actually a unit, it's something else
    2847                    unit = None
    2848                    self._retreat(self._index - 1)
    2849                else:
    2850                    this = exp.Literal.string(parts[0])
    2851                    unit = self.expression(exp.Var, this=parts[1])
    2852
    2853        return self.expression(exp.Interval, this=this, unit=unit)
    2854
    2855    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    2856        this = self._parse_term()
    2857
    2858        while True:
    2859            if self._match_set(self.BITWISE):
    2860                this = self.expression(
    2861                    self.BITWISE[self._prev.token_type], this=this, expression=self._parse_term()
    2862                )
    2863            elif self._match_pair(TokenType.LT, TokenType.LT):
    2864                this = self.expression(
    2865                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    2866                )
    2867            elif self._match_pair(TokenType.GT, TokenType.GT):
    2868                this = self.expression(
    2869                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    2870                )
    2871            else:
    2872                break
    2873
    2874        return this
    2875
    2876    def _parse_term(self) -> t.Optional[exp.Expression]:
    2877        return self._parse_tokens(self._parse_factor, self.TERM)
    2878
    2879    def _parse_factor(self) -> t.Optional[exp.Expression]:
    2880        return self._parse_tokens(self._parse_unary, self.FACTOR)
    2881
    2882    def _parse_unary(self) -> t.Optional[exp.Expression]:
    2883        if self._match_set(self.UNARY_PARSERS):
    2884            return self.UNARY_PARSERS[self._prev.token_type](self)
    2885        return self._parse_at_time_zone(self._parse_type())
    2886
    2887    def _parse_type(self) -> t.Optional[exp.Expression]:
    2888        interval = self._parse_interval()
    2889        if interval:
    2890            return interval
    2891
    2892        index = self._index
    2893        data_type = self._parse_types(check_func=True)
    2894        this = self._parse_column()
    2895
    2896        if data_type:
    2897            if isinstance(this, exp.Literal):
    2898                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    2899                if parser:
    2900                    return parser(self, this, data_type)
    2901                return self.expression(exp.Cast, this=this, to=data_type)
    2902            if not data_type.expressions:
    2903                self._retreat(index)
    2904                return self._parse_column()
    2905            return self._parse_column_ops(data_type)
    2906
    2907        return this
    2908
    2909    def _parse_type_size(self) -> t.Optional[exp.DataTypeSize]:
    2910        this = self._parse_type()
    2911        if not this:
    2912            return None
    2913
    2914        return self.expression(
    2915            exp.DataTypeSize, this=this, expression=self._parse_var(any_token=True)
    2916        )
    2917
    2918    def _parse_types(
    2919        self, check_func: bool = False, schema: bool = False
    2920    ) -> t.Optional[exp.Expression]:
    2921        index = self._index
    2922
    2923        prefix = self._match_text_seq("SYSUDTLIB", ".")
    2924
    2925        if not self._match_set(self.TYPE_TOKENS):
    2926            return None
    2927
    2928        type_token = self._prev.token_type
    2929
    2930        if type_token == TokenType.PSEUDO_TYPE:
    2931            return self.expression(exp.PseudoType, this=self._prev.text)
    2932
    2933        nested = type_token in self.NESTED_TYPE_TOKENS
    2934        is_struct = type_token == TokenType.STRUCT
    2935        expressions = None
    2936        maybe_func = False
    2937
    2938        if self._match(TokenType.L_PAREN):
    2939            if is_struct:
    2940                expressions = self._parse_csv(self._parse_struct_types)
    2941            elif nested:
    2942                expressions = self._parse_csv(
    2943                    lambda: self._parse_types(check_func=check_func, schema=schema)
    2944                )
    2945            elif type_token in self.ENUM_TYPE_TOKENS:
    2946                expressions = self._parse_csv(self._parse_primary)
    2947            else:
    2948                expressions = self._parse_csv(self._parse_type_size)
    2949
    2950            if not expressions or not self._match(TokenType.R_PAREN):
    2951                self._retreat(index)
    2952                return None
    2953
    2954            maybe_func = True
    2955
    2956        if self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
    2957            this = exp.DataType(
    2958                this=exp.DataType.Type.ARRAY,
    2959                expressions=[exp.DataType.build(type_token.value, expressions=expressions)],
    2960                nested=True,
    2961            )
    2962
    2963            while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
    2964                this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
    2965
    2966            return this
    2967
    2968        if self._match(TokenType.L_BRACKET):
    2969            self._retreat(index)
    2970            return None
    2971
    2972        values: t.Optional[t.List[t.Optional[exp.Expression]]] = None
    2973        if nested and self._match(TokenType.LT):
    2974            if is_struct:
    2975                expressions = self._parse_csv(self._parse_struct_types)
    2976            else:
    2977                expressions = self._parse_csv(
    2978                    lambda: self._parse_types(check_func=check_func, schema=schema)
    2979                )
    2980
    2981            if not self._match(TokenType.GT):
    2982                self.raise_error("Expecting >")
    2983
    2984            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    2985                values = self._parse_csv(self._parse_conjunction)
    2986                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    2987
    2988        value: t.Optional[exp.Expression] = None
    2989        if type_token in self.TIMESTAMPS:
    2990            if self._match_text_seq("WITH", "TIME", "ZONE"):
    2991                maybe_func = False
    2992                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPTZ, expressions=expressions)
    2993            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    2994                maybe_func = False
    2995                value = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    2996            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    2997                maybe_func = False
    2998        elif type_token == TokenType.INTERVAL:
    2999            unit = self._parse_var()
    3000
    3001            if not unit:
    3002                value = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    3003            else:
    3004                value = self.expression(exp.Interval, unit=unit)
    3005
    3006        if maybe_func and check_func:
    3007            index2 = self._index
    3008            peek = self._parse_string()
    3009
    3010            if not peek:
    3011                self._retreat(index)
    3012                return None
    3013
    3014            self._retreat(index2)
    3015
    3016        if value:
    3017            return value
    3018
    3019        return exp.DataType(
    3020            this=exp.DataType.Type[type_token.value.upper()],
    3021            expressions=expressions,
    3022            nested=nested,
    3023            values=values,
    3024            prefix=prefix,
    3025        )
    3026
    3027    def _parse_struct_types(self) -> t.Optional[exp.Expression]:
    3028        this = self._parse_type() or self._parse_id_var()
    3029        self._match(TokenType.COLON)
    3030        return self._parse_column_def(this)
    3031
    3032    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3033        if not self._match_text_seq("AT", "TIME", "ZONE"):
    3034            return this
    3035        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    3036
    3037    def _parse_column(self) -> t.Optional[exp.Expression]:
    3038        this = self._parse_field()
    3039        if isinstance(this, exp.Identifier):
    3040            this = self.expression(exp.Column, this=this)
    3041        elif not this:
    3042            return self._parse_bracket(this)
    3043        return self._parse_column_ops(this)
    3044
    3045    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3046        this = self._parse_bracket(this)
    3047
    3048        while self._match_set(self.COLUMN_OPERATORS):
    3049            op_token = self._prev.token_type
    3050            op = self.COLUMN_OPERATORS.get(op_token)
    3051
    3052            if op_token == TokenType.DCOLON:
    3053                field = self._parse_types()
    3054                if not field:
    3055                    self.raise_error("Expected type")
    3056            elif op and self._curr:
    3057                self._advance()
    3058                value = self._prev.text
    3059                field = (
    3060                    exp.Literal.number(value)
    3061                    if self._prev.token_type == TokenType.NUMBER
    3062                    else exp.Literal.string(value)
    3063                )
    3064            else:
    3065                field = self._parse_field(anonymous_func=True, any_token=True)
    3066
    3067            if isinstance(field, exp.Func):
    3068                # bigquery allows function calls like x.y.count(...)
    3069                # SAFE.SUBSTR(...)
    3070                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    3071                this = self._replace_columns_with_dots(this)
    3072
    3073            if op:
    3074                this = op(self, this, field)
    3075            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    3076                this = self.expression(
    3077                    exp.Column,
    3078                    this=field,
    3079                    table=this.this,
    3080                    db=this.args.get("table"),
    3081                    catalog=this.args.get("db"),
    3082                )
    3083            else:
    3084                this = self.expression(exp.Dot, this=this, expression=field)
    3085            this = self._parse_bracket(this)
    3086        return this
    3087
    3088    def _parse_primary(self) -> t.Optional[exp.Expression]:
    3089        if self._match_set(self.PRIMARY_PARSERS):
    3090            token_type = self._prev.token_type
    3091            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    3092
    3093            if token_type == TokenType.STRING:
    3094                expressions = [primary]
    3095                while self._match(TokenType.STRING):
    3096                    expressions.append(exp.Literal.string(self._prev.text))
    3097
    3098                if len(expressions) > 1:
    3099                    return self.expression(exp.Concat, expressions=expressions)
    3100
    3101            return primary
    3102
    3103        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    3104            return exp.Literal.number(f"0.{self._prev.text}")
    3105
    3106        if self._match(TokenType.L_PAREN):
    3107            comments = self._prev_comments
    3108            query = self._parse_select()
    3109
    3110            if query:
    3111                expressions = [query]
    3112            else:
    3113                expressions = self._parse_csv(self._parse_expression)
    3114
    3115            this = self._parse_query_modifiers(seq_get(expressions, 0))
    3116
    3117            if isinstance(this, exp.Subqueryable):
    3118                this = self._parse_set_operations(
    3119                    self._parse_subquery(this=this, parse_alias=False)
    3120                )
    3121            elif len(expressions) > 1:
    3122                this = self.expression(exp.Tuple, expressions=expressions)
    3123            else:
    3124                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
    3125
    3126            if this:
    3127                this.add_comments(comments)
    3128
    3129            self._match_r_paren(expression=this)
    3130            return this
    3131
    3132        return None
    3133
    3134    def _parse_field(
    3135        self,
    3136        any_token: bool = False,
    3137        tokens: t.Optional[t.Collection[TokenType]] = None,
    3138        anonymous_func: bool = False,
    3139    ) -> t.Optional[exp.Expression]:
    3140        return (
    3141            self._parse_primary()
    3142            or self._parse_function(anonymous=anonymous_func)
    3143            or self._parse_id_var(any_token=any_token, tokens=tokens)
    3144        )
    3145
    3146    def _parse_function(
    3147        self,
    3148        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    3149        anonymous: bool = False,
    3150        optional_parens: bool = True,
    3151    ) -> t.Optional[exp.Expression]:
    3152        if not self._curr:
    3153            return None
    3154
    3155        token_type = self._curr.token_type
    3156
    3157        if optional_parens and self._match_set(self.NO_PAREN_FUNCTION_PARSERS):
    3158            return self.NO_PAREN_FUNCTION_PARSERS[token_type](self)
    3159
    3160        if not self._next or self._next.token_type != TokenType.L_PAREN:
    3161            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    3162                self._advance()
    3163                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    3164
    3165            return None
    3166
    3167        if token_type not in self.FUNC_TOKENS:
    3168            return None
    3169
    3170        this = self._curr.text
    3171        upper = this.upper()
    3172        self._advance(2)
    3173
    3174        parser = self.FUNCTION_PARSERS.get(upper)
    3175
    3176        if parser and not anonymous:
    3177            this = parser(self)
    3178        else:
    3179            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    3180
    3181            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    3182                this = self.expression(subquery_predicate, this=self._parse_select())
    3183                self._match_r_paren()
    3184                return this
    3185
    3186            if functions is None:
    3187                functions = self.FUNCTIONS
    3188
    3189            function = functions.get(upper)
    3190
    3191            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    3192            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    3193
    3194            if function and not anonymous:
    3195                this = self.validate_expression(function(args), args)
    3196            else:
    3197                this = self.expression(exp.Anonymous, this=this, expressions=args)
    3198
    3199        self._match_r_paren(this)
    3200        return self._parse_window(this)
    3201
    3202    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    3203        return self._parse_column_def(self._parse_id_var())
    3204
    3205    def _parse_user_defined_function(
    3206        self, kind: t.Optional[TokenType] = None
    3207    ) -> t.Optional[exp.Expression]:
    3208        this = self._parse_id_var()
    3209
    3210        while self._match(TokenType.DOT):
    3211            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    3212
    3213        if not self._match(TokenType.L_PAREN):
    3214            return this
    3215
    3216        expressions = self._parse_csv(self._parse_function_parameter)
    3217        self._match_r_paren()
    3218        return self.expression(
    3219            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    3220        )
    3221
    3222    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    3223        literal = self._parse_primary()
    3224        if literal:
    3225            return self.expression(exp.Introducer, this=token.text, expression=literal)
    3226
    3227        return self.expression(exp.Identifier, this=token.text)
    3228
    3229    def _parse_session_parameter(self) -> exp.SessionParameter:
    3230        kind = None
    3231        this = self._parse_id_var() or self._parse_primary()
    3232
    3233        if this and self._match(TokenType.DOT):
    3234            kind = this.name
    3235            this = self._parse_var() or self._parse_primary()
    3236
    3237        return self.expression(exp.SessionParameter, this=this, kind=kind)
    3238
    3239    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    3240        index = self._index
    3241
    3242        if self._match(TokenType.L_PAREN):
    3243            expressions = self._parse_csv(self._parse_id_var)
    3244
    3245            if not self._match(TokenType.R_PAREN):
    3246                self._retreat(index)
    3247        else:
    3248            expressions = [self._parse_id_var()]
    3249
    3250        if self._match_set(self.LAMBDAS):
    3251            return self.LAMBDAS[self._prev.token_type](self, expressions)
    3252
    3253        self._retreat(index)
    3254
    3255        this: t.Optional[exp.Expression]
    3256
    3257        if self._match(TokenType.DISTINCT):
    3258            this = self.expression(
    3259                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
    3260            )
    3261        else:
    3262            this = self._parse_select_or_expression(alias=alias)
    3263
    3264            if isinstance(this, exp.EQ):
    3265                left = this.this
    3266                if isinstance(left, exp.Column):
    3267                    left.replace(exp.var(left.text("this")))
    3268
    3269        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
    3270
    3271    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    3272        index = self._index
    3273
    3274        if not self.errors:
    3275            try:
    3276                if self._parse_select(nested=True):
    3277                    return this
    3278            except ParseError:
    3279                pass
    3280            finally:
    3281                self.errors.clear()
    3282                self._retreat(index)
    3283
    3284        if not self._match(TokenType.L_PAREN):
    3285            return this
    3286
    3287        args = self._parse_csv(
    3288            lambda: self._parse_constraint()
    3289            or self._parse_column_def(self._parse_field(any_token=True))
    3290        )
    3291
    3292        self._match_r_paren()
    3293        return self.expression(exp.Schema, this=this, expressions=args)
    3294
    3295    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3296        # column defs are not really columns, they're identifiers
    3297        if isinstance(this, exp.Column):
    3298            this = this.this
    3299
    3300        kind = self._parse_types(schema=True)
    3301
    3302        if self._match_text_seq("FOR", "ORDINALITY"):
    3303            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    3304
    3305        constraints = []
    3306        while True:
    3307            constraint = self._parse_column_constraint()
    3308            if not constraint:
    3309                break
    3310            constraints.append(constraint)
    3311
    3312        if not kind and not constraints:
    3313            return this
    3314
    3315        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    3316
    3317    def _parse_auto_increment(
    3318        self,
    3319    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    3320        start = None
    3321        increment = None
    3322
    3323        if self._match(TokenType.L_PAREN, advance=False):
    3324            args = self._parse_wrapped_csv(self._parse_bitwise)
    3325            start = seq_get(args, 0)
    3326            increment = seq_get(args, 1)
    3327        elif self._match_text_seq("START"):
    3328            start = self._parse_bitwise()
    3329            self._match_text_seq("INCREMENT")
    3330            increment = self._parse_bitwise()
    3331
    3332        if start and increment:
    3333            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    3334
    3335        return exp.AutoIncrementColumnConstraint()
    3336
    3337    def _parse_compress(self) -> exp.CompressColumnConstraint:
    3338        if self._match(TokenType.L_PAREN, advance=False):
    3339            return self.expression(
    3340                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    3341            )
    3342
    3343        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    3344
    3345    def _parse_generated_as_identity(self) -> exp.GeneratedAsIdentityColumnConstraint:
    3346        if self._match_text_seq("BY", "DEFAULT"):
    3347            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    3348            this = self.expression(
    3349                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    3350            )
    3351        else:
    3352            self._match_text_seq("ALWAYS")
    3353            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    3354
    3355        self._match(TokenType.ALIAS)
    3356        identity = self._match_text_seq("IDENTITY")
    3357
    3358        if self._match(TokenType.L_PAREN):
    3359            if self._match_text_seq("START", "WITH"):
    3360                this.set("start", self._parse_bitwise())
    3361            if self._match_text_seq("INCREMENT", "BY"):
    3362                this.set("increment", self._parse_bitwise())
    3363            if self._match_text_seq("MINVALUE"):
    3364                this.set("minvalue", self._parse_bitwise())
    3365            if self._match_text_seq("MAXVALUE"):
    3366                this.set("maxvalue", self._parse_bitwise())
    3367
    3368            if self._match_text_seq("CYCLE"):
    3369                this.set("cycle", True)
    3370            elif self._match_text_seq("NO", "CYCLE"):
    3371                this.set("cycle", False)
    3372
    3373            if not identity:
    3374                this.set("expression", self._parse_bitwise())
    3375
    3376            self._match_r_paren()
    3377
    3378        return this
    3379
    3380    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    3381        self._match_text_seq("LENGTH")
    3382        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    3383
    3384    def _parse_not_constraint(
    3385        self,
    3386    ) -> t.Optional[exp.NotNullColumnConstraint | exp.CaseSpecificColumnConstraint]:
    3387        if self._match_text_seq("NULL"):
    3388            return self.expression(exp.NotNullColumnConstraint)
    3389        if self._match_text_seq("CASESPECIFIC"):
    3390            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    3391        return None
    3392
    3393    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    3394        if self._match(TokenType.CONSTRAINT):
    3395            this = self._parse_id_var()
    3396        else:
    3397            this = None
    3398
    3399        if self._match_texts(self.CONSTRAINT_PARSERS):
    3400            return self.expression(
    3401                exp.ColumnConstraint,
    3402                this=this,
    3403                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    3404            )
    3405
    3406        return this
    3407
    3408    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    3409        if not self._match(TokenType.CONSTRAINT):
    3410            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    3411
    3412        this = self._parse_id_var()
    3413        expressions = []
    3414
    3415        while True:
    3416            constraint = self._parse_unnamed_constraint() or self._parse_function()
    3417            if not constraint:
    3418                break
    3419            expressions.append(constraint)
    3420
    3421        return self.expression(exp.Constraint, this=this, expressions=expressions)
    3422
    3423    def _parse_unnamed_constraint(
    3424        self, constraints: t.Optional[t.Collection[str]] = None
    3425    ) -> t.Optional[exp.Expression]:
    3426        if not self._match_texts(constraints or self.CONSTRAINT_PARSERS):
    3427            return None
    3428
    3429        constraint = self._prev.text.upper()
    3430        if constraint not in self.CONSTRAINT_PARSERS:
    3431            self.raise_error(f"No parser found for schema constraint {constraint}.")
    3432
    3433        return self.CONSTRAINT_PARSERS[constraint](self)
    3434
    3435    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    3436        self._match_text_seq("KEY")
    3437        return self.expression(
    3438            exp.UniqueColumnConstraint, this=self._parse_schema(self._parse_id_var(any_token=False))
    3439        )
    3440
    3441    def _parse_key_constraint_options(self) -> t.List[str]:
    3442        options = []
    3443        while True:
    3444            if not self._curr:
    3445                break
    3446
    3447            if self._match(TokenType.ON):
    3448                action = None
    3449                on = self._advance_any() and self._prev.text
    3450
    3451                if self._match_text_seq("NO", "ACTION"):
    3452                    action = "NO ACTION"
    3453                elif self._match_text_seq("CASCADE"):
    3454                    action = "CASCADE"
    3455                elif self._match_pair(TokenType.SET, TokenType.NULL):
    3456                    action = "SET NULL"
    3457                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    3458                    action = "SET DEFAULT"
    3459                else:
    3460                    self.raise_error("Invalid key constraint")
    3461
    3462                options.append(f"ON {on} {action}")
    3463            elif self._match_text_seq("NOT", "ENFORCED"):
    3464                options.append("NOT ENFORCED")
    3465            elif self._match_text_seq("DEFERRABLE"):
    3466                options.append("DEFERRABLE")
    3467            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    3468                options.append("INITIALLY DEFERRED")
    3469            elif self._match_text_seq("NORELY"):
    3470                options.append("NORELY")
    3471            elif self._match_text_seq("MATCH", "FULL"):
    3472                options.append("MATCH FULL")
    3473            else:
    3474                break
    3475
    3476        return options
    3477
    3478    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    3479        if match and not self._match(TokenType.REFERENCES):
    3480            return None
    3481
    3482        expressions = None
    3483        this = self._parse_id_var()
    3484
    3485        if self._match(TokenType.L_PAREN, advance=False):
    3486            expressions = self._parse_wrapped_id_vars()
    3487
    3488        options = self._parse_key_constraint_options()
    3489        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    3490
    3491    def _parse_foreign_key(self) -> exp.ForeignKey:
    3492        expressions = self._parse_wrapped_id_vars()
    3493        reference = self._parse_references()
    3494        options = {}
    3495
    3496        while self._match(TokenType.ON):
    3497            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    3498                self.raise_error("Expected DELETE or UPDATE")
    3499
    3500            kind = self._prev.text.lower()
    3501
    3502            if self._match_text_seq("NO", "ACTION"):
    3503                action = "NO ACTION"
    3504            elif self._match(TokenType.SET):
    3505                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    3506                action = "SET " + self._prev.text.upper()
    3507            else:
    3508                self._advance()
    3509                action = self._prev.text.upper()
    3510
    3511            options[kind] = action
    3512
    3513        return self.expression(
    3514            exp.ForeignKey, expressions=expressions, reference=reference, **options  # type: ignore
    3515        )
    3516
    3517    def _parse_primary_key(
    3518        self, wrapped_optional: bool = False, in_props: bool = False
    3519    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    3520        desc = (
    3521            self._match_set((TokenType.ASC, TokenType.DESC))
    3522            and self._prev.token_type == TokenType.DESC
    3523        )
    3524
    3525        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    3526            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    3527
    3528        expressions = self._parse_wrapped_csv(self._parse_field, optional=wrapped_optional)
    3529        options = self._parse_key_constraint_options()
    3530        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    3531
    3532    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3533        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    3534            return this
    3535
    3536        bracket_kind = self._prev.token_type
    3537
    3538        if self._match(TokenType.COLON):
    3539            expressions: t.List[t.Optional[exp.Expression]] = [
    3540                self.expression(exp.Slice, expression=self._parse_conjunction())
    3541            ]
    3542        else:
    3543            expressions = self._parse_csv(lambda: self._parse_slice(self._parse_conjunction()))
    3544
    3545        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    3546        if bracket_kind == TokenType.L_BRACE:
    3547            this = self.expression(exp.Struct, expressions=expressions)
    3548        elif not this or this.name.upper() == "ARRAY":
    3549            this = self.expression(exp.Array, expressions=expressions)
    3550        else:
    3551            expressions = apply_index_offset(this, expressions, -self.INDEX_OFFSET)
    3552            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    3553
    3554        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
    3555            self.raise_error("Expected ]")
    3556        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
    3557            self.raise_error("Expected }")
    3558
    3559        self._add_comments(this)
    3560        return self._parse_bracket(this)
    3561
    3562    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3563        if self._match(TokenType.COLON):
    3564            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
    3565        return this
    3566
    3567    def _parse_case(self) -> t.Optional[exp.Expression]:
    3568        ifs = []
    3569        default = None
    3570
    3571        expression = self._parse_conjunction()
    3572
    3573        while self._match(TokenType.WHEN):
    3574            this = self._parse_conjunction()
    3575            self._match(TokenType.THEN)
    3576            then = self._parse_conjunction()
    3577            ifs.append(self.expression(exp.If, this=this, true=then))
    3578
    3579        if self._match(TokenType.ELSE):
    3580            default = self._parse_conjunction()
    3581
    3582        if not self._match(TokenType.END):
    3583            self.raise_error("Expected END after CASE", self._prev)
    3584
    3585        return self._parse_window(
    3586            self.expression(exp.Case, this=expression, ifs=ifs, default=default)
    3587        )
    3588
    3589    def _parse_if(self) -> t.Optional[exp.Expression]:
    3590        if self._match(TokenType.L_PAREN):
    3591            args = self._parse_csv(self._parse_conjunction)
    3592            this = self.validate_expression(exp.If.from_arg_list(args), args)
    3593            self._match_r_paren()
    3594        else:
    3595            index = self._index - 1
    3596            condition = self._parse_conjunction()
    3597
    3598            if not condition:
    3599                self._retreat(index)
    3600                return None
    3601
    3602            self._match(TokenType.THEN)
    3603            true = self._parse_conjunction()
    3604            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
    3605            self._match(TokenType.END)
    3606            this = self.expression(exp.If, this=condition, true=true, false=false)
    3607
    3608        return self._parse_window(this)
    3609
    3610    def _parse_extract(self) -> exp.Extract:
    3611        this = self._parse_function() or self._parse_var() or self._parse_type()
    3612
    3613        if self._match(TokenType.FROM):
    3614            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    3615
    3616        if not self._match(TokenType.COMMA):
    3617            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    3618
    3619        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    3620
    3621    def _parse_cast(self, strict: bool) -> exp.Expression:
    3622        this = self._parse_conjunction()
    3623
    3624        if not self._match(TokenType.ALIAS):
    3625            if self._match(TokenType.COMMA):
    3626                return self.expression(
    3627                    exp.CastToStrType, this=this, expression=self._parse_string()
    3628                )
    3629            else:
    3630                self.raise_error("Expected AS after CAST")
    3631
    3632        to = self._parse_types()
    3633
    3634        if not to:
    3635            self.raise_error("Expected TYPE after CAST")
    3636        elif to.this == exp.DataType.Type.CHAR:
    3637            if self._match(TokenType.CHARACTER_SET):
    3638                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    3639        elif to.this in exp.DataType.TEMPORAL_TYPES and self._match(TokenType.FORMAT):
    3640            fmt = self._parse_string()
    3641
    3642            return self.expression(
    3643                exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    3644                this=this,
    3645                format=exp.Literal.string(
    3646                    format_time(
    3647                        fmt.this if fmt else "",
    3648                        self.FORMAT_MAPPING or self.TIME_MAPPING,
    3649                        self.FORMAT_TRIE or self.TIME_TRIE,
    3650                    )
    3651                ),
    3652            )
    3653
    3654        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
    3655
    3656    def _parse_concat(self) -> t.Optional[exp.Expression]:
    3657        args = self._parse_csv(self._parse_conjunction)
    3658        if self.CONCAT_NULL_OUTPUTS_STRING:
    3659            args = [exp.func("COALESCE", arg, exp.Literal.string("")) for arg in args]
    3660
    3661        # Some dialects (e.g. Trino) don't allow a single-argument CONCAT call, so when
    3662        # we find such a call we replace it with its argument.
    3663        if len(args) == 1:
    3664            return args[0]
    3665
    3666        return self.expression(
    3667            exp.Concat if self.STRICT_STRING_CONCAT else exp.SafeConcat, expressions=args
    3668        )
    3669
    3670    def _parse_string_agg(self) -> exp.Expression:
    3671        expression: t.Optional[exp.Expression]
    3672
    3673        if self._match(TokenType.DISTINCT):
    3674            args = self._parse_csv(self._parse_conjunction)
    3675            expression = self.expression(exp.Distinct, expressions=[seq_get(args, 0)])
    3676        else:
    3677            args = self._parse_csv(self._parse_conjunction)
    3678            expression = seq_get(args, 0)
    3679
    3680        index = self._index
    3681        if not self._match(TokenType.R_PAREN):
    3682            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    3683            order = self._parse_order(this=expression)
    3684            return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    3685
    3686        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    3687        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    3688        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    3689        if not self._match_text_seq("WITHIN", "GROUP"):
    3690            self._retreat(index)
    3691            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    3692
    3693        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    3694        order = self._parse_order(this=expression)
    3695        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    3696
    3697    def _parse_convert(self, strict: bool) -> t.Optional[exp.Expression]:
    3698        to: t.Optional[exp.Expression]
    3699        this = self._parse_bitwise()
    3700
    3701        if self._match(TokenType.USING):
    3702            to = self.expression(exp.CharacterSet, this=self._parse_var())
    3703        elif self._match(TokenType.COMMA):
    3704            to = self._parse_bitwise()
    3705        else:
    3706            to = None
    3707
    3708        # Swap the argument order if needed to produce the correct AST
    3709        if self.CONVERT_TYPE_FIRST:
    3710            this, to = to, this
    3711
    3712        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
    3713
    3714    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    3715        """
    3716        There are generally two variants of the DECODE function:
    3717
    3718        - DECODE(bin, charset)
    3719        - DECODE(expression, search, result [, search, result] ... [, default])
    3720
    3721        The second variant will always be parsed into a CASE expression. Note that NULL
    3722        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    3723        instead of relying on pattern matching.
    3724        """
    3725        args = self._parse_csv(self._parse_conjunction)
    3726
    3727        if len(args) < 3:
    3728            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    3729
    3730        expression, *expressions = args
    3731        if not expression:
    3732            return None
    3733
    3734        ifs = []
    3735        for search, result in zip(expressions[::2], expressions[1::2]):
    3736            if not search or not result:
    3737                return None
    3738
    3739            if isinstance(search, exp.Literal):
    3740                ifs.append(
    3741                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    3742                )
    3743            elif isinstance(search, exp.Null):
    3744                ifs.append(
    3745                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    3746                )
    3747            else:
    3748                cond = exp.or_(
    3749                    exp.EQ(this=expression.copy(), expression=search),
    3750                    exp.and_(
    3751                        exp.Is(this=expression.copy(), expression=exp.Null()),
    3752                        exp.Is(this=search.copy(), expression=exp.Null()),
    3753                        copy=False,
    3754                    ),
    3755                    copy=False,
    3756                )
    3757                ifs.append(exp.If(this=cond, true=result))
    3758
    3759        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    3760
    3761    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    3762        self._match_text_seq("KEY")
    3763        key = self._parse_field()
    3764        self._match(TokenType.COLON)
    3765        self._match_text_seq("VALUE")
    3766        value = self._parse_field()
    3767
    3768        if not key and not value:
    3769            return None
    3770        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    3771
    3772    def _parse_json_object(self) -> exp.JSONObject:
    3773        star = self._parse_star()
    3774        expressions = [star] if star else self._parse_csv(self._parse_json_key_value)
    3775
    3776        null_handling = None
    3777        if self._match_text_seq("NULL", "ON", "NULL"):
    3778            null_handling = "NULL ON NULL"
    3779        elif self._match_text_seq("ABSENT", "ON", "NULL"):
    3780            null_handling = "ABSENT ON NULL"
    3781
    3782        unique_keys = None
    3783        if self._match_text_seq("WITH", "UNIQUE"):
    3784            unique_keys = True
    3785        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    3786            unique_keys = False
    3787
    3788        self._match_text_seq("KEYS")
    3789
    3790        return_type = self._match_text_seq("RETURNING") and self._parse_type()
    3791        format_json = self._match_text_seq("FORMAT", "JSON")
    3792        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    3793
    3794        return self.expression(
    3795            exp.JSONObject,
    3796            expressions=expressions,
    3797            null_handling=null_handling,
    3798            unique_keys=unique_keys,
    3799            return_type=return_type,
    3800            format_json=format_json,
    3801            encoding=encoding,
    3802        )
    3803
    3804    def _parse_logarithm(self) -> exp.Func:
    3805        # Default argument order is base, expression
    3806        args = self._parse_csv(self._parse_range)
    3807
    3808        if len(args) > 1:
    3809            if not self.LOG_BASE_FIRST:
    3810                args.reverse()
    3811            return exp.Log.from_arg_list(args)
    3812
    3813        return self.expression(
    3814            exp.Ln if self.LOG_DEFAULTS_TO_LN else exp.Log, this=seq_get(args, 0)
    3815        )
    3816
    3817    def _parse_match_against(self) -> exp.MatchAgainst:
    3818        expressions = self._parse_csv(self._parse_column)
    3819
    3820        self._match_text_seq(")", "AGAINST", "(")
    3821
    3822        this = self._parse_string()
    3823
    3824        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    3825            modifier = "IN NATURAL LANGUAGE MODE"
    3826            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    3827                modifier = f"{modifier} WITH QUERY EXPANSION"
    3828        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    3829            modifier = "IN BOOLEAN MODE"
    3830        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    3831            modifier = "WITH QUERY EXPANSION"
    3832        else:
    3833            modifier = None
    3834
    3835        return self.expression(
    3836            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    3837        )
    3838
    3839    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    3840    def _parse_open_json(self) -> exp.OpenJSON:
    3841        this = self._parse_bitwise()
    3842        path = self._match(TokenType.COMMA) and self._parse_string()
    3843
    3844        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    3845            this = self._parse_field(any_token=True)
    3846            kind = self._parse_types()
    3847            path = self._parse_string()
    3848            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    3849
    3850            return self.expression(
    3851                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    3852            )
    3853
    3854        expressions = None
    3855        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    3856            self._match_l_paren()
    3857            expressions = self._parse_csv(_parse_open_json_column_def)
    3858
    3859        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    3860
    3861    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    3862        args = self._parse_csv(self._parse_bitwise)
    3863
    3864        if self._match(TokenType.IN):
    3865            return self.expression(
    3866                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    3867            )
    3868
    3869        if haystack_first:
    3870            haystack = seq_get(args, 0)
    3871            needle = seq_get(args, 1)
    3872        else:
    3873            needle = seq_get(args, 0)
    3874            haystack = seq_get(args, 1)
    3875
    3876        return self.expression(
    3877            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    3878        )
    3879
    3880    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    3881        args = self._parse_csv(self._parse_table)
    3882        return exp.JoinHint(this=func_name.upper(), expressions=args)
    3883
    3884    def _parse_substring(self) -> exp.Substring:
    3885        # Postgres supports the form: substring(string [from int] [for int])
    3886        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    3887
    3888        args = self._parse_csv(self._parse_bitwise)
    3889
    3890        if self._match(TokenType.FROM):
    3891            args.append(self._parse_bitwise())
    3892            if self._match(TokenType.FOR):
    3893                args.append(self._parse_bitwise())
    3894
    3895        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    3896
    3897    def _parse_trim(self) -> exp.Trim:
    3898        # https://www.w3resource.com/sql/character-functions/trim.php
    3899        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    3900
    3901        position = None
    3902        collation = None
    3903
    3904        if self._match_texts(self.TRIM_TYPES):
    3905            position = self._prev.text.upper()
    3906
    3907        expression = self._parse_bitwise()
    3908        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    3909            this = self._parse_bitwise()
    3910        else:
    3911            this = expression
    3912            expression = None
    3913
    3914        if self._match(TokenType.COLLATE):
    3915            collation = self._parse_bitwise()
    3916
    3917        return self.expression(
    3918            exp.Trim, this=this, position=position, expression=expression, collation=collation
    3919        )
    3920
    3921    def _parse_window_clause(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    3922        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    3923
    3924    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    3925        return self._parse_window(self._parse_id_var(), alias=True)
    3926
    3927    def _parse_respect_or_ignore_nulls(
    3928        self, this: t.Optional[exp.Expression]
    3929    ) -> t.Optional[exp.Expression]:
    3930        if self._match_text_seq("IGNORE", "NULLS"):
    3931            return self.expression(exp.IgnoreNulls, this=this)
    3932        if self._match_text_seq("RESPECT", "NULLS"):
    3933            return self.expression(exp.RespectNulls, this=this)
    3934        return this
    3935
    3936    def _parse_window(
    3937        self, this: t.Optional[exp.Expression], alias: bool = False
    3938    ) -> t.Optional[exp.Expression]:
    3939        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    3940            this = self.expression(exp.Filter, this=this, expression=self._parse_where())
    3941            self._match_r_paren()
    3942
    3943        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    3944        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    3945        if self._match_text_seq("WITHIN", "GROUP"):
    3946            order = self._parse_wrapped(self._parse_order)
    3947            this = self.expression(exp.WithinGroup, this=this, expression=order)
    3948
    3949        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    3950        # Some dialects choose to implement and some do not.
    3951        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    3952
    3953        # There is some code above in _parse_lambda that handles
    3954        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    3955
    3956        # The below changes handle
    3957        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    3958
    3959        # Oracle allows both formats
    3960        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    3961        #   and Snowflake chose to do the same for familiarity
    3962        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    3963        this = self._parse_respect_or_ignore_nulls(this)
    3964
    3965        # bigquery select from window x AS (partition by ...)
    3966        if alias:
    3967            over = None
    3968            self._match(TokenType.ALIAS)
    3969        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    3970            return this
    3971        else:
    3972            over = self._prev.text.upper()
    3973
    3974        if not self._match(TokenType.L_PAREN):
    3975            return self.expression(
    3976                exp.Window, this=this, alias=self._parse_id_var(False), over=over
    3977            )
    3978
    3979        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    3980
    3981        first = self._match(TokenType.FIRST)
    3982        if self._match_text_seq("LAST"):
    3983            first = False
    3984
    3985        partition = self._parse_partition_by()
    3986        order = self._parse_order()
    3987        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    3988
    3989        if kind:
    3990            self._match(TokenType.BETWEEN)
    3991            start = self._parse_window_spec()
    3992            self._match(TokenType.AND)
    3993            end = self._parse_window_spec()
    3994
    3995            spec = self.expression(
    3996                exp.WindowSpec,
    3997                kind=kind,
    3998                start=start["value"],
    3999                start_side=start["side"],
    4000                end=end["value"],
    4001                end_side=end["side"],
    4002            )
    4003        else:
    4004            spec = None
    4005
    4006        self._match_r_paren()
    4007
    4008        return self.expression(
    4009            exp.Window,
    4010            this=this,
    4011            partition_by=partition,
    4012            order=order,
    4013            spec=spec,
    4014            alias=window_alias,
    4015            over=over,
    4016            first=first,
    4017        )
    4018
    4019    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    4020        self._match(TokenType.BETWEEN)
    4021
    4022        return {
    4023            "value": (
    4024                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    4025                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    4026                or self._parse_bitwise()
    4027            ),
    4028            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    4029        }
    4030
    4031    def _parse_alias(
    4032        self, this: t.Optional[exp.Expression], explicit: bool = False
    4033    ) -> t.Optional[exp.Expression]:
    4034        any_token = self._match(TokenType.ALIAS)
    4035
    4036        if explicit and not any_token:
    4037            return this
    4038
    4039        if self._match(TokenType.L_PAREN):
    4040            aliases = self.expression(
    4041                exp.Aliases,
    4042                this=this,
    4043                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    4044            )
    4045            self._match_r_paren(aliases)
    4046            return aliases
    4047
    4048        alias = self._parse_id_var(any_token)
    4049
    4050        if alias:
    4051            return self.expression(exp.Alias, this=this, alias=alias)
    4052
    4053        return this
    4054
    4055    def _parse_id_var(
    4056        self,
    4057        any_token: bool = True,
    4058        tokens: t.Optional[t.Collection[TokenType]] = None,
    4059    ) -> t.Optional[exp.Expression]:
    4060        identifier = self._parse_identifier()
    4061
    4062        if identifier:
    4063            return identifier
    4064
    4065        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
    4066            quoted = self._prev.token_type == TokenType.STRING
    4067            return exp.Identifier(this=self._prev.text, quoted=quoted)
    4068
    4069        return None
    4070
    4071    def _parse_string(self) -> t.Optional[exp.Expression]:
    4072        if self._match(TokenType.STRING):
    4073            return self.PRIMARY_PARSERS[TokenType.STRING](self, self._prev)
    4074        return self._parse_placeholder()
    4075
    4076    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    4077        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    4078
    4079    def _parse_number(self) -> t.Optional[exp.Expression]:
    4080        if self._match(TokenType.NUMBER):
    4081            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
    4082        return self._parse_placeholder()
    4083
    4084    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    4085        if self._match(TokenType.IDENTIFIER):
    4086            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    4087        return self._parse_placeholder()
    4088
    4089    def _parse_var(
    4090        self, any_token: bool = False, tokens: t.Optional[t.Collection[TokenType]] = None
    4091    ) -> t.Optional[exp.Expression]:
    4092        if (
    4093            (any_token and self._advance_any())
    4094            or self._match(TokenType.VAR)
    4095            or (self._match_set(tokens) if tokens else False)
    4096        ):
    4097            return self.expression(exp.Var, this=self._prev.text)
    4098        return self._parse_placeholder()
    4099
    4100    def _advance_any(self) -> t.Optional[Token]:
    4101        if self._curr and self._curr.token_type not in self.RESERVED_KEYWORDS:
    4102            self._advance()
    4103            return self._prev
    4104        return None
    4105
    4106    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    4107        return self._parse_var() or self._parse_string()
    4108
    4109    def _parse_null(self) -> t.Optional[exp.Expression]:
    4110        if self._match(TokenType.NULL):
    4111            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    4112        return None
    4113
    4114    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    4115        if self._match(TokenType.TRUE):
    4116            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    4117        if self._match(TokenType.FALSE):
    4118            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    4119        return None
    4120
    4121    def _parse_star(self) -> t.Optional[exp.Expression]:
    4122        if self._match(TokenType.STAR):
    4123            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    4124        return None
    4125
    4126    def _parse_parameter(self) -> exp.Parameter:
    4127        wrapped = self._match(TokenType.L_BRACE)
    4128        this = self._parse_var() or self._parse_identifier() or self._parse_primary()
    4129        self._match(TokenType.R_BRACE)
    4130        return self.expression(exp.Parameter, this=this, wrapped=wrapped)
    4131
    4132    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    4133        if self._match_set(self.PLACEHOLDER_PARSERS):
    4134            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    4135            if placeholder:
    4136                return placeholder
    4137            self._advance(-1)
    4138        return None
    4139
    4140    def _parse_except(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    4141        if not self._match(TokenType.EXCEPT):
    4142            return None
    4143        if self._match(TokenType.L_PAREN, advance=False):
    4144            return self._parse_wrapped_csv(self._parse_column)
    4145        return self._parse_csv(self._parse_column)
    4146
    4147    def _parse_replace(self) -> t.Optional[t.List[t.Optional[exp.Expression]]]:
    4148        if not self._match(TokenType.REPLACE):
    4149            return None
    4150        if self._match(TokenType.L_PAREN, advance=False):
    4151            return self._parse_wrapped_csv(self._parse_expression)
    4152        return self._parse_csv(self._parse_expression)
    4153
    4154    def _parse_csv(
    4155        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    4156    ) -> t.List[t.Optional[exp.Expression]]:
    4157        parse_result = parse_method()
    4158        items = [parse_result] if parse_result is not None else []
    4159
    4160        while self._match(sep):
    4161            self._add_comments(parse_result)
    4162            parse_result = parse_method()
    4163            if parse_result is not None:
    4164                items.append(parse_result)
    4165
    4166        return items
    4167
    4168    def _parse_tokens(
    4169        self, parse_method: t.Callable, expressions: t.Dict
    4170    ) -> t.Optional[exp.Expression]:
    4171        this = parse_method()
    4172
    4173        while self._match_set(expressions):
    4174            this = self.expression(
    4175                expressions[self._prev.token_type],
    4176                this=this,
    4177                comments=self._prev_comments,
    4178                expression=parse_method(),
    4179            )
    4180
    4181        return this
    4182
    4183    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[t.Optional[exp.Expression]]:
    4184        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    4185
    4186    def _parse_wrapped_csv(
    4187        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    4188    ) -> t.List[t.Optional[exp.Expression]]:
    4189        return self._parse_wrapped(
    4190            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    4191        )
    4192
    4193    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    4194        wrapped = self._match(TokenType.L_PAREN)
    4195        if not wrapped and not optional:
    4196            self.raise_error("Expecting (")
    4197        parse_result = parse_method()
    4198        if wrapped:
    4199            self._match_r_paren()
    4200        return parse_result
    4201
    4202    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4203        return self._parse_select() or self._parse_set_operations(
    4204            self._parse_expression() if alias else self._parse_conjunction()
    4205        )
    4206
    4207    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    4208        return self._parse_query_modifiers(
    4209            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    4210        )
    4211
    4212    def _parse_transaction(self) -> exp.Transaction:
    4213        this = None
    4214        if self._match_texts(self.TRANSACTION_KIND):
    4215            this = self._prev.text
    4216
    4217        self._match_texts({"TRANSACTION", "WORK"})
    4218
    4219        modes = []
    4220        while True:
    4221            mode = []
    4222            while self._match(TokenType.VAR):
    4223                mode.append(self._prev.text)
    4224
    4225            if mode:
    4226                modes.append(" ".join(mode))
    4227            if not self._match(TokenType.COMMA):
    4228                break
    4229
    4230        return self.expression(exp.Transaction, this=this, modes=modes)
    4231
    4232    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    4233        chain = None
    4234        savepoint = None
    4235        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    4236
    4237        self._match_texts({"TRANSACTION", "WORK"})
    4238
    4239        if self._match_text_seq("TO"):
    4240            self._match_text_seq("SAVEPOINT")
    4241            savepoint = self._parse_id_var()
    4242
    4243        if self._match(TokenType.AND):
    4244            chain = not self._match_text_seq("NO")
    4245            self._match_text_seq("CHAIN")
    4246
    4247        if is_rollback:
    4248            return self.expression(exp.Rollback, savepoint=savepoint)
    4249
    4250        return self.expression(exp.Commit, chain=chain)
    4251
    4252    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    4253        if not self._match_text_seq("ADD"):
    4254            return None
    4255
    4256        self._match(TokenType.COLUMN)
    4257        exists_column = self._parse_exists(not_=True)
    4258        expression = self._parse_column_def(self._parse_field(any_token=True))
    4259
    4260        if expression:
    4261            expression.set("exists", exists_column)
    4262
    4263            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    4264            if self._match_texts(("FIRST", "AFTER")):
    4265                position = self._prev.text
    4266                column_position = self.expression(
    4267                    exp.ColumnPosition, this=self._parse_column(), position=position
    4268                )
    4269                expression.set("position", column_position)
    4270
    4271        return expression
    4272
    4273    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    4274        drop = self._match(TokenType.DROP) and self._parse_drop()
    4275        if drop and not isinstance(drop, exp.Command):
    4276            drop.set("kind", drop.args.get("kind", "COLUMN"))
    4277        return drop
    4278
    4279    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    4280    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    4281        return self.expression(
    4282            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    4283        )
    4284
    4285    def _parse_add_constraint(self) -> exp.AddConstraint:
    4286        this = None
    4287        kind = self._prev.token_type
    4288
    4289        if kind == TokenType.CONSTRAINT:
    4290            this = self._parse_id_var()
    4291
    4292            if self._match_text_seq("CHECK"):
    4293                expression = self._parse_wrapped(self._parse_conjunction)
    4294                enforced = self._match_text_seq("ENFORCED")
    4295
    4296                return self.expression(
    4297                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
    4298                )
    4299
    4300        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
    4301            expression = self._parse_foreign_key()
    4302        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
    4303            expression = self._parse_primary_key()
    4304        else:
    4305            expression = None
    4306
    4307        return self.expression(exp.AddConstraint, this=this, expression=expression)
    4308
    4309    def _parse_alter_table_add(self) -> t.List[t.Optional[exp.Expression]]:
    4310        index = self._index - 1
    4311
    4312        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
    4313            return self._parse_csv(self._parse_add_constraint)
    4314
    4315        self._retreat(index)
    4316        return self._parse_csv(self._parse_add_column)
    4317
    4318    def _parse_alter_table_alter(self) -> exp.AlterColumn:
    4319        self._match(TokenType.COLUMN)
    4320        column = self._parse_field(any_token=True)
    4321
    4322        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    4323            return self.expression(exp.AlterColumn, this=column, drop=True)
    4324        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    4325            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
    4326
    4327        self._match_text_seq("SET", "DATA")
    4328        return self.expression(
    4329            exp.AlterColumn,
    4330            this=column,
    4331            dtype=self._match_text_seq("TYPE") and self._parse_types(),
    4332            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    4333            using=self._match(TokenType.USING) and self._parse_conjunction(),
    4334        )
    4335
    4336    def _parse_alter_table_drop(self) -> t.List[t.Optional[exp.Expression]]:
    4337        index = self._index - 1
    4338
    4339        partition_exists = self._parse_exists()
    4340        if self._match(TokenType.PARTITION, advance=False):
    4341            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    4342
    4343        self._retreat(index)
    4344        return self._parse_csv(self._parse_drop_column)
    4345
    4346    def _parse_alter_table_rename(self) -> exp.RenameTable:
    4347        self._match_text_seq("TO")
    4348        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    4349
    4350    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    4351        start = self._prev
    4352
    4353        if not self._match(TokenType.TABLE):
    4354            return self._parse_as_command(start)
    4355
    4356        exists = self._parse_exists()
    4357        this = self._parse_table(schema=True)
    4358
    4359        if self._next:
    4360            self._advance()
    4361        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    4362
    4363        if parser:
    4364            actions = ensure_list(parser(self))
    4365
    4366            if not self._curr:
    4367                return self.expression(
    4368                    exp.AlterTable,
    4369                    this=this,
    4370                    exists=exists,
    4371                    actions=actions,
    4372                )
    4373        return self._parse_as_command(start)
    4374
    4375    def _parse_merge(self) -> exp.Merge:
    4376        self._match(TokenType.INTO)
    4377        target = self._parse_table()
    4378
    4379        self._match(TokenType.USING)
    4380        using = self._parse_table()
    4381
    4382        self._match(TokenType.ON)
    4383        on = self._parse_conjunction()
    4384
    4385        whens = []
    4386        while self._match(TokenType.WHEN):
    4387            matched = not self._match(TokenType.NOT)
    4388            self._match_text_seq("MATCHED")
    4389            source = (
    4390                False
    4391                if self._match_text_seq("BY", "TARGET")
    4392                else self._match_text_seq("BY", "SOURCE")
    4393            )
    4394            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
    4395
    4396            self._match(TokenType.THEN)
    4397
    4398            if self._match(TokenType.INSERT):
    4399                _this = self._parse_star()
    4400                if _this:
    4401                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    4402                else:
    4403                    then = self.expression(
    4404                        exp.Insert,
    4405                        this=self._parse_value(),
    4406                        expression=self._match(TokenType.VALUES) and self._parse_value(),
    4407                    )
    4408            elif self._match(TokenType.UPDATE):
    4409                expressions = self._parse_star()
    4410                if expressions:
    4411                    then = self.expression(exp.Update, expressions=expressions)
    4412                else:
    4413                    then = self.expression(
    4414                        exp.Update,
    4415                        expressions=self._match(TokenType.SET)
    4416                        and self._parse_csv(self._parse_equality),
    4417                    )
    4418            elif self._match(TokenType.DELETE):
    4419                then = self.expression(exp.Var, this=self._prev.text)
    4420            else:
    4421                then = None
    4422
    4423            whens.append(
    4424                self.expression(
    4425                    exp.When,
    4426                    matched=matched,
    4427                    source=source,
    4428                    condition=condition,
    4429                    then=then,
    4430                )
    4431            )
    4432
    4433        return self.expression(
    4434            exp.Merge,
    4435            this=target,
    4436            using=using,
    4437            on=on,
    4438            expressions=whens,
    4439        )
    4440
    4441    def _parse_show(self) -> t.Optional[exp.Expression]:
    4442        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    4443        if parser:
    4444            return parser(self)
    4445        self._advance()
    4446        return self.expression(exp.Show, this=self._prev.text.upper())
    4447
    4448    def _parse_set_item_assignment(
    4449        self, kind: t.Optional[str] = None
    4450    ) -> t.Optional[exp.Expression]:
    4451        index = self._index
    4452
    4453        if kind in {"GLOBAL", "SESSION"} and self._match_text_seq("TRANSACTION"):
    4454            return self._parse_set_transaction(global_=kind == "GLOBAL")
    4455
    4456        left = self._parse_primary() or self._parse_id_var()
    4457
    4458        if not self._match_texts(("=", "TO")):
    4459            self._retreat(index)
    4460            return None
    4461
    4462        right = self._parse_statement() or self._parse_id_var()
    4463        this = self.expression(exp.EQ, this=left, expression=right)
    4464
    4465        return self.expression(exp.SetItem, this=this, kind=kind)
    4466
    4467    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    4468        self._match_text_seq("TRANSACTION")
    4469        characteristics = self._parse_csv(
    4470            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    4471        )
    4472        return self.expression(
    4473            exp.SetItem,
    4474            expressions=characteristics,
    4475            kind="TRANSACTION",
    4476            **{"global": global_},  # type: ignore
    4477        )
    4478
    4479    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    4480        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    4481        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    4482
    4483    def _parse_set(self) -> exp.Set | exp.Command:
    4484        index = self._index
    4485        set_ = self.expression(exp.Set, expressions=self._parse_csv(self._parse_set_item))
    4486
    4487        if self._curr:
    4488            self._retreat(index)
    4489            return self._parse_as_command(self._prev)
    4490
    4491        return set_
    4492
    4493    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
    4494        for option in options:
    4495            if self._match_text_seq(*option.split(" ")):
    4496                return exp.var(option)
    4497        return None
    4498
    4499    def _parse_as_command(self, start: Token) -> exp.Command:
    4500        while self._curr:
    4501            self._advance()
    4502        text = self._find_sql(start, self._prev)
    4503        size = len(start.text)
    4504        return exp.Command(this=text[:size], expression=text[size:])
    4505
    4506    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    4507        settings = []
    4508
    4509        self._match_l_paren()
    4510        kind = self._parse_id_var()
    4511
    4512        if self._match(TokenType.L_PAREN):
    4513            while True:
    4514                key = self._parse_id_var()
    4515                value = self._parse_primary()
    4516
    4517                if not key and value is None:
    4518                    break
    4519                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    4520            self._match(TokenType.R_PAREN)
    4521
    4522        self._match_r_paren()
    4523
    4524        return self.expression(
    4525            exp.DictProperty,
    4526            this=this,
    4527            kind=kind.this if kind else None,
    4528            settings=settings,
    4529        )
    4530
    4531    def _parse_dict_range(self, this: str) -> exp.DictRange:
    4532        self._match_l_paren()
    4533        has_min = self._match_text_seq("MIN")
    4534        if has_min:
    4535            min = self._parse_var() or self._parse_primary()
    4536            self._match_text_seq("MAX")
    4537            max = self._parse_var() or self._parse_primary()
    4538        else:
    4539            max = self._parse_var() or self._parse_primary()
    4540            min = exp.Literal.number(0)
    4541        self._match_r_paren()
    4542        return self.expression(exp.DictRange, this=this, min=min, max=max)
    4543
    4544    def _find_parser(
    4545        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    4546    ) -> t.Optional[t.Callable]:
    4547        if not self._curr:
    4548            return None
    4549
    4550        index = self._index
    4551        this = []
    4552        while True:
    4553            # The current token might be multiple words
    4554            curr = self._curr.text.upper()
    4555            key = curr.split(" ")
    4556            this.append(curr)
    4557            self._advance()
    4558            result, trie = in_trie(trie, key)
    4559            if result == 0:
    4560                break
    4561            if result == 2:
    4562                subparser = parsers[" ".join(this)]
    4563                return subparser
    4564        self._retreat(index)
    4565        return None
    4566
    4567    def _match(self, token_type, advance=True, expression=None):
    4568        if not self._curr:
    4569            return None
    4570
    4571        if self._curr.token_type == token_type:
    4572            if advance:
    4573                self._advance()
    4574            self._add_comments(expression)
    4575            return True
    4576
    4577        return None
    4578
    4579    def _match_set(self, types, advance=True):
    4580        if not self._curr:
    4581            return None
    4582
    4583        if self._curr.token_type in types:
    4584            if advance:
    4585                self._advance()
    4586            return True
    4587
    4588        return None
    4589
    4590    def _match_pair(self, token_type_a, token_type_b, advance=True):
    4591        if not self._curr or not self._next:
    4592            return None
    4593
    4594        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    4595            if advance:
    4596                self._advance(2)
    4597            return True
    4598
    4599        return None
    4600
    4601    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    4602        if not self._match(TokenType.L_PAREN, expression=expression):
    4603            self.raise_error("Expecting (")
    4604
    4605    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    4606        if not self._match(TokenType.R_PAREN, expression=expression):
    4607            self.raise_error("Expecting )")
    4608
    4609    def _match_texts(self, texts, advance=True):
    4610        if self._curr and self._curr.text.upper() in texts:
    4611            if advance:
    4612                self._advance()
    4613            return True
    4614        return False
    4615
    4616    def _match_text_seq(self, *texts, advance=True):
    4617        index = self._index
    4618        for text in texts:
    4619            if self._curr and self._curr.text.upper() == text:
    4620                self._advance()
    4621            else:
    4622                self._retreat(index)
    4623                return False
    4624
    4625        if not advance:
    4626            self._retreat(index)
    4627
    4628        return True
    4629
    4630    @t.overload
    4631    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
    4632        ...
    4633
    4634    @t.overload
    4635    def _replace_columns_with_dots(
    4636        self, this: t.Optional[exp.Expression]
    4637    ) -> t.Optional[exp.Expression]:
    4638        ...
    4639
    4640    def _replace_columns_with_dots(self, this):
    4641        if isinstance(this, exp.Dot):
    4642            exp.replace_children(this, self._replace_columns_with_dots)
    4643        elif isinstance(this, exp.Column):
    4644            exp.replace_children(this, self._replace_columns_with_dots)
    4645            table = this.args.get("table")
    4646            this = (
    4647                self.expression(exp.Dot, this=table, expression=this.this)
    4648                if table
    4649                else self.expression(exp.Var, this=this.name)
    4650            )
    4651        elif isinstance(this, exp.Identifier):
    4652            this = self.expression(exp.Var, this=this.name)
    4653
    4654        return this
    4655
    4656    def _replace_lambda(
    4657        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
    4658    ) -> t.Optional[exp.Expression]:
    4659        if not node:
    4660            return node
    4661
    4662        for column in node.find_all(exp.Column):
    4663            if column.parts[0].name in lambda_variables:
    4664                dot_or_id = column.to_dot() if column.table else column.this
    4665                parent = column.parent
    4666
    4667                while isinstance(parent, exp.Dot):
    4668                    if not isinstance(parent.parent, exp.Dot):
    4669                        parent.replace(dot_or_id)
    4670                        break
    4671                    parent = parent.parent
    4672                else:
    4673                    if column is node:
    4674                        node = dot_or_id
    4675                    else:
    4676                        column.replace(dot_or_id)
    4677        return node

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: Determines 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) View Source

    829    def __init__(
    830        self,
    831        error_level: t.Optional[ErrorLevel] = None,
    832        error_message_context: int = 100,
    833        max_errors: int = 3,
    834    ):
    835        self.error_level = error_level or ErrorLevel.IMMEDIATE
    836        self.error_message_context = error_message_context
    837        self.max_errors = max_errors
    838        self.reset()

def reset(self): View Source

    840    def reset(self):
    841        self.sql = ""
    842        self.errors = []
    843        self._tokens = []
    844        self._index = 0
    845        self._curr = None
    846        self._next = None
    847        self._prev = None
    848        self._prev_comments = None

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

    850    def parse(
    851        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    852    ) -> t.List[t.Optional[exp.Expression]]:
    853        """
    854        Parses a list of tokens and returns a list of syntax trees, one tree
    855        per parsed SQL statement.
    856
    857        Args:
    858            raw_tokens: The list of tokens.
    859            sql: The original SQL string, used to produce helpful debug messages.
    860
    861        Returns:
    862            The list of the produced syntax trees.
    863        """
    864        return self._parse(
    865            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    866        )

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

    868    def parse_into(
    869        self,
    870        expression_types: exp.IntoType,
    871        raw_tokens: t.List[Token],
    872        sql: t.Optional[str] = None,
    873    ) -> t.List[t.Optional[exp.Expression]]:
    874        """
    875        Parses a list of tokens into a given Expression type. If a collection of Expression
    876        types is given instead, this method will try to parse the token list into each one
    877        of them, stopping at the first for which the parsing succeeds.
    878
    879        Args:
    880            expression_types: The expression type(s) to try and parse the token list into.
    881            raw_tokens: The list of tokens.
    882            sql: The original SQL string, used to produce helpful debug messages.
    883
    884        Returns:
    885            The target Expression.
    886        """
    887        errors = []
    888        for expression_type in ensure_list(expression_types):
    889            parser = self.EXPRESSION_PARSERS.get(expression_type)
    890            if not parser:
    891                raise TypeError(f"No parser registered for {expression_type}")
    892
    893            try:
    894                return self._parse(parser, raw_tokens, sql)
    895            except ParseError as e:
    896                e.errors[0]["into_expression"] = expression_type
    897                errors.append(e)
    898
    899        raise ParseError(
    900            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    901            errors=merge_errors(errors),
    902        ) 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

    939    def check_errors(self) -> None:
    940        """Logs or raises any found errors, depending on the chosen error level setting."""
    941        if self.error_level == ErrorLevel.WARN:
    942            for error in self.errors:
    943                logger.error(str(error))
    944        elif self.error_level == ErrorLevel.RAISE and self.errors:
    945            raise ParseError(
    946                concat_messages(self.errors, self.max_errors),
    947                errors=merge_errors(self.errors),
    948            )

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

    950    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    951        """
    952        Appends an error in the list of recorded errors or raises it, depending on the chosen
    953        error level setting.
    954        """
    955        token = token or self._curr or self._prev or Token.string("")
    956        start = token.start
    957        end = token.end + 1
    958        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    959        highlight = self.sql[start:end]
    960        end_context = self.sql[end : end + self.error_message_context]
    961
    962        error = ParseError.new(
    963            f"{message}. Line {token.line}, Col: {token.col}.\n"
    964            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    965            description=message,
    966            line=token.line,
    967            col=token.col,
    968            start_context=start_context,
    969            highlight=highlight,
    970            end_context=end_context,
    971        )
    972
    973        if self.error_level == ErrorLevel.IMMEDIATE:
    974            raise error
    975
    976        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

    978    def expression(
    979        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    980    ) -> E:
    981        """
    982        Creates a new, validated Expression.
    983
    984        Args:
    985            exp_class: The expression class to instantiate.
    986            comments: An optional list of comments to attach to the expression.
    987            kwargs: The arguments to set for the expression along with their respective values.
    988
    989        Returns:
    990            The target expression.
    991        """
    992        instance = exp_class(**kwargs)
    993        instance.add_comments(comments) if comments else self._add_comments(instance)
    994        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

    1001    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1002        """
    1003        Validates an Expression, making sure that all its mandatory arguments are set.
    1004
    1005        Args:
    1006            expression: The expression to validate.
    1007            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1008
    1009        Returns:
    1010            The validated expression.
    1011        """
    1012        if self.error_level != ErrorLevel.IGNORE:
    1013            for error_message in expression.error_messages(args):
    1014                self.raise_error(error_message)
    1015
    1016        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.