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

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

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

    935    def __init__(
    936        self,
    937        error_level: t.Optional[ErrorLevel] = None,
    938        error_message_context: int = 100,
    939        max_errors: int = 3,
    940    ):
    941        self.error_level = error_level or ErrorLevel.IMMEDIATE
    942        self.error_message_context = error_message_context
    943        self.max_errors = max_errors
    944        self._tokenizer = self.TOKENIZER_CLASS()
    945        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_CAT': <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'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, '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'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, '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'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, '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'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, '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'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, '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'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, '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_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, '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'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, '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'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, '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'>}
STRUCT_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.ARRAY: 'ARRAY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INET: 'INET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.INT128: 'INT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UNKNOWN: 'UNKNOWN'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
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.DOT: 'DOT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.LT: 'LT'>, <TokenType.EQ: 'EQ'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PLUS: 'PLUS'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.GT: 'GT'>, <TokenType.NOT: 'NOT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.COLON: 'COLON'>, <TokenType.DASH: 'DASH'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SELECT: 'SELECT'>, <TokenType.AMP: 'AMP'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.STAR: 'STAR'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.PIPE: 'PIPE'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.COMMA: 'COMMA'>, <TokenType.MOD: 'MOD'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.SLASH: 'SLASH'>, <TokenType.HASH: 'HASH'>, <TokenType.CARET: 'CARET'>, <TokenType.QUOTE: 'QUOTE'>}
DB_CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DICTIONARY: 'DICTIONARY'>}
ID_VAR_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.FULL: 'FULL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.SEMI: 'SEMI'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
INTERVAL_VARS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.FULL: 'FULL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.SEMI: 'SEMI'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
TABLE_ALIAS_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
UPDATE_ALIAS_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
TRIM_TYPES = {'BOTH', 'TRAILING', 'LEADING'}
FUNC_TOKENS = {<TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.INSERT: 'INSERT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATE: 'DATE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.GLOB: 'GLOB'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.XOR: 'XOR'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.INT128: 'INT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LIKE: 'LIKE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ALL: 'ALL'>}
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'>}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.INNER: 'INNER'>}
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.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <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.HEREDOC_STRING: 'HEREDOC_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>>, <TokenType.FOR: 'FOR'>: <function Parser.<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>>, 'SAMPLE': <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>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <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>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'UNIQUE', 'LIKE', 'CHECK', 'PRIMARY KEY', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <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>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <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 = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
MODIFIABLES = (<class 'sqlglot.expressions.Subquery'>, <class 'sqlglot.expressions.Subqueryable'>, <class 'sqlglot.expressions.Table'>)
DDL_SELECT_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ WRITE', 'READ ONLY', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'FAIL', 'ROLLBACK', 'ABORT', 'REPLACE', 'IGNORE'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
CLONE_KINDS = {'OFFSET', 'STATEMENT', 'TIMESTAMP'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'NULLS', 'ASC'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.SEMI: 'SEMI'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
FETCH_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.SEMI: 'SEMI'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.LOAD: 'LOAD'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IS: 'IS'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULL: 'NULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MONEY: 'MONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.FULL: 'FULL'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DESC: 'DESC'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.BIT: 'BIT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INT256: 'INT256'>, <TokenType.UUID: 'UUID'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.YEAR: 'YEAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ANY: 'ANY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INET: 'INET'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SET: 'SET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT128: 'INT128'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CASE: 'CASE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT: 'INT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.END: 'END'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.KILL: 'KILL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.VAR: 'VAR'>, <TokenType.SEMI: 'SEMI'>, <TokenType.XML: 'XML'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TOP: 'TOP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SOME: 'SOME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASC: 'ASC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DIV: 'DIV'>, <TokenType.ROW: 'ROW'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.ALL: 'ALL'>}
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
ALTER_TABLE_ADD_COLUMN_KEYWORD = True
TABLESAMPLE_CSV = False
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
TOKENIZER_CLASS: Type[sqlglot.tokens.Tokenizer] = <class 'sqlglot.executor.python.Python.Tokenizer'>
INDEX_OFFSET: int = 0
UNNEST_COLUMN_ONLY: bool = False
ALIAS_POST_TABLESAMPLE: bool = False
STRICT_STRING_CONCAT = False
SUPPORTS_USER_DEFINED_TYPES = True
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

    947    def reset(self):
    948        self.sql = ""
    949        self.errors = []
    950        self._tokens = []
    951        self._index = 0
    952        self._curr = None
    953        self._next = None
    954        self._prev = None
    955        self._prev_comments = None

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

    957    def parse(
    958        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    959    ) -> t.List[t.Optional[exp.Expression]]:
    960        """
    961        Parses a list of tokens and returns a list of syntax trees, one tree
    962        per parsed SQL statement.
    963
    964        Args:
    965            raw_tokens: The list of tokens.
    966            sql: The original SQL string, used to produce helpful debug messages.
    967
    968        Returns:
    969            The list of the produced syntax trees.
    970        """
    971        return self._parse(
    972            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    973        )

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

     975    def parse_into(
     976        self,
     977        expression_types: exp.IntoType,
     978        raw_tokens: t.List[Token],
     979        sql: t.Optional[str] = None,
     980    ) -> t.List[t.Optional[exp.Expression]]:
     981        """
     982        Parses a list of tokens into a given Expression type. If a collection of Expression
     983        types is given instead, this method will try to parse the token list into each one
     984        of them, stopping at the first for which the parsing succeeds.
     985
     986        Args:
     987            expression_types: The expression type(s) to try and parse the token list into.
     988            raw_tokens: The list of tokens.
     989            sql: The original SQL string, used to produce helpful debug messages.
     990
     991        Returns:
     992            The target Expression.
     993        """
     994        errors = []
     995        for expression_type in ensure_list(expression_types):
     996            parser = self.EXPRESSION_PARSERS.get(expression_type)
     997            if not parser:
     998                raise TypeError(f"No parser registered for {expression_type}")
     999
    1000            try:
    1001                return self._parse(parser, raw_tokens, sql)
    1002            except ParseError as e:
    1003                e.errors[0]["into_expression"] = expression_type
    1004                errors.append(e)
    1005
    1006        raise ParseError(
    1007            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1008            errors=merge_errors(errors),
    1009        ) 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

    1046    def check_errors(self) -> None:
    1047        """Logs or raises any found errors, depending on the chosen error level setting."""
    1048        if self.error_level == ErrorLevel.WARN:
    1049            for error in self.errors:
    1050                logger.error(str(error))
    1051        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1052            raise ParseError(
    1053                concat_messages(self.errors, self.max_errors),
    1054                errors=merge_errors(self.errors),
    1055            )

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

    1057    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1058        """
    1059        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1060        error level setting.
    1061        """
    1062        token = token or self._curr or self._prev or Token.string("")
    1063        start = token.start
    1064        end = token.end + 1
    1065        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1066        highlight = self.sql[start:end]
    1067        end_context = self.sql[end : end + self.error_message_context]
    1068
    1069        error = ParseError.new(
    1070            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1071            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1072            description=message,
    1073            line=token.line,
    1074            col=token.col,
    1075            start_context=start_context,
    1076            highlight=highlight,
    1077            end_context=end_context,
    1078        )
    1079
    1080        if self.error_level == ErrorLevel.IMMEDIATE:
    1081            raise error
    1082
    1083        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

    1085    def expression(
    1086        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1087    ) -> E:
    1088        """
    1089        Creates a new, validated Expression.
    1090
    1091        Args:
    1092            exp_class: The expression class to instantiate.
    1093            comments: An optional list of comments to attach to the expression.
    1094            kwargs: The arguments to set for the expression along with their respective values.
    1095
    1096        Returns:
    1097            The target expression.
    1098        """
    1099        instance = exp_class(**kwargs)
    1100        instance.add_comments(comments) if comments else self._add_comments(instance)
    1101        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

    1108    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1109        """
    1110        Validates an Expression, making sure that all its mandatory arguments are set.
    1111
    1112        Args:
    1113            expression: The expression to validate.
    1114            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1115
    1116        Returns:
    1117            The validated expression.
    1118        """
    1119        if self.error_level != ErrorLevel.IGNORE:
    1120            for error_message in expression.error_messages(args):
    1121                self.raise_error(error_message)
    1122
    1123        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