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

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

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

    918    def __init__(
    919        self,
    920        error_level: t.Optional[ErrorLevel] = None,
    921        error_message_context: int = 100,
    922        max_errors: int = 3,
    923    ):
    924        self.error_level = error_level or ErrorLevel.IMMEDIATE
    925        self.error_message_context = error_message_context
    926        self.max_errors = max_errors
    927        self._tokenizer = self.TOKENIZER_CLASS()
    928        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'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Concat'>>, 'CONCAT_WS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConcatWs'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hex'>>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DATE_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDateOfMonth'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log'>>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeConcat'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SET_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SetAgg'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'LIKE': <function parse_like>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>}
TYPE_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.CHAR: 'CHAR'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.UUID: 'UUID'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NULL: 'NULL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>}
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'>}
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.STAR: 'STAR'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.AMP: 'AMP'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.CARET: 'CARET'>, <TokenType.PLUS: 'PLUS'>, <TokenType.TILDA: 'TILDA'>, <TokenType.DASH: 'DASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.MOD: 'MOD'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.COLON: 'COLON'>, <TokenType.GT: 'GT'>, <TokenType.NOT: 'NOT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.HASH: 'HASH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.LT: 'LT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.DOT: 'DOT'>}
DB_CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SEMI: 'SEMI'>}
INTERVAL_VARS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SEMI: 'SEMI'>}
TABLE_ALIAS_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>}
UPDATE_ALIAS_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.GLOB: 'GLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.JSON: 'JSON'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LIKE: 'LIKE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UUID: 'UUID'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT: 'INT'>, <TokenType.NULL: 'NULL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT: 'UINT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.MAP: 'MAP'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.XOR: 'XOR'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.INSERT: 'INSERT'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INET: 'INET'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.INT128: 'INT128'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>}
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.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.ANTI: 'ANTI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INNER: 'INNER'>, <TokenType.OUTER: 'OUTER'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.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.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'UNIQUE', 'CHECK', 'LIKE', 'FOREIGN KEY', 'PRIMARY 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.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
MODIFIABLES = (<class 'sqlglot.expressions.Subquery'>, <class 'sqlglot.expressions.Subqueryable'>, <class 'sqlglot.expressions.Table'>)
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS = {'READ ONLY', 'READ WRITE', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'FAIL', 'ABORT', 'IGNORE', 'ROLLBACK', 'REPLACE'}
CLONE_KINDS = {'OFFSET', 'STATEMENT', 'TIMESTAMP'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ROW: 'ROW'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SEMI: 'SEMI'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
FETCH_TOKENS = {<TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LEFT: 'LEFT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOME: 'SOME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ASC: 'ASC'>, <TokenType.TOP: 'TOP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CHAR: 'CHAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.UINT: 'UINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.END: 'END'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DESC: 'DESC'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT256: 'INT256'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ALL: 'ALL'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.XML: 'XML'>, <TokenType.BIT: 'BIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DIV: 'DIV'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CASE: 'CASE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ANY: 'ANY'>, <TokenType.IS: 'IS'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.YEAR: 'YEAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.MERGE: 'MERGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.UUID: 'UUID'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NEXT: 'NEXT'>, <TokenType.NULL: 'NULL'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.BINARY: 'BINARY'>, <TokenType.INET: 'INET'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SEMI: 'SEMI'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
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
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

    930    def reset(self):
    931        self.sql = ""
    932        self.errors = []
    933        self._tokens = []
    934        self._index = 0
    935        self._curr = None
    936        self._next = None
    937        self._prev = None
    938        self._prev_comments = None

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

    940    def parse(
    941        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    942    ) -> t.List[t.Optional[exp.Expression]]:
    943        """
    944        Parses a list of tokens and returns a list of syntax trees, one tree
    945        per parsed SQL statement.
    946
    947        Args:
    948            raw_tokens: The list of tokens.
    949            sql: The original SQL string, used to produce helpful debug messages.
    950
    951        Returns:
    952            The list of the produced syntax trees.
    953        """
    954        return self._parse(
    955            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    956        )

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

    958    def parse_into(
    959        self,
    960        expression_types: exp.IntoType,
    961        raw_tokens: t.List[Token],
    962        sql: t.Optional[str] = None,
    963    ) -> t.List[t.Optional[exp.Expression]]:
    964        """
    965        Parses a list of tokens into a given Expression type. If a collection of Expression
    966        types is given instead, this method will try to parse the token list into each one
    967        of them, stopping at the first for which the parsing succeeds.
    968
    969        Args:
    970            expression_types: The expression type(s) to try and parse the token list into.
    971            raw_tokens: The list of tokens.
    972            sql: The original SQL string, used to produce helpful debug messages.
    973
    974        Returns:
    975            The target Expression.
    976        """
    977        errors = []
    978        for expression_type in ensure_list(expression_types):
    979            parser = self.EXPRESSION_PARSERS.get(expression_type)
    980            if not parser:
    981                raise TypeError(f"No parser registered for {expression_type}")
    982
    983            try:
    984                return self._parse(parser, raw_tokens, sql)
    985            except ParseError as e:
    986                e.errors[0]["into_expression"] = expression_type
    987                errors.append(e)
    988
    989        raise ParseError(
    990            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    991            errors=merge_errors(errors),
    992        ) 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

    1029    def check_errors(self) -> None:
    1030        """Logs or raises any found errors, depending on the chosen error level setting."""
    1031        if self.error_level == ErrorLevel.WARN:
    1032            for error in self.errors:
    1033                logger.error(str(error))
    1034        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1035            raise ParseError(
    1036                concat_messages(self.errors, self.max_errors),
    1037                errors=merge_errors(self.errors),
    1038            )

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

    1040    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1041        """
    1042        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1043        error level setting.
    1044        """
    1045        token = token or self._curr or self._prev or Token.string("")
    1046        start = token.start
    1047        end = token.end + 1
    1048        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1049        highlight = self.sql[start:end]
    1050        end_context = self.sql[end : end + self.error_message_context]
    1051
    1052        error = ParseError.new(
    1053            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1054            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1055            description=message,
    1056            line=token.line,
    1057            col=token.col,
    1058            start_context=start_context,
    1059            highlight=highlight,
    1060            end_context=end_context,
    1061        )
    1062
    1063        if self.error_level == ErrorLevel.IMMEDIATE:
    1064            raise error
    1065
    1066        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

    1068    def expression(
    1069        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1070    ) -> E:
    1071        """
    1072        Creates a new, validated Expression.
    1073
    1074        Args:
    1075            exp_class: The expression class to instantiate.
    1076            comments: An optional list of comments to attach to the expression.
    1077            kwargs: The arguments to set for the expression along with their respective values.
    1078
    1079        Returns:
    1080            The target expression.
    1081        """
    1082        instance = exp_class(**kwargs)
    1083        instance.add_comments(comments) if comments else self._add_comments(instance)
    1084        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

    1091    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1092        """
    1093        Validates an Expression, making sure that all its mandatory arguments are set.
    1094
    1095        Args:
    1096            expression: The expression to validate.
    1097            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1098
    1099        Returns:
    1100            The validated expression.
    1101        """
    1102        if self.error_level != ErrorLevel.IGNORE:
    1103            for error_message in expression.error_messages(args):
    1104                self.raise_error(error_message)
    1105
    1106        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