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

    848    def __init__(
    849        self,
    850        error_level: t.Optional[ErrorLevel] = None,
    851        error_message_context: int = 100,
    852        max_errors: int = 3,
    853    ):
    854        self.error_level = error_level or ErrorLevel.IMMEDIATE
    855        self.error_message_context = error_message_context
    856        self.max_errors = max_errors
    857        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_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'>>, '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_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_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'>>, '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'>}
NESTED_TYPE_TOKENS = {<TokenType.MAP: 'MAP'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NULLABLE: 'NULLABLE'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>}
TYPE_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATE: 'DATE'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT256: 'INT256'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.SUPER: 'SUPER'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.INTERVAL: 'INTERVAL'>}
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.CARET: 'CARET'>, <TokenType.PIPE: 'PIPE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.EQ: 'EQ'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SELECT: 'SELECT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.SLASH: 'SLASH'>, <TokenType.LT: 'LT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.AMP: 'AMP'>, <TokenType.NOT: 'NOT'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.PLUS: 'PLUS'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.COLON: 'COLON'>, <TokenType.DOT: 'DOT'>, <TokenType.HASH: 'HASH'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.MOD: 'MOD'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.DASH: 'DASH'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.GT: 'GT'>, <TokenType.STAR: 'STAR'>}
DB_CREATABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.TABLE: 'TABLE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATABASE: 'DATABASE'>}
ID_VAR_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FULL: 'FULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.END: 'END'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.TABLE: 'TABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.SET: 'SET'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.IS: 'IS'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>}
INTERVAL_VARS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FULL: 'FULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.TABLE: 'TABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.SET: 'SET'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.IS: 'IS'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>}
TABLE_ALIAS_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.END: 'END'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.TABLE: 'TABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.SET: 'SET'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.END: 'END'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.SET: 'SET'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INTERVAL: 'INTERVAL'>}
UPDATE_ALIAS_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.END: 'END'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DESC: 'DESC'>, <TokenType.IS: 'IS'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INTERVAL: 'INTERVAL'>}
TRIM_TYPES = {'BOTH', 'TRAILING', 'LEADING'}
FUNC_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DATE: 'DATE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.XOR: 'XOR'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT256: 'INT256'>, <TokenType.LIKE: 'LIKE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LEFT: 'LEFT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.ALL: 'ALL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.ROW: 'ROW'>, <TokenType.GLOB: 'GLOB'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INTERVAL: 'INTERVAL'>}
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'>}
TIMESTAMPS = {<TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <TokenType.SEMI: 'SEMI'>}
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.FROM: 'FROM'>: <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>>}
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>>, '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>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE', 'LIKE', 'CHECK'}
NO_PAREN_FUNCTION_PARSERS = {<TokenType.ANY: 'ANY'>: <function Parser.<lambda>>, <TokenType.CASE: 'CASE'>: <function Parser.<lambda>>, <TokenType.IF: 'IF'>: <function Parser.<lambda>>, <TokenType.NEXT_VALUE_FOR: 'NEXT_VALUE_FOR'>: <function Parser.<lambda>>}
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>>}
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.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS = {'READ ONLY', 'ISOLATION LEVEL READ COMMITTED', 'ISOLATION LEVEL READ UNCOMMITTED', 'ISOLATION LEVEL SERIALIZABLE', 'ISOLATION LEVEL REPEATABLE READ', 'READ WRITE'}
INSERT_ALTERNATIVES = {'IGNORE', 'REPLACE', 'ABORT', 'ROLLBACK', 'FAIL'}
CLONE_KINDS = {'OFFSET', 'TIMESTAMP', 'STATEMENT'}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TRUE: 'TRUE'>, <TokenType.APPLY: 'APPLY'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DELETE: 'DELETE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FULL: 'FULL'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT128: 'INT128'>, <TokenType.END: 'END'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TOP: 'TOP'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.ASC: 'ASC'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.LOAD: 'LOAD'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.JSON: 'JSON'>, <TokenType.INET: 'INET'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IF: 'IF'>, <TokenType.TABLE: 'TABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIME: 'TIME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.ROW: 'ROW'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>, <TokenType.DATE: 'DATE'>, <TokenType.SET: 'SET'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BIT: 'BIT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VAR: 'VAR'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.UINT: 'UINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.ALL: 'ALL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MAP: 'MAP'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DESC: 'DESC'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.IS: 'IS'>, <TokenType.XML: 'XML'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UUID: 'UUID'>, <TokenType.KEEP: 'KEEP'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.INT: 'INT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INTERVAL: 'INTERVAL'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
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
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

    859    def reset(self):
    860        self.sql = ""
    861        self.errors = []
    862        self._tokens = []
    863        self._index = 0
    864        self._curr = None
    865        self._next = None
    866        self._prev = None
    867        self._prev_comments = None

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

    869    def parse(
    870        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    871    ) -> t.List[t.Optional[exp.Expression]]:
    872        """
    873        Parses a list of tokens and returns a list of syntax trees, one tree
    874        per parsed SQL statement.
    875
    876        Args:
    877            raw_tokens: The list of tokens.
    878            sql: The original SQL string, used to produce helpful debug messages.
    879
    880        Returns:
    881            The list of the produced syntax trees.
    882        """
    883        return self._parse(
    884            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    885        )

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

    887    def parse_into(
    888        self,
    889        expression_types: exp.IntoType,
    890        raw_tokens: t.List[Token],
    891        sql: t.Optional[str] = None,
    892    ) -> t.List[t.Optional[exp.Expression]]:
    893        """
    894        Parses a list of tokens into a given Expression type. If a collection of Expression
    895        types is given instead, this method will try to parse the token list into each one
    896        of them, stopping at the first for which the parsing succeeds.
    897
    898        Args:
    899            expression_types: The expression type(s) to try and parse the token list into.
    900            raw_tokens: The list of tokens.
    901            sql: The original SQL string, used to produce helpful debug messages.
    902
    903        Returns:
    904            The target Expression.
    905        """
    906        errors = []
    907        for expression_type in ensure_list(expression_types):
    908            parser = self.EXPRESSION_PARSERS.get(expression_type)
    909            if not parser:
    910                raise TypeError(f"No parser registered for {expression_type}")
    911
    912            try:
    913                return self._parse(parser, raw_tokens, sql)
    914            except ParseError as e:
    915                e.errors[0]["into_expression"] = expression_type
    916                errors.append(e)
    917
    918        raise ParseError(
    919            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    920            errors=merge_errors(errors),
    921        ) 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

    958    def check_errors(self) -> None:
    959        """Logs or raises any found errors, depending on the chosen error level setting."""
    960        if self.error_level == ErrorLevel.WARN:
    961            for error in self.errors:
    962                logger.error(str(error))
    963        elif self.error_level == ErrorLevel.RAISE and self.errors:
    964            raise ParseError(
    965                concat_messages(self.errors, self.max_errors),
    966                errors=merge_errors(self.errors),
    967            )

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

    969    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    970        """
    971        Appends an error in the list of recorded errors or raises it, depending on the chosen
    972        error level setting.
    973        """
    974        token = token or self._curr or self._prev or Token.string("")
    975        start = token.start
    976        end = token.end + 1
    977        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    978        highlight = self.sql[start:end]
    979        end_context = self.sql[end : end + self.error_message_context]
    980
    981        error = ParseError.new(
    982            f"{message}. Line {token.line}, Col: {token.col}.\n"
    983            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    984            description=message,
    985            line=token.line,
    986            col=token.col,
    987            start_context=start_context,
    988            highlight=highlight,
    989            end_context=end_context,
    990        )
    991
    992        if self.error_level == ErrorLevel.IMMEDIATE:
    993            raise error
    994
    995        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

     997    def expression(
     998        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
     999    ) -> E:
    1000        """
    1001        Creates a new, validated Expression.
    1002
    1003        Args:
    1004            exp_class: The expression class to instantiate.
    1005            comments: An optional list of comments to attach to the expression.
    1006            kwargs: The arguments to set for the expression along with their respective values.
    1007
    1008        Returns:
    1009            The target expression.
    1010        """
    1011        instance = exp_class(**kwargs)
    1012        instance.add_comments(comments) if comments else self._add_comments(instance)
    1013        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

    1020    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1021        """
    1022        Validates an Expression, making sure that all its mandatory arguments are set.
    1023
    1024        Args:
    1025            expression: The expression to validate.
    1026            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1027
    1028        Returns:
    1029            The validated expression.
    1030        """
    1031        if self.error_level != ErrorLevel.IGNORE:
    1032            for error_message in expression.error_messages(args):
    1033                self.raise_error(error_message)
    1034
    1035        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