sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

    848    def __init__(
    849        self,
    850        error_level: t.Optional[ErrorLevel] = None,
    851        error_message_context: int = 100,
    852        max_errors: int = 3,
    853    ):
    854        self.error_level = error_level or ErrorLevel.IMMEDIATE
    855        self.error_message_context = error_message_context
    856        self.max_errors = max_errors
    857        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.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INT128: 'INT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.XML: 'XML'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INET: 'INET'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>}
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.DASH: 'DASH'>, <TokenType.GT: 'GT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.SLASH: 'SLASH'>, <TokenType.LT: 'LT'>, <TokenType.COLON: 'COLON'>, <TokenType.NOT: 'NOT'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.AMP: 'AMP'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.CARET: 'CARET'>, <TokenType.SELECT: 'SELECT'>, <TokenType.EQ: 'EQ'>, <TokenType.HASH: 'HASH'>, <TokenType.MOD: 'MOD'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.COMMA: 'COMMA'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.TILDA: 'TILDA'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STAR: 'STAR'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.DOT: 'DOT'>}
DB_CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>}
CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.FUNCTION: 'FUNCTION'>}
ID_VAR_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FULL: 'FULL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.END: 'END'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ROWS: 'ROWS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
INTERVAL_VARS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FULL: 'FULL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ROWS: 'ROWS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
TABLE_ALIAS_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.END: 'END'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ROWS: 'ROWS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.END: 'END'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ROWS: 'ROWS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.END: 'END'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.ROWS: 'ROWS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INT128: 'INT128'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.XML: 'XML'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.XOR: 'XOR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM: 'ENUM'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.GLOB: 'GLOB'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.ISNULL: 'ISNULL'>}
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.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>, <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 = {'CHECK', 'PRIMARY KEY', 'LIKE', 'UNIQUE', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {<TokenType.ANY: 'ANY'>: <function Parser.<lambda>>, <TokenType.CASE: 'CASE'>: <function Parser.<lambda>>, <TokenType.IF: 'IF'>: <function Parser.<lambda>>, <TokenType.NEXT_VALUE_FOR: 'NEXT_VALUE_FOR'>: <function Parser.<lambda>>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'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.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL READ UNCOMMITTED', 'ISOLATION LEVEL SERIALIZABLE', 'READ WRITE', 'READ ONLY', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'ROLLBACK', 'ABORT', 'FAIL', 'IGNORE', 'REPLACE'}
CLONE_KINDS = {'STATEMENT', 'OFFSET', 'TIMESTAMP'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>, <TokenType.IGNORE: 'IGNORE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.INT128: 'INT128'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.JSON: 'JSON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.XML: 'XML'>, <TokenType.SHOW: 'SHOW'>, <TokenType.UUID: 'UUID'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIME: 'TIME'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DESC: 'DESC'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INT256: 'INT256'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FULL: 'FULL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CASE: 'CASE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ASC: 'ASC'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DIV: 'DIV'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.JSONB: 'JSONB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.END: 'END'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ANTI: 'ANTI'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IF: 'IF'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ANY: 'ANY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.INET: 'INET'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.BIT: 'BIT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INT: 'INT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SOME: 'SOME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.IS: 'IS'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BIGINT: 'BIGINT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_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

    859    def reset(self):
    860        self.sql = ""
    861        self.errors = []
    862        self._tokens = []
    863        self._index = 0
    864        self._curr = None
    865        self._next = None
    866        self._prev = None
    867        self._prev_comments = None

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

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

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

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

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

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

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

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

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