sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

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

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

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

    37def parse_like(args: t.List) -> exp.Escape | exp.Like:
    38    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    39    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like

def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression]) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]: View Source

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

class Parser: View Source

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

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

###### Arguments:

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

Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3) View Source

    943    def __init__(
    944        self,
    945        error_level: t.Optional[ErrorLevel] = None,
    946        error_message_context: int = 100,
    947        max_errors: int = 3,
    948    ):
    949        self.error_level = error_level or ErrorLevel.IMMEDIATE
    950        self.error_message_context = error_message_context
    951        self.max_errors = max_errors
    952        self._tokenizer = self.TOKENIZER_CLASS()
    953        self.reset()

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

    955    def reset(self):
    956        self.sql = ""
    957        self.errors = []
    958        self._tokens = []
    959        self._index = 0
    960        self._curr = None
    961        self._next = None
    962        self._prev = None
    963        self._prev_comments = None

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

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

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

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

    1054    def check_errors(self) -> None:
    1055        """Logs or raises any found errors, depending on the chosen error level setting."""
    1056        if self.error_level == ErrorLevel.WARN:
    1057            for error in self.errors:
    1058                logger.error(str(error))
    1059        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1060            raise ParseError(
    1061                concat_messages(self.errors, self.max_errors),
    1062                errors=merge_errors(self.errors),
    1063            )

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

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

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

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