sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

logger = <Logger sqlglot (WARNING)>
def parse_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

    22def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    23    if len(args) == 1 and args[0].is_star:
    24        return exp.StarMap(this=args[0])
    25
    26    keys = []
    27    values = []
    28    for i in range(0, len(args), 2):
    29        keys.append(args[i])
    30        values.append(args[i + 1])
    31
    32    return exp.VarMap(
    33        keys=exp.Array(expressions=keys),
    34        values=exp.Array(expressions=values),
    35    )

def parse_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like: View Source

    38def parse_like(args: t.List) -> exp.Escape | exp.Like:
    39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    40    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

    43def binary_range_parser(
    44    expr_type: t.Type[exp.Expression],
    45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
    46    return lambda self, this: self._parse_escape(
    47        self.expression(expr_type, this=this, expression=self._parse_bitwise())
    48    )

def parse_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func: View Source

    51def parse_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    52    # Default argument order is base, expression
    53    this = seq_get(args, 0)
    54    expression = seq_get(args, 1)
    55
    56    if expression:
    57        if not dialect.LOG_BASE_FIRST:
    58            this, expression = expression, this
    59        return exp.Log(this=this, expression=expression)
    60
    61    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)

class Parser: View Source

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

Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.

###### Arguments:

- error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
- error_message_context: Determines the amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
- max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3

Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) View Source

     988    def __init__(
     989        self,
     990        error_level: t.Optional[ErrorLevel] = None,
     991        error_message_context: int = 100,
     992        max_errors: int = 3,
     993        dialect: DialectType = None,
     994    ):
     995        from sqlglot.dialects import Dialect
     996
     997        self.error_level = error_level or ErrorLevel.IMMEDIATE
     998        self.error_message_context = error_message_context
     999        self.max_errors = max_errors
    1000        self.dialect = Dialect.get_or_raise(dialect)
    1001        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, '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'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, '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'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, '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'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, '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'>>, 'COUNTIF': <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'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, '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'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, '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'>>, 'GET_PATH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GetPath'>>, '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_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, '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_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, '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': <function parse_logarithm>, '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'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, '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'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, '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_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, '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_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, '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_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, '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_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, '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_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, '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>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, '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.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.JSON: 'JSON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
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_TOKENS = {<TokenType.R_BRACE: 'R_BRACE'>, <TokenType.PLUS: 'PLUS'>, <TokenType.LT: 'LT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.EQ: 'EQ'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.MOD: 'MOD'>, <TokenType.SLASH: 'SLASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.TILDA: 'TILDA'>, <TokenType.COLON: 'COLON'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.CARET: 'CARET'>, <TokenType.DOT: 'DOT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.GT: 'GT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.AMP: 'AMP'>, <TokenType.DASH: 'DASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.HASH: 'HASH'>, <TokenType.NOT: 'NOT'>, <TokenType.STAR: 'STAR'>, <TokenType.SEMICOLON: 'SEMICOLON'>}
DB_CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATABASE: 'DATABASE'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>}
ID_VAR_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FULL: 'FULL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
INTERVAL_VARS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FULL: 'FULL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
TABLE_ALIAS_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
UPDATE_ALIAS_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.GLOB: 'GLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.ANY: 'ANY'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INSERT: 'INSERT'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.XOR: 'XOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <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'>}
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'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.INNER: 'INNER'>, <TokenType.CROSS: 'CROSS'>}
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.When'>: <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.REFRESH: 'REFRESH'>: <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.UNICODE_STRING: 'UNICODE_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': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <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>>, 'CONTAINS': <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>>, 'INPUT': <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>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <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>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <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>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <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>>, 'PERIOD': <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 = {'PRIMARY KEY', 'LIKE', 'CHECK', 'PERIOD', 'FOREIGN KEY', 'UNIQUE'}
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.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <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.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS = {'READ ONLY', 'ISOLATION LEVEL REPEATABLE READ', 'READ WRITE', 'ISOLATION LEVEL READ UNCOMMITTED', 'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'ROLLBACK', 'REPLACE', 'IGNORE', 'ABORT', 'FAIL'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'STREAM', 'TIMESTAMP', 'OFFSET', 'STATEMENT'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'NULLS'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FULL: 'FULL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
FETCH_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FULL: 'FULL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.INT256: 'INT256'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CASE: 'CASE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KILL: 'KILL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.UUID: 'UUID'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SET: 'SET'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INET: 'INET'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT: 'INT'>, <TokenType.ROW: 'ROW'>, <TokenType.DATE: 'DATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UINT: 'UINT'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.JSON: 'JSON'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CACHE: 'CACHE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.VAR: 'VAR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.ANTI: 'ANTI'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.SOME: 'SOME'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FULL: 'FULL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.FILTER: 'FILTER'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ASC: 'ASC'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.IS: 'IS'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.NULL: 'NULL'>, <TokenType.MAP: 'MAP'>, <TokenType.TOP: 'TOP'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DESC: 'DESC'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIME: 'TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.SUPER: 'SUPER'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'order', 'limit', 'offset'}
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self): View Source

    1003    def reset(self):
    1004        self.sql = ""
    1005        self.errors = []
    1006        self._tokens = []
    1007        self._index = 0
    1008        self._curr = None
    1009        self._next = None
    1010        self._prev = None
    1011        self._prev_comments = None

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

    1013    def parse(
    1014        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1015    ) -> t.List[t.Optional[exp.Expression]]:
    1016        """
    1017        Parses a list of tokens and returns a list of syntax trees, one tree
    1018        per parsed SQL statement.
    1019
    1020        Args:
    1021            raw_tokens: The list of tokens.
    1022            sql: The original SQL string, used to produce helpful debug messages.
    1023
    1024        Returns:
    1025            The list of the produced syntax trees.
    1026        """
    1027        return self._parse(
    1028            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1029        )

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

    1031    def parse_into(
    1032        self,
    1033        expression_types: exp.IntoType,
    1034        raw_tokens: t.List[Token],
    1035        sql: t.Optional[str] = None,
    1036    ) -> t.List[t.Optional[exp.Expression]]:
    1037        """
    1038        Parses a list of tokens into a given Expression type. If a collection of Expression
    1039        types is given instead, this method will try to parse the token list into each one
    1040        of them, stopping at the first for which the parsing succeeds.
    1041
    1042        Args:
    1043            expression_types: The expression type(s) to try and parse the token list into.
    1044            raw_tokens: The list of tokens.
    1045            sql: The original SQL string, used to produce helpful debug messages.
    1046
    1047        Returns:
    1048            The target Expression.
    1049        """
    1050        errors = []
    1051        for expression_type in ensure_list(expression_types):
    1052            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1053            if not parser:
    1054                raise TypeError(f"No parser registered for {expression_type}")
    1055
    1056            try:
    1057                return self._parse(parser, raw_tokens, sql)
    1058            except ParseError as e:
    1059                e.errors[0]["into_expression"] = expression_type
    1060                errors.append(e)
    1061
    1062        raise ParseError(
    1063            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1064            errors=merge_errors(errors),
    1065        ) 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

    1102    def check_errors(self) -> None:
    1103        """Logs or raises any found errors, depending on the chosen error level setting."""
    1104        if self.error_level == ErrorLevel.WARN:
    1105            for error in self.errors:
    1106                logger.error(str(error))
    1107        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1108            raise ParseError(
    1109                concat_messages(self.errors, self.max_errors),
    1110                errors=merge_errors(self.errors),
    1111            )

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

    1113    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1114        """
    1115        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1116        error level setting.
    1117        """
    1118        token = token or self._curr or self._prev or Token.string("")
    1119        start = token.start
    1120        end = token.end + 1
    1121        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1122        highlight = self.sql[start:end]
    1123        end_context = self.sql[end : end + self.error_message_context]
    1124
    1125        error = ParseError.new(
    1126            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1127            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1128            description=message,
    1129            line=token.line,
    1130            col=token.col,
    1131            start_context=start_context,
    1132            highlight=highlight,
    1133            end_context=end_context,
    1134        )
    1135
    1136        if self.error_level == ErrorLevel.IMMEDIATE:
    1137            raise error
    1138
    1139        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

    1141    def expression(
    1142        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1143    ) -> E:
    1144        """
    1145        Creates a new, validated Expression.
    1146
    1147        Args:
    1148            exp_class: The expression class to instantiate.
    1149            comments: An optional list of comments to attach to the expression.
    1150            kwargs: The arguments to set for the expression along with their respective values.
    1151
    1152        Returns:
    1153            The target expression.
    1154        """
    1155        instance = exp_class(**kwargs)
    1156        instance.add_comments(comments) if comments else self._add_comments(instance)
    1157        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

    1164    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1165        """
    1166        Validates an Expression, making sure that all its mandatory arguments are set.
    1167
    1168        Args:
    1169            expression: The expression to validate.
    1170            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1171
    1172        Returns:
    1173            The validated expression.
    1174        """
    1175        if self.error_level != ErrorLevel.IGNORE:
    1176            for error_message in expression.error_messages(args):
    1177                self.raise_error(error_message)
    1178
    1179        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