Edit on GitHub

# sqlglot.parser

View Source

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

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

    843    def __init__(
    844        self,
    845        error_level: t.Optional[ErrorLevel] = None,
    846        error_message_context: int = 100,
    847        max_errors: int = 3,
    848    ):
    849        self.error_level = error_level or ErrorLevel.IMMEDIATE
    850        self.error_message_context = error_message_context
    851        self.max_errors = max_errors
    852        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Concat'>>, 'CONCAT_WS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConcatWs'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hex'>>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'LAST_DATE_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDateOfMonth'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log'>>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeConcat'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SET_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SetAgg'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'LIKE': <function parse_like>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
NESTED_TYPE_TOKENS = {<TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ARRAY: 'ARRAY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.XML: 'XML'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIME: 'TIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INT256: 'INT256'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_KEYWORDS = {<TokenType.GT: 'GT'>, <TokenType.TILDA: 'TILDA'>, <TokenType.LT: 'LT'>, <TokenType.NOT: 'NOT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.CARET: 'CARET'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.EQ: 'EQ'>, <TokenType.STAR: 'STAR'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.DASH: 'DASH'>, <TokenType.COLON: 'COLON'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.MOD: 'MOD'>, <TokenType.AMP: 'AMP'>, <TokenType.COMMA: 'COMMA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.PIPE: 'PIPE'>, <TokenType.HASH: 'HASH'>, <TokenType.DOT: 'DOT'>}
DB_CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>}
CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLUMN: 'COLUMN'>}
ID_VAR_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CASE: 'CASE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FULL: 'FULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.END: 'END'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
INTERVAL_VARS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CASE: 'CASE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FULL: 'FULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
TABLE_ALIAS_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CASE: 'CASE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.END: 'END'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CASE: 'CASE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.END: 'END'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CASE: 'CASE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.END: 'END'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIME: 'TIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.SOME: 'SOME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ALL: 'ALL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LIKE: 'LIKE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT128: 'INT128'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.GLOB: 'GLOB'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>, <TokenType.DPIPE: 'DPIPE'>: <class 'sqlglot.expressions.SafeDPipe'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMESTAMPS = {<TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.FROM: 'FROM'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'UNIQUE', 'LIKE', 'FOREIGN KEY', 'PRIMARY KEY', 'CHECK'}
NO_PAREN_FUNCTION_PARSERS = {<TokenType.ANY: 'ANY'>: <function Parser.<lambda>>, <TokenType.CASE: 'CASE'>: <function Parser.<lambda>>, <TokenType.IF: 'IF'>: <function Parser.<lambda>>, <TokenType.NEXT_VALUE_FOR: 'NEXT_VALUE_FOR'>: <function Parser.<lambda>>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS: Dict[str, Callable] = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONCAT': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS: Dict[sqlglot.expressions.DataType.Type, Callable] = {}
MODIFIABLES = (<class 'sqlglot.expressions.Subquery'>, <class 'sqlglot.expressions.Subqueryable'>, <class 'sqlglot.expressions.Table'>)
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'IMMEDIATE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL READ COMMITTED', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ WRITE', 'ISOLATION LEVEL SERIALIZABLE', 'READ ONLY'}
INSERT_ALTERNATIVES = {'IGNORE', 'REPLACE', 'FAIL', 'ROLLBACK', 'ABORT'}
CLONE_KINDS = {'STATEMENT', 'TIMESTAMP', 'OFFSET'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.DATETIME: 'DATETIME'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.SOME: 'SOME'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IF: 'IF'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.ASC: 'ASC'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT256: 'INT256'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ROW: 'ROW'>, <TokenType.ANY: 'ANY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SET: 'SET'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.INET: 'INET'>, <TokenType.XML: 'XML'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT128: 'INT128'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CASE: 'CASE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UUID: 'UUID'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FALSE: 'FALSE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FULL: 'FULL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.END: 'END'>, <TokenType.BIT: 'BIT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TOP: 'TOP'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.INT: 'INT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
STRICT_CAST = True
CONCAT_NULL_OUTPUTS_STRING = False
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_BASE_FIRST = True
LOG_DEFAULTS_TO_LN = False
INDEX_OFFSET: int = 0
UNNEST_COLUMN_ONLY: bool = False
ALIAS_POST_TABLESAMPLE: bool = False
STRICT_STRING_CONCAT = False
NULL_ORDERING: str = 'nulls_are_small'
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
FORMAT_MAPPING: Dict[str, str] = {}
FORMAT_TRIE: Dict = {}
TIME_MAPPING: Dict[str, str] = {}
TIME_TRIE: Dict = {}
error_level
error_message_context
max_errors
def reset(self): View Source

    854    def reset(self):
    855        self.sql = ""
    856        self.errors = []
    857        self._tokens = []
    858        self._index = 0
    859        self._curr = None
    860        self._next = None
    861        self._prev = None
    862        self._prev_comments = None

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

    864    def parse(
    865        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    866    ) -> t.List[t.Optional[exp.Expression]]:
    867        """
    868        Parses a list of tokens and returns a list of syntax trees, one tree
    869        per parsed SQL statement.
    870
    871        Args:
    872            raw_tokens: The list of tokens.
    873            sql: The original SQL string, used to produce helpful debug messages.
    874
    875        Returns:
    876            The list of the produced syntax trees.
    877        """
    878        return self._parse(
    879            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    880        )

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

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

    953    def check_errors(self) -> None:
    954        """Logs or raises any found errors, depending on the chosen error level setting."""
    955        if self.error_level == ErrorLevel.WARN:
    956            for error in self.errors:
    957                logger.error(str(error))
    958        elif self.error_level == ErrorLevel.RAISE and self.errors:
    959            raise ParseError(
    960                concat_messages(self.errors, self.max_errors),
    961                errors=merge_errors(self.errors),
    962            )

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

    964    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    965        """
    966        Appends an error in the list of recorded errors or raises it, depending on the chosen
    967        error level setting.
    968        """
    969        token = token or self._curr or self._prev or Token.string("")
    970        start = token.start
    971        end = token.end + 1
    972        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    973        highlight = self.sql[start:end]
    974        end_context = self.sql[end : end + self.error_message_context]
    975
    976        error = ParseError.new(
    977            f"{message}. Line {token.line}, Col: {token.col}.\n"
    978            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    979            description=message,
    980            line=token.line,
    981            col=token.col,
    982            start_context=start_context,
    983            highlight=highlight,
    984            end_context=end_context,
    985        )
    986
    987        if self.error_level == ErrorLevel.IMMEDIATE:
    988            raise error
    989
    990        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

     992    def expression(
     993        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
     994    ) -> E:
     995        """
     996        Creates a new, validated Expression.
     997
     998        Args:
     999            exp_class: The expression class to instantiate.
    1000            comments: An optional list of comments to attach to the expression.
    1001            kwargs: The arguments to set for the expression along with their respective values.
    1002
    1003        Returns:
    1004            The target expression.
    1005        """
    1006        instance = exp_class(**kwargs)
    1007        instance.add_comments(comments) if comments else self._add_comments(instance)
    1008        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

    1015    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1016        """
    1017        Validates an Expression, making sure that all its mandatory arguments are set.
    1018
    1019        Args:
    1020            expression: The expression to validate.
    1021            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1022
    1023        Returns:
    1024            The validated expression.
    1025        """
    1026        if self.error_level != ErrorLevel.IGNORE:
    1027            for error_message in expression.error_messages(args):
    1028                self.raise_error(error_message)
    1029
    1030        return expression

Validates an Expression, making sure that all its mandatory arguments are set.

###### Arguments:

- expression: The expression to validate.
- args: An optional list of items that was used to instantiate the expression, if it's a Func.

###### Returns:

> The validated expression.

errors
sql