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

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

def reset(self): View Source

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

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

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

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

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

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

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

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

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

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