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

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

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

###### Arguments:

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

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

    889    def __init__(
    890        self,
    891        error_level: t.Optional[ErrorLevel] = None,
    892        error_message_context: int = 100,
    893        max_errors: int = 3,
    894    ):
    895        self.error_level = error_level or ErrorLevel.IMMEDIATE
    896        self.error_message_context = error_message_context
    897        self.max_errors = max_errors
    898        self._tokenizer = self.TOKENIZER_CLASS()
    899        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'>>, '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'>>, '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.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NULLABLE: 'NULLABLE'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>}
TYPE_TOKENS = {<TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MAP: 'MAP'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.NULL: 'NULL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIME: 'TIME'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>}
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.R_PAREN: 'R_PAREN'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.DOT: 'DOT'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SLASH: 'SLASH'>, <TokenType.HASH: 'HASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.AMP: 'AMP'>, <TokenType.CARET: 'CARET'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.SELECT: 'SELECT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.DASH: 'DASH'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.PLUS: 'PLUS'>, <TokenType.STAR: 'STAR'>, <TokenType.NOT: 'NOT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.GT: 'GT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.EQ: 'EQ'>, <TokenType.MOD: 'MOD'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.LT: 'LT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.COLON: 'COLON'>}
DB_CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>}
CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>}
ID_VAR_TOKENS = {<TokenType.END: 'END'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SET: 'SET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IS: 'IS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.APPLY: 'APPLY'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FULL: 'FULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
INTERVAL_VARS = {<TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SET: 'SET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IS: 'IS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.APPLY: 'APPLY'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FULL: 'FULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
TABLE_ALIAS_TOKENS = {<TokenType.END: 'END'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.SET: 'SET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IS: 'IS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.END: 'END'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.SET: 'SET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.END: 'END'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IS: 'IS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
TRIM_TYPES = {'TRAILING', 'BOTH', 'LEADING'}
FUNC_TOKENS = {<TokenType.IMAGE: 'IMAGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.GLOB: 'GLOB'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT128: 'INT128'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.XOR: 'XOR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INSERT: 'INSERT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.NULL: 'NULL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.ALL: 'ALL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.BIT: 'BIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.XML: 'XML'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>, <TokenType.DPIPE: 'DPIPE'>: <class 'sqlglot.expressions.SafeDPipe'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <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 = {'CHECK', 'UNIQUE', 'FOREIGN KEY', 'PRIMARY KEY', 'LIKE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONCAT': <function Parser.<lambda>>, '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.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'DEFERRED', 'EXCLUSIVE', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ WRITE', 'ISOLATION LEVEL SERIALIZABLE', 'READ ONLY', 'ISOLATION LEVEL READ COMMITTED'}
INSERT_ALTERNATIVES = {'REPLACE', 'ROLLBACK', 'FAIL', 'ABORT', 'IGNORE'}
CLONE_KINDS = {'STATEMENT', 'OFFSET', 'TIMESTAMP'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.END: 'END'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SET: 'SET'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UUID: 'UUID'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.MAP: 'MAP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IS: 'IS'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.DIV: 'DIV'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INT: 'INT'>, <TokenType.INT256: 'INT256'>, <TokenType.ALL: 'ALL'>, <TokenType.NULL: 'NULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.TOP: 'TOP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.BIT: 'BIT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.DESC: 'DESC'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.VIEW: 'VIEW'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ASC: 'ASC'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FALSE: 'FALSE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CASE: 'CASE'>, <TokenType.VAR: 'VAR'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.APPLY: 'APPLY'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ROW: 'ROW'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SOME: 'SOME'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FULL: 'FULL'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LEFT: 'LEFT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TRUE: 'TRUE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_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
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

    901    def reset(self):
    902        self.sql = ""
    903        self.errors = []
    904        self._tokens = []
    905        self._index = 0
    906        self._curr = None
    907        self._next = None
    908        self._prev = None
    909        self._prev_comments = None

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

    911    def parse(
    912        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    913    ) -> t.List[t.Optional[exp.Expression]]:
    914        """
    915        Parses a list of tokens and returns a list of syntax trees, one tree
    916        per parsed SQL statement.
    917
    918        Args:
    919            raw_tokens: The list of tokens.
    920            sql: The original SQL string, used to produce helpful debug messages.
    921
    922        Returns:
    923            The list of the produced syntax trees.
    924        """
    925        return self._parse(
    926            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    927        )

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

    929    def parse_into(
    930        self,
    931        expression_types: exp.IntoType,
    932        raw_tokens: t.List[Token],
    933        sql: t.Optional[str] = None,
    934    ) -> t.List[t.Optional[exp.Expression]]:
    935        """
    936        Parses a list of tokens into a given Expression type. If a collection of Expression
    937        types is given instead, this method will try to parse the token list into each one
    938        of them, stopping at the first for which the parsing succeeds.
    939
    940        Args:
    941            expression_types: The expression type(s) to try and parse the token list into.
    942            raw_tokens: The list of tokens.
    943            sql: The original SQL string, used to produce helpful debug messages.
    944
    945        Returns:
    946            The target Expression.
    947        """
    948        errors = []
    949        for expression_type in ensure_list(expression_types):
    950            parser = self.EXPRESSION_PARSERS.get(expression_type)
    951            if not parser:
    952                raise TypeError(f"No parser registered for {expression_type}")
    953
    954            try:
    955                return self._parse(parser, raw_tokens, sql)
    956            except ParseError as e:
    957                e.errors[0]["into_expression"] = expression_type
    958                errors.append(e)
    959
    960        raise ParseError(
    961            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    962            errors=merge_errors(errors),
    963        ) 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

    1000    def check_errors(self) -> None:
    1001        """Logs or raises any found errors, depending on the chosen error level setting."""
    1002        if self.error_level == ErrorLevel.WARN:
    1003            for error in self.errors:
    1004                logger.error(str(error))
    1005        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1006            raise ParseError(
    1007                concat_messages(self.errors, self.max_errors),
    1008                errors=merge_errors(self.errors),
    1009            )

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

    1011    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1012        """
    1013        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1014        error level setting.
    1015        """
    1016        token = token or self._curr or self._prev or Token.string("")
    1017        start = token.start
    1018        end = token.end + 1
    1019        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1020        highlight = self.sql[start:end]
    1021        end_context = self.sql[end : end + self.error_message_context]
    1022
    1023        error = ParseError.new(
    1024            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1025            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1026            description=message,
    1027            line=token.line,
    1028            col=token.col,
    1029            start_context=start_context,
    1030            highlight=highlight,
    1031            end_context=end_context,
    1032        )
    1033
    1034        if self.error_level == ErrorLevel.IMMEDIATE:
    1035            raise error
    1036
    1037        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

    1039    def expression(
    1040        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1041    ) -> E:
    1042        """
    1043        Creates a new, validated Expression.
    1044
    1045        Args:
    1046            exp_class: The expression class to instantiate.
    1047            comments: An optional list of comments to attach to the expression.
    1048            kwargs: The arguments to set for the expression along with their respective values.
    1049
    1050        Returns:
    1051            The target expression.
    1052        """
    1053        instance = exp_class(**kwargs)
    1054        instance.add_comments(comments) if comments else self._add_comments(instance)
    1055        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

    1062    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1063        """
    1064        Validates an Expression, making sure that all its mandatory arguments are set.
    1065
    1066        Args:
    1067            expression: The expression to validate.
    1068            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1069
    1070        Returns:
    1071            The validated expression.
    1072        """
    1073        if self.error_level != ErrorLevel.IGNORE:
    1074            for error_message in expression.error_messages(args):
    1075                self.raise_error(error_message)
    1076
    1077        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