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