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

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

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

    905    def __init__(
    906        self,
    907        error_level: t.Optional[ErrorLevel] = None,
    908        error_message_context: int = 100,
    909        max_errors: int = 3,
    910    ):
    911        self.error_level = error_level or ErrorLevel.IMMEDIATE
    912        self.error_message_context = error_message_context
    913        self.max_errors = max_errors
    914        self._tokenizer = self.TOKENIZER_CLASS()
    915        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'>>, '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_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.ARRAY: 'ARRAY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MAP: 'MAP'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>}
TYPE_TOKENS = {<TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT: 'INT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SMALLINT: 'SMALLINT'>}
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.STAR: 'STAR'>, <TokenType.COMMA: 'COMMA'>, <TokenType.EQ: 'EQ'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.PLUS: 'PLUS'>, <TokenType.MOD: 'MOD'>, <TokenType.HASH: 'HASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.CARET: 'CARET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.NOT: 'NOT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.GT: 'GT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.DASH: 'DASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.COLON: 'COLON'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.DOT: 'DOT'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.LT: 'LT'>, <TokenType.AMP: 'AMP'>, <TokenType.TILDA: 'TILDA'>}
DB_CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.SET: 'SET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.FULL: 'FULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IS: 'IS'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.END: 'END'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWS: 'ROWS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LEFT: 'LEFT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
INTERVAL_VARS = {<TokenType.SET: 'SET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.FULL: 'FULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IS: 'IS'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWS: 'ROWS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LEFT: 'LEFT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
TABLE_ALIAS_TOKENS = {<TokenType.SET: 'SET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IS: 'IS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.END: 'END'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWS: 'ROWS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.SET: 'SET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.END: 'END'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWS: 'ROWS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IS: 'IS'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.END: 'END'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ROWS: 'ROWS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
TRIM_TYPES = {'LEADING', 'TRAILING', 'BOTH'}
FUNC_TOKENS = {<TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.XOR: 'XOR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UUID: 'UUID'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT: 'UINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INDEX: 'INDEX'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.GLOB: 'GLOB'>, <TokenType.SOME: 'SOME'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INSERT: 'INSERT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIME: 'TIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.BIT: 'BIT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.SMALLINT: 'SMALLINT'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>, <TokenType.DPIPE: 'DPIPE'>: <class 'sqlglot.expressions.SafeDPipe'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.SEMI: 'SEMI'>, <TokenType.CROSS: 'CROSS'>, <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.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 = {'LIKE', 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', 'UNIQUE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS: Dict[sqlglot.expressions.DataType.Type, Callable] = {}
MODIFIABLES = (<class 'sqlglot.expressions.Subquery'>, <class 'sqlglot.expressions.Subqueryable'>, <class 'sqlglot.expressions.Table'>)
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS = {'READ ONLY', 'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ WRITE', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'ROLLBACK', 'FAIL', 'IGNORE', 'ABORT', 'REPLACE'}
CLONE_KINDS = {'OFFSET', 'STATEMENT', 'TIMESTAMP'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.SET: 'SET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INET: 'INET'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FIRST: 'FIRST'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INT: 'INT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UINT: 'UINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.FULL: 'FULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VAR: 'VAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CASE: 'CASE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.NULL: 'NULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ASC: 'ASC'>, <TokenType.XML: 'XML'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TOP: 'TOP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.BIT: 'BIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IS: 'IS'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.END: 'END'>, <TokenType.DESC: 'DESC'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.JSON: 'JSON'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT128: 'INT128'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TEXT: 'TEXT'>, <TokenType.DIV: 'DIV'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LEFT: 'LEFT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LOAD: 'LOAD'>, <TokenType.DATE: 'DATE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.MONEY: 'MONEY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.SMALLINT: 'SMALLINT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
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
SUPPORTS_USER_DEFINED_TYPES = True
ALTER_TABLE_ADD_COLUMN_KEYWORD = True
TABLESAMPLE_CSV = False
TOKENIZER_CLASS: Type[sqlglot.tokens.Tokenizer] = <class 'sqlglot.executor.python.Python.Tokenizer'>
INDEX_OFFSET: int = 0
UNNEST_COLUMN_ONLY: bool = False
ALIAS_POST_TABLESAMPLE: bool = False
STRICT_STRING_CONCAT = False
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

    917    def reset(self):
    918        self.sql = ""
    919        self.errors = []
    920        self._tokens = []
    921        self._index = 0
    922        self._curr = None
    923        self._next = None
    924        self._prev = None
    925        self._prev_comments = None

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

    927    def parse(
    928        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    929    ) -> t.List[t.Optional[exp.Expression]]:
    930        """
    931        Parses a list of tokens and returns a list of syntax trees, one tree
    932        per parsed SQL statement.
    933
    934        Args:
    935            raw_tokens: The list of tokens.
    936            sql: The original SQL string, used to produce helpful debug messages.
    937
    938        Returns:
    939            The list of the produced syntax trees.
    940        """
    941        return self._parse(
    942            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    943        )

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

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

    1016    def check_errors(self) -> None:
    1017        """Logs or raises any found errors, depending on the chosen error level setting."""
    1018        if self.error_level == ErrorLevel.WARN:
    1019            for error in self.errors:
    1020                logger.error(str(error))
    1021        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1022            raise ParseError(
    1023                concat_messages(self.errors, self.max_errors),
    1024                errors=merge_errors(self.errors),
    1025            )

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

    1027    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1028        """
    1029        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1030        error level setting.
    1031        """
    1032        token = token or self._curr or self._prev or Token.string("")
    1033        start = token.start
    1034        end = token.end + 1
    1035        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1036        highlight = self.sql[start:end]
    1037        end_context = self.sql[end : end + self.error_message_context]
    1038
    1039        error = ParseError.new(
    1040            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1041            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1042            description=message,
    1043            line=token.line,
    1044            col=token.col,
    1045            start_context=start_context,
    1046            highlight=highlight,
    1047            end_context=end_context,
    1048        )
    1049
    1050        if self.error_level == ErrorLevel.IMMEDIATE:
    1051            raise error
    1052
    1053        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

    1055    def expression(
    1056        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1057    ) -> E:
    1058        """
    1059        Creates a new, validated Expression.
    1060
    1061        Args:
    1062            exp_class: The expression class to instantiate.
    1063            comments: An optional list of comments to attach to the expression.
    1064            kwargs: The arguments to set for the expression along with their respective values.
    1065
    1066        Returns:
    1067            The target expression.
    1068        """
    1069        instance = exp_class(**kwargs)
    1070        instance.add_comments(comments) if comments else self._add_comments(instance)
    1071        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

    1078    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1079        """
    1080        Validates an Expression, making sure that all its mandatory arguments are set.
    1081
    1082        Args:
    1083            expression: The expression to validate.
    1084            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1085
    1086        Returns:
    1087            The validated expression.
    1088        """
    1089        if self.error_level != ErrorLevel.IGNORE:
    1090            for error_message in expression.error_messages(args):
    1091                self.raise_error(error_message)
    1092
    1093        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