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, Lit
      16    from sqlglot.dialects.dialect import Dialect, DialectType
      17
      18    T = t.TypeVar("T")
      19
      20logger = logging.getLogger("sqlglot")
      21
      22OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
      23
      24
      25def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
      26    if len(args) == 1 and args[0].is_star:
      27        return exp.StarMap(this=args[0])
      28
      29    keys = []
      30    values = []
      31    for i in range(0, len(args), 2):
      32        keys.append(args[i])
      33        values.append(args[i + 1])
      34
      35    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
      36
      37
      38def build_like(args: t.List) -> exp.Escape | exp.Like:
      39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
      40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
      41
      42
      43def binary_range_parser(
      44    expr_type: t.Type[exp.Expression], reverse_args: bool = False
      45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
      46    def _parse_binary_range(
      47        self: Parser, this: t.Optional[exp.Expression]
      48    ) -> t.Optional[exp.Expression]:
      49        expression = self._parse_bitwise()
      50        if reverse_args:
      51            this, expression = expression, this
      52        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
      53
      54    return _parse_binary_range
      55
      56
      57def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
      58    # Default argument order is base, expression
      59    this = seq_get(args, 0)
      60    expression = seq_get(args, 1)
      61
      62    if expression:
      63        if not dialect.LOG_BASE_FIRST:
      64            this, expression = expression, this
      65        return exp.Log(this=this, expression=expression)
      66
      67    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
      68
      69
      70def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
      71    arg = seq_get(args, 0)
      72    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
      73
      74
      75def build_lower(args: t.List) -> exp.Lower | exp.Hex:
      76    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
      77    arg = seq_get(args, 0)
      78    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
      79
      80
      81def build_upper(args: t.List) -> exp.Upper | exp.Hex:
      82    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
      83    arg = seq_get(args, 0)
      84    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
      85
      86
      87def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
      88    def _builder(args: t.List, dialect: Dialect) -> E:
      89        expression = expr_type(
      90            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
      91        )
      92        if len(args) > 2 and expr_type is exp.JSONExtract:
      93            expression.set("expressions", args[2:])
      94
      95        return expression
      96
      97    return _builder
      98
      99
     100def build_mod(args: t.List) -> exp.Mod:
     101    this = seq_get(args, 0)
     102    expression = seq_get(args, 1)
     103
     104    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
     105    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
     106    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
     107
     108    return exp.Mod(this=this, expression=expression)
     109
     110
     111class _Parser(type):
     112    def __new__(cls, clsname, bases, attrs):
     113        klass = super().__new__(cls, clsname, bases, attrs)
     114
     115        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
     116        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
     117
     118        return klass
     119
     120
     121class Parser(metaclass=_Parser):
     122    """
     123    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     124
     125    Args:
     126        error_level: The desired error level.
     127            Default: ErrorLevel.IMMEDIATE
     128        error_message_context: The amount of context to capture from a query string when displaying
     129            the error message (in number of characters).
     130            Default: 100
     131        max_errors: Maximum number of error messages to include in a raised ParseError.
     132            This is only relevant if error_level is ErrorLevel.RAISE.
     133            Default: 3
     134    """
     135
     136    FUNCTIONS: t.Dict[str, t.Callable] = {
     137        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     138        "CONCAT": lambda args, dialect: exp.Concat(
     139            expressions=args,
     140            safe=not dialect.STRICT_STRING_CONCAT,
     141            coalesce=dialect.CONCAT_COALESCE,
     142        ),
     143        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     144            expressions=args,
     145            safe=not dialect.STRICT_STRING_CONCAT,
     146            coalesce=dialect.CONCAT_COALESCE,
     147        ),
     148        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     149            this=seq_get(args, 0),
     150            to=exp.DataType(this=exp.DataType.Type.TEXT),
     151        ),
     152        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     153        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     154        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     155        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     156        "LIKE": build_like,
     157        "LOG": build_logarithm,
     158        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     159        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     160        "MOD": build_mod,
     161        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     162            this=seq_get(args, 0),
     163            to=exp.DataType(this=exp.DataType.Type.TEXT),
     164        ),
     165        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     166            this=exp.Cast(
     167                this=seq_get(args, 0),
     168                to=exp.DataType(this=exp.DataType.Type.TEXT),
     169            ),
     170            start=exp.Literal.number(1),
     171            length=exp.Literal.number(10),
     172        ),
     173        "VAR_MAP": build_var_map,
     174        "LOWER": build_lower,
     175        "UPPER": build_upper,
     176        "HEX": build_hex,
     177        "TO_HEX": build_hex,
     178    }
     179
     180    NO_PAREN_FUNCTIONS = {
     181        TokenType.CURRENT_DATE: exp.CurrentDate,
     182        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     183        TokenType.CURRENT_TIME: exp.CurrentTime,
     184        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     185        TokenType.CURRENT_USER: exp.CurrentUser,
     186    }
     187
     188    STRUCT_TYPE_TOKENS = {
     189        TokenType.NESTED,
     190        TokenType.OBJECT,
     191        TokenType.STRUCT,
     192    }
     193
     194    NESTED_TYPE_TOKENS = {
     195        TokenType.ARRAY,
     196        TokenType.LIST,
     197        TokenType.LOWCARDINALITY,
     198        TokenType.MAP,
     199        TokenType.NULLABLE,
     200        *STRUCT_TYPE_TOKENS,
     201    }
     202
     203    ENUM_TYPE_TOKENS = {
     204        TokenType.ENUM,
     205        TokenType.ENUM8,
     206        TokenType.ENUM16,
     207    }
     208
     209    AGGREGATE_TYPE_TOKENS = {
     210        TokenType.AGGREGATEFUNCTION,
     211        TokenType.SIMPLEAGGREGATEFUNCTION,
     212    }
     213
     214    TYPE_TOKENS = {
     215        TokenType.BIT,
     216        TokenType.BOOLEAN,
     217        TokenType.TINYINT,
     218        TokenType.UTINYINT,
     219        TokenType.SMALLINT,
     220        TokenType.USMALLINT,
     221        TokenType.INT,
     222        TokenType.UINT,
     223        TokenType.BIGINT,
     224        TokenType.UBIGINT,
     225        TokenType.INT128,
     226        TokenType.UINT128,
     227        TokenType.INT256,
     228        TokenType.UINT256,
     229        TokenType.MEDIUMINT,
     230        TokenType.UMEDIUMINT,
     231        TokenType.FIXEDSTRING,
     232        TokenType.FLOAT,
     233        TokenType.DOUBLE,
     234        TokenType.CHAR,
     235        TokenType.NCHAR,
     236        TokenType.VARCHAR,
     237        TokenType.NVARCHAR,
     238        TokenType.BPCHAR,
     239        TokenType.TEXT,
     240        TokenType.MEDIUMTEXT,
     241        TokenType.LONGTEXT,
     242        TokenType.MEDIUMBLOB,
     243        TokenType.LONGBLOB,
     244        TokenType.BINARY,
     245        TokenType.VARBINARY,
     246        TokenType.JSON,
     247        TokenType.JSONB,
     248        TokenType.INTERVAL,
     249        TokenType.TINYBLOB,
     250        TokenType.TINYTEXT,
     251        TokenType.TIME,
     252        TokenType.TIMETZ,
     253        TokenType.TIMESTAMP,
     254        TokenType.TIMESTAMP_S,
     255        TokenType.TIMESTAMP_MS,
     256        TokenType.TIMESTAMP_NS,
     257        TokenType.TIMESTAMPTZ,
     258        TokenType.TIMESTAMPLTZ,
     259        TokenType.TIMESTAMPNTZ,
     260        TokenType.DATETIME,
     261        TokenType.DATETIME64,
     262        TokenType.DATE,
     263        TokenType.DATE32,
     264        TokenType.INT4RANGE,
     265        TokenType.INT4MULTIRANGE,
     266        TokenType.INT8RANGE,
     267        TokenType.INT8MULTIRANGE,
     268        TokenType.NUMRANGE,
     269        TokenType.NUMMULTIRANGE,
     270        TokenType.TSRANGE,
     271        TokenType.TSMULTIRANGE,
     272        TokenType.TSTZRANGE,
     273        TokenType.TSTZMULTIRANGE,
     274        TokenType.DATERANGE,
     275        TokenType.DATEMULTIRANGE,
     276        TokenType.DECIMAL,
     277        TokenType.UDECIMAL,
     278        TokenType.BIGDECIMAL,
     279        TokenType.UUID,
     280        TokenType.GEOGRAPHY,
     281        TokenType.GEOMETRY,
     282        TokenType.HLLSKETCH,
     283        TokenType.HSTORE,
     284        TokenType.PSEUDO_TYPE,
     285        TokenType.SUPER,
     286        TokenType.SERIAL,
     287        TokenType.SMALLSERIAL,
     288        TokenType.BIGSERIAL,
     289        TokenType.XML,
     290        TokenType.YEAR,
     291        TokenType.UNIQUEIDENTIFIER,
     292        TokenType.USERDEFINED,
     293        TokenType.MONEY,
     294        TokenType.SMALLMONEY,
     295        TokenType.ROWVERSION,
     296        TokenType.IMAGE,
     297        TokenType.VARIANT,
     298        TokenType.OBJECT,
     299        TokenType.OBJECT_IDENTIFIER,
     300        TokenType.INET,
     301        TokenType.IPADDRESS,
     302        TokenType.IPPREFIX,
     303        TokenType.IPV4,
     304        TokenType.IPV6,
     305        TokenType.UNKNOWN,
     306        TokenType.NULL,
     307        TokenType.NAME,
     308        TokenType.TDIGEST,
     309        *ENUM_TYPE_TOKENS,
     310        *NESTED_TYPE_TOKENS,
     311        *AGGREGATE_TYPE_TOKENS,
     312    }
     313
     314    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     315        TokenType.BIGINT: TokenType.UBIGINT,
     316        TokenType.INT: TokenType.UINT,
     317        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     318        TokenType.SMALLINT: TokenType.USMALLINT,
     319        TokenType.TINYINT: TokenType.UTINYINT,
     320        TokenType.DECIMAL: TokenType.UDECIMAL,
     321    }
     322
     323    SUBQUERY_PREDICATES = {
     324        TokenType.ANY: exp.Any,
     325        TokenType.ALL: exp.All,
     326        TokenType.EXISTS: exp.Exists,
     327        TokenType.SOME: exp.Any,
     328    }
     329
     330    RESERVED_TOKENS = {
     331        *Tokenizer.SINGLE_TOKENS.values(),
     332        TokenType.SELECT,
     333    } - {TokenType.IDENTIFIER}
     334
     335    DB_CREATABLES = {
     336        TokenType.DATABASE,
     337        TokenType.DICTIONARY,
     338        TokenType.MODEL,
     339        TokenType.SCHEMA,
     340        TokenType.SEQUENCE,
     341        TokenType.STORAGE_INTEGRATION,
     342        TokenType.TABLE,
     343        TokenType.TAG,
     344        TokenType.VIEW,
     345        TokenType.WAREHOUSE,
     346        TokenType.STREAMLIT,
     347    }
     348
     349    CREATABLES = {
     350        TokenType.COLUMN,
     351        TokenType.CONSTRAINT,
     352        TokenType.FOREIGN_KEY,
     353        TokenType.FUNCTION,
     354        TokenType.INDEX,
     355        TokenType.PROCEDURE,
     356        *DB_CREATABLES,
     357    }
     358
     359    # Tokens that can represent identifiers
     360    ID_VAR_TOKENS = {
     361        TokenType.VAR,
     362        TokenType.ANTI,
     363        TokenType.APPLY,
     364        TokenType.ASC,
     365        TokenType.ASOF,
     366        TokenType.AUTO_INCREMENT,
     367        TokenType.BEGIN,
     368        TokenType.BPCHAR,
     369        TokenType.CACHE,
     370        TokenType.CASE,
     371        TokenType.COLLATE,
     372        TokenType.COMMAND,
     373        TokenType.COMMENT,
     374        TokenType.COMMIT,
     375        TokenType.CONSTRAINT,
     376        TokenType.COPY,
     377        TokenType.DEFAULT,
     378        TokenType.DELETE,
     379        TokenType.DESC,
     380        TokenType.DESCRIBE,
     381        TokenType.DICTIONARY,
     382        TokenType.DIV,
     383        TokenType.END,
     384        TokenType.EXECUTE,
     385        TokenType.ESCAPE,
     386        TokenType.FALSE,
     387        TokenType.FIRST,
     388        TokenType.FILTER,
     389        TokenType.FINAL,
     390        TokenType.FORMAT,
     391        TokenType.FULL,
     392        TokenType.IDENTIFIER,
     393        TokenType.IS,
     394        TokenType.ISNULL,
     395        TokenType.INTERVAL,
     396        TokenType.KEEP,
     397        TokenType.KILL,
     398        TokenType.LEFT,
     399        TokenType.LOAD,
     400        TokenType.MERGE,
     401        TokenType.NATURAL,
     402        TokenType.NEXT,
     403        TokenType.OFFSET,
     404        TokenType.OPERATOR,
     405        TokenType.ORDINALITY,
     406        TokenType.OVERLAPS,
     407        TokenType.OVERWRITE,
     408        TokenType.PARTITION,
     409        TokenType.PERCENT,
     410        TokenType.PIVOT,
     411        TokenType.PRAGMA,
     412        TokenType.RANGE,
     413        TokenType.RECURSIVE,
     414        TokenType.REFERENCES,
     415        TokenType.REFRESH,
     416        TokenType.REPLACE,
     417        TokenType.RIGHT,
     418        TokenType.ROLLUP,
     419        TokenType.ROW,
     420        TokenType.ROWS,
     421        TokenType.SEMI,
     422        TokenType.SET,
     423        TokenType.SETTINGS,
     424        TokenType.SHOW,
     425        TokenType.TEMPORARY,
     426        TokenType.TOP,
     427        TokenType.TRUE,
     428        TokenType.TRUNCATE,
     429        TokenType.UNIQUE,
     430        TokenType.UNNEST,
     431        TokenType.UNPIVOT,
     432        TokenType.UPDATE,
     433        TokenType.USE,
     434        TokenType.VOLATILE,
     435        TokenType.WINDOW,
     436        *CREATABLES,
     437        *SUBQUERY_PREDICATES,
     438        *TYPE_TOKENS,
     439        *NO_PAREN_FUNCTIONS,
     440    }
     441
     442    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
     443
     444    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     445        TokenType.ANTI,
     446        TokenType.APPLY,
     447        TokenType.ASOF,
     448        TokenType.FULL,
     449        TokenType.LEFT,
     450        TokenType.LOCK,
     451        TokenType.NATURAL,
     452        TokenType.OFFSET,
     453        TokenType.RIGHT,
     454        TokenType.SEMI,
     455        TokenType.WINDOW,
     456    }
     457
     458    ALIAS_TOKENS = ID_VAR_TOKENS
     459
     460    ARRAY_CONSTRUCTORS = {
     461        "ARRAY": exp.Array,
     462        "LIST": exp.List,
     463    }
     464
     465    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     466
     467    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     468
     469    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     470
     471    FUNC_TOKENS = {
     472        TokenType.COLLATE,
     473        TokenType.COMMAND,
     474        TokenType.CURRENT_DATE,
     475        TokenType.CURRENT_DATETIME,
     476        TokenType.CURRENT_TIMESTAMP,
     477        TokenType.CURRENT_TIME,
     478        TokenType.CURRENT_USER,
     479        TokenType.FILTER,
     480        TokenType.FIRST,
     481        TokenType.FORMAT,
     482        TokenType.GLOB,
     483        TokenType.IDENTIFIER,
     484        TokenType.INDEX,
     485        TokenType.ISNULL,
     486        TokenType.ILIKE,
     487        TokenType.INSERT,
     488        TokenType.LIKE,
     489        TokenType.MERGE,
     490        TokenType.OFFSET,
     491        TokenType.PRIMARY_KEY,
     492        TokenType.RANGE,
     493        TokenType.REPLACE,
     494        TokenType.RLIKE,
     495        TokenType.ROW,
     496        TokenType.UNNEST,
     497        TokenType.VAR,
     498        TokenType.LEFT,
     499        TokenType.RIGHT,
     500        TokenType.SEQUENCE,
     501        TokenType.DATE,
     502        TokenType.DATETIME,
     503        TokenType.TABLE,
     504        TokenType.TIMESTAMP,
     505        TokenType.TIMESTAMPTZ,
     506        TokenType.TRUNCATE,
     507        TokenType.WINDOW,
     508        TokenType.XOR,
     509        *TYPE_TOKENS,
     510        *SUBQUERY_PREDICATES,
     511    }
     512
     513    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     514        TokenType.AND: exp.And,
     515    }
     516
     517    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     518        TokenType.COLON_EQ: exp.PropertyEQ,
     519    }
     520
     521    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     522        TokenType.OR: exp.Or,
     523    }
     524
     525    EQUALITY = {
     526        TokenType.EQ: exp.EQ,
     527        TokenType.NEQ: exp.NEQ,
     528        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     529    }
     530
     531    COMPARISON = {
     532        TokenType.GT: exp.GT,
     533        TokenType.GTE: exp.GTE,
     534        TokenType.LT: exp.LT,
     535        TokenType.LTE: exp.LTE,
     536    }
     537
     538    BITWISE = {
     539        TokenType.AMP: exp.BitwiseAnd,
     540        TokenType.CARET: exp.BitwiseXor,
     541        TokenType.PIPE: exp.BitwiseOr,
     542    }
     543
     544    TERM = {
     545        TokenType.DASH: exp.Sub,
     546        TokenType.PLUS: exp.Add,
     547        TokenType.MOD: exp.Mod,
     548        TokenType.COLLATE: exp.Collate,
     549    }
     550
     551    FACTOR = {
     552        TokenType.DIV: exp.IntDiv,
     553        TokenType.LR_ARROW: exp.Distance,
     554        TokenType.SLASH: exp.Div,
     555        TokenType.STAR: exp.Mul,
     556    }
     557
     558    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     559
     560    TIMES = {
     561        TokenType.TIME,
     562        TokenType.TIMETZ,
     563    }
     564
     565    TIMESTAMPS = {
     566        TokenType.TIMESTAMP,
     567        TokenType.TIMESTAMPTZ,
     568        TokenType.TIMESTAMPLTZ,
     569        *TIMES,
     570    }
     571
     572    SET_OPERATIONS = {
     573        TokenType.UNION,
     574        TokenType.INTERSECT,
     575        TokenType.EXCEPT,
     576    }
     577
     578    JOIN_METHODS = {
     579        TokenType.ASOF,
     580        TokenType.NATURAL,
     581        TokenType.POSITIONAL,
     582    }
     583
     584    JOIN_SIDES = {
     585        TokenType.LEFT,
     586        TokenType.RIGHT,
     587        TokenType.FULL,
     588    }
     589
     590    JOIN_KINDS = {
     591        TokenType.INNER,
     592        TokenType.OUTER,
     593        TokenType.CROSS,
     594        TokenType.SEMI,
     595        TokenType.ANTI,
     596    }
     597
     598    JOIN_HINTS: t.Set[str] = set()
     599
     600    LAMBDAS = {
     601        TokenType.ARROW: lambda self, expressions: self.expression(
     602            exp.Lambda,
     603            this=self._replace_lambda(
     604                self._parse_assignment(),
     605                expressions,
     606            ),
     607            expressions=expressions,
     608        ),
     609        TokenType.FARROW: lambda self, expressions: self.expression(
     610            exp.Kwarg,
     611            this=exp.var(expressions[0].name),
     612            expression=self._parse_assignment(),
     613        ),
     614    }
     615
     616    COLUMN_OPERATORS = {
     617        TokenType.DOT: None,
     618        TokenType.DCOLON: lambda self, this, to: self.expression(
     619            exp.Cast if self.STRICT_CAST else exp.TryCast,
     620            this=this,
     621            to=to,
     622        ),
     623        TokenType.ARROW: lambda self, this, path: self.expression(
     624            exp.JSONExtract,
     625            this=this,
     626            expression=self.dialect.to_json_path(path),
     627            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     628        ),
     629        TokenType.DARROW: lambda self, this, path: self.expression(
     630            exp.JSONExtractScalar,
     631            this=this,
     632            expression=self.dialect.to_json_path(path),
     633            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     634        ),
     635        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     636            exp.JSONBExtract,
     637            this=this,
     638            expression=path,
     639        ),
     640        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     641            exp.JSONBExtractScalar,
     642            this=this,
     643            expression=path,
     644        ),
     645        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     646            exp.JSONBContains,
     647            this=this,
     648            expression=key,
     649        ),
     650    }
     651
     652    EXPRESSION_PARSERS = {
     653        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     654        exp.Column: lambda self: self._parse_column(),
     655        exp.Condition: lambda self: self._parse_assignment(),
     656        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
     657        exp.Expression: lambda self: self._parse_expression(),
     658        exp.From: lambda self: self._parse_from(joins=True),
     659        exp.Group: lambda self: self._parse_group(),
     660        exp.Having: lambda self: self._parse_having(),
     661        exp.Identifier: lambda self: self._parse_id_var(),
     662        exp.Join: lambda self: self._parse_join(),
     663        exp.Lambda: lambda self: self._parse_lambda(),
     664        exp.Lateral: lambda self: self._parse_lateral(),
     665        exp.Limit: lambda self: self._parse_limit(),
     666        exp.Offset: lambda self: self._parse_offset(),
     667        exp.Order: lambda self: self._parse_order(),
     668        exp.Ordered: lambda self: self._parse_ordered(),
     669        exp.Properties: lambda self: self._parse_properties(),
     670        exp.Qualify: lambda self: self._parse_qualify(),
     671        exp.Returning: lambda self: self._parse_returning(),
     672        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     673        exp.Table: lambda self: self._parse_table_parts(),
     674        exp.TableAlias: lambda self: self._parse_table_alias(),
     675        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
     676        exp.Where: lambda self: self._parse_where(),
     677        exp.Window: lambda self: self._parse_named_window(),
     678        exp.With: lambda self: self._parse_with(),
     679        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     680    }
     681
     682    STATEMENT_PARSERS = {
     683        TokenType.ALTER: lambda self: self._parse_alter(),
     684        TokenType.BEGIN: lambda self: self._parse_transaction(),
     685        TokenType.CACHE: lambda self: self._parse_cache(),
     686        TokenType.COMMENT: lambda self: self._parse_comment(),
     687        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     688        TokenType.COPY: lambda self: self._parse_copy(),
     689        TokenType.CREATE: lambda self: self._parse_create(),
     690        TokenType.DELETE: lambda self: self._parse_delete(),
     691        TokenType.DESC: lambda self: self._parse_describe(),
     692        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     693        TokenType.DROP: lambda self: self._parse_drop(),
     694        TokenType.INSERT: lambda self: self._parse_insert(),
     695        TokenType.KILL: lambda self: self._parse_kill(),
     696        TokenType.LOAD: lambda self: self._parse_load(),
     697        TokenType.MERGE: lambda self: self._parse_merge(),
     698        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     699        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     700        TokenType.REFRESH: lambda self: self._parse_refresh(),
     701        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     702        TokenType.SET: lambda self: self._parse_set(),
     703        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     704        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     705        TokenType.UPDATE: lambda self: self._parse_update(),
     706        TokenType.USE: lambda self: self.expression(
     707            exp.Use,
     708            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
     709            this=self._parse_table(schema=False),
     710        ),
     711        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
     712    }
     713
     714    UNARY_PARSERS = {
     715        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     716        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     717        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     718        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     719        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     720        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     721    }
     722
     723    STRING_PARSERS = {
     724        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     725            exp.RawString, this=token.text
     726        ),
     727        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     728            exp.National, this=token.text
     729        ),
     730        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     731        TokenType.STRING: lambda self, token: self.expression(
     732            exp.Literal, this=token.text, is_string=True
     733        ),
     734        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     735            exp.UnicodeString,
     736            this=token.text,
     737            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     738        ),
     739    }
     740
     741    NUMERIC_PARSERS = {
     742        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     743        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     744        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
     745        TokenType.NUMBER: lambda self, token: self.expression(
     746            exp.Literal, this=token.text, is_string=False
     747        ),
     748    }
     749
     750    PRIMARY_PARSERS = {
     751        **STRING_PARSERS,
     752        **NUMERIC_PARSERS,
     753        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     754        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     755        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     756        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     757        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     758        TokenType.STAR: lambda self, _: self.expression(
     759            exp.Star,
     760            **{
     761                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
     762                "replace": self._parse_star_op("REPLACE"),
     763                "rename": self._parse_star_op("RENAME"),
     764            },
     765        ),
     766    }
     767
     768    PLACEHOLDER_PARSERS = {
     769        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     770        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     771        TokenType.COLON: lambda self: (
     772            self.expression(exp.Placeholder, this=self._prev.text)
     773            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
     774            else None
     775        ),
     776    }
     777
     778    RANGE_PARSERS = {
     779        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     780        TokenType.GLOB: binary_range_parser(exp.Glob),
     781        TokenType.ILIKE: binary_range_parser(exp.ILike),
     782        TokenType.IN: lambda self, this: self._parse_in(this),
     783        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     784        TokenType.IS: lambda self, this: self._parse_is(this),
     785        TokenType.LIKE: binary_range_parser(exp.Like),
     786        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     787        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     788        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     789        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     790    }
     791
     792    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     793        "ALLOWED_VALUES": lambda self: self.expression(
     794            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     795        ),
     796        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     797        "AUTO": lambda self: self._parse_auto_property(),
     798        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     799        "BACKUP": lambda self: self.expression(
     800            exp.BackupProperty, this=self._parse_var(any_token=True)
     801        ),
     802        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     803        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     804        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     805        "CHECKSUM": lambda self: self._parse_checksum(),
     806        "CLUSTER BY": lambda self: self._parse_cluster(),
     807        "CLUSTERED": lambda self: self._parse_clustered_by(),
     808        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     809            exp.CollateProperty, **kwargs
     810        ),
     811        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     812        "CONTAINS": lambda self: self._parse_contains_property(),
     813        "COPY": lambda self: self._parse_copy_property(),
     814        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     815        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     816        "DEFINER": lambda self: self._parse_definer(),
     817        "DETERMINISTIC": lambda self: self.expression(
     818            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     819        ),
     820        "DISTKEY": lambda self: self._parse_distkey(),
     821        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     822        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     823        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     824        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     825        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     826        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     827        "FREESPACE": lambda self: self._parse_freespace(),
     828        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     829        "HEAP": lambda self: self.expression(exp.HeapProperty),
     830        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     831        "IMMUTABLE": lambda self: self.expression(
     832            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     833        ),
     834        "INHERITS": lambda self: self.expression(
     835            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     836        ),
     837        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     838        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     839        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     840        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     841        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     842        "LIKE": lambda self: self._parse_create_like(),
     843        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     844        "LOCK": lambda self: self._parse_locking(),
     845        "LOCKING": lambda self: self._parse_locking(),
     846        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     847        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     848        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     849        "MODIFIES": lambda self: self._parse_modifies_property(),
     850        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     851        "NO": lambda self: self._parse_no_property(),
     852        "ON": lambda self: self._parse_on_property(),
     853        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     854        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     855        "PARTITION": lambda self: self._parse_partitioned_of(),
     856        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     857        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     858        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     859        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     860        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     861        "READS": lambda self: self._parse_reads_property(),
     862        "REMOTE": lambda self: self._parse_remote_with_connection(),
     863        "RETURNS": lambda self: self._parse_returns(),
     864        "STRICT": lambda self: self.expression(exp.StrictProperty),
     865        "ROW": lambda self: self._parse_row(),
     866        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     867        "SAMPLE": lambda self: self.expression(
     868            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
     869        ),
     870        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
     871        "SETTINGS": lambda self: self.expression(
     872            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
     873        ),
     874        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
     875        "SORTKEY": lambda self: self._parse_sortkey(),
     876        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
     877        "STABLE": lambda self: self.expression(
     878            exp.StabilityProperty, this=exp.Literal.string("STABLE")
     879        ),
     880        "STORED": lambda self: self._parse_stored(),
     881        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
     882        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
     883        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
     884        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
     885        "TO": lambda self: self._parse_to_table(),
     886        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
     887        "TRANSFORM": lambda self: self.expression(
     888            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
     889        ),
     890        "TTL": lambda self: self._parse_ttl(),
     891        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     892        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
     893        "VOLATILE": lambda self: self._parse_volatile_property(),
     894        "WITH": lambda self: self._parse_with_property(),
     895    }
     896
     897    CONSTRAINT_PARSERS = {
     898        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
     899        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
     900        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
     901        "CHARACTER SET": lambda self: self.expression(
     902            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
     903        ),
     904        "CHECK": lambda self: self.expression(
     905            exp.CheckColumnConstraint,
     906            this=self._parse_wrapped(self._parse_assignment),
     907            enforced=self._match_text_seq("ENFORCED"),
     908        ),
     909        "COLLATE": lambda self: self.expression(
     910            exp.CollateColumnConstraint, this=self._parse_var(any_token=True)
     911        ),
     912        "COMMENT": lambda self: self.expression(
     913            exp.CommentColumnConstraint, this=self._parse_string()
     914        ),
     915        "COMPRESS": lambda self: self._parse_compress(),
     916        "CLUSTERED": lambda self: self.expression(
     917            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
     918        ),
     919        "NONCLUSTERED": lambda self: self.expression(
     920            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
     921        ),
     922        "DEFAULT": lambda self: self.expression(
     923            exp.DefaultColumnConstraint, this=self._parse_bitwise()
     924        ),
     925        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
     926        "EPHEMERAL": lambda self: self.expression(
     927            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
     928        ),
     929        "EXCLUDE": lambda self: self.expression(
     930            exp.ExcludeColumnConstraint, this=self._parse_index_params()
     931        ),
     932        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
     933        "FORMAT": lambda self: self.expression(
     934            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
     935        ),
     936        "GENERATED": lambda self: self._parse_generated_as_identity(),
     937        "IDENTITY": lambda self: self._parse_auto_increment(),
     938        "INLINE": lambda self: self._parse_inline(),
     939        "LIKE": lambda self: self._parse_create_like(),
     940        "NOT": lambda self: self._parse_not_constraint(),
     941        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
     942        "ON": lambda self: (
     943            self._match(TokenType.UPDATE)
     944            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
     945        )
     946        or self.expression(exp.OnProperty, this=self._parse_id_var()),
     947        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
     948        "PERIOD": lambda self: self._parse_period_for_system_time(),
     949        "PRIMARY KEY": lambda self: self._parse_primary_key(),
     950        "REFERENCES": lambda self: self._parse_references(match=False),
     951        "TITLE": lambda self: self.expression(
     952            exp.TitleColumnConstraint, this=self._parse_var_or_string()
     953        ),
     954        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
     955        "UNIQUE": lambda self: self._parse_unique(),
     956        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
     957        "WITH": lambda self: self.expression(
     958            exp.Properties, expressions=self._parse_wrapped_properties()
     959        ),
     960    }
     961
     962    ALTER_PARSERS = {
     963        "ADD": lambda self: self._parse_alter_table_add(),
     964        "ALTER": lambda self: self._parse_alter_table_alter(),
     965        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
     966        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
     967        "DROP": lambda self: self._parse_alter_table_drop(),
     968        "RENAME": lambda self: self._parse_alter_table_rename(),
     969        "SET": lambda self: self._parse_alter_table_set(),
     970    }
     971
     972    ALTER_ALTER_PARSERS = {
     973        "DISTKEY": lambda self: self._parse_alter_diststyle(),
     974        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
     975        "SORTKEY": lambda self: self._parse_alter_sortkey(),
     976        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
     977    }
     978
     979    SCHEMA_UNNAMED_CONSTRAINTS = {
     980        "CHECK",
     981        "EXCLUDE",
     982        "FOREIGN KEY",
     983        "LIKE",
     984        "PERIOD",
     985        "PRIMARY KEY",
     986        "UNIQUE",
     987    }
     988
     989    NO_PAREN_FUNCTION_PARSERS = {
     990        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
     991        "CASE": lambda self: self._parse_case(),
     992        "IF": lambda self: self._parse_if(),
     993        "NEXT": lambda self: self._parse_next_value_for(),
     994    }
     995
     996    INVALID_FUNC_NAME_TOKENS = {
     997        TokenType.IDENTIFIER,
     998        TokenType.STRING,
     999    }
    1000
    1001    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1002
    1003    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1004
    1005    FUNCTION_PARSERS = {
    1006        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1007        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1008        "DECODE": lambda self: self._parse_decode(),
    1009        "EXTRACT": lambda self: self._parse_extract(),
    1010        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1011        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1012        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1013        "JSON_TABLE": lambda self: self._parse_json_table(),
    1014        "MATCH": lambda self: self._parse_match_against(),
    1015        "OPENJSON": lambda self: self._parse_open_json(),
    1016        "POSITION": lambda self: self._parse_position(),
    1017        "PREDICT": lambda self: self._parse_predict(),
    1018        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1019        "STRING_AGG": lambda self: self._parse_string_agg(),
    1020        "SUBSTRING": lambda self: self._parse_substring(),
    1021        "TRIM": lambda self: self._parse_trim(),
    1022        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1023        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1024    }
    1025
    1026    QUERY_MODIFIER_PARSERS = {
    1027        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1028        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1029        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1030        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1031        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1032        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1033        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1034        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1035        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1036        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1037        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1038        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1039        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1040        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1041        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1042        TokenType.CLUSTER_BY: lambda self: (
    1043            "cluster",
    1044            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1045        ),
    1046        TokenType.DISTRIBUTE_BY: lambda self: (
    1047            "distribute",
    1048            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1049        ),
    1050        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1051        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1052        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1053    }
    1054
    1055    SET_PARSERS = {
    1056        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1057        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1058        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1059        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1060    }
    1061
    1062    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1063
    1064    TYPE_LITERAL_PARSERS = {
    1065        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1066    }
    1067
    1068    TYPE_CONVERTER: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1069
    1070    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1071
    1072    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1073
    1074    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1075    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1076        "ISOLATION": (
    1077            ("LEVEL", "REPEATABLE", "READ"),
    1078            ("LEVEL", "READ", "COMMITTED"),
    1079            ("LEVEL", "READ", "UNCOMITTED"),
    1080            ("LEVEL", "SERIALIZABLE"),
    1081        ),
    1082        "READ": ("WRITE", "ONLY"),
    1083    }
    1084
    1085    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1086        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1087    )
    1088    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1089
    1090    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1091        "SCALE": ("EXTEND", "NOEXTEND"),
    1092        "SHARD": ("EXTEND", "NOEXTEND"),
    1093        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1094        **dict.fromkeys(
    1095            (
    1096                "SESSION",
    1097                "GLOBAL",
    1098                "KEEP",
    1099                "NOKEEP",
    1100                "ORDER",
    1101                "NOORDER",
    1102                "NOCACHE",
    1103                "CYCLE",
    1104                "NOCYCLE",
    1105                "NOMINVALUE",
    1106                "NOMAXVALUE",
    1107                "NOSCALE",
    1108                "NOSHARD",
    1109            ),
    1110            tuple(),
    1111        ),
    1112    }
    1113
    1114    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1115
    1116    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
    1117
    1118    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1119
    1120    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1121
    1122    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1123    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1124
    1125    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1126
    1127    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1128
    1129    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1130
    1131    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1132
    1133    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1134    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1135    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1136
    1137    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1138
    1139    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1140
    1141    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
    1142
    1143    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1144
    1145    NULL_TOKENS = {TokenType.NULL}
    1146
    1147    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
    1148
    1149    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1150
    1151    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1152
    1153    STRICT_CAST = True
    1154
    1155    PREFIXED_PIVOT_COLUMNS = False
    1156    IDENTIFY_PIVOT_STRINGS = False
    1157
    1158    LOG_DEFAULTS_TO_LN = False
    1159
    1160    # Whether ADD is present for each column added by ALTER TABLE
    1161    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1162
    1163    # Whether the table sample clause expects CSV syntax
    1164    TABLESAMPLE_CSV = False
    1165
    1166    # The default method used for table sampling
    1167    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1168
    1169    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1170    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1171
    1172    # Whether the TRIM function expects the characters to trim as its first argument
    1173    TRIM_PATTERN_FIRST = False
    1174
    1175    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1176    STRING_ALIASES = False
    1177
    1178    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1179    MODIFIERS_ATTACHED_TO_UNION = True
    1180    UNION_MODIFIERS = {"order", "limit", "offset"}
    1181
    1182    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1183    NO_PAREN_IF_COMMANDS = True
    1184
    1185    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1186    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1187
    1188    # Whether the `:` operator is used to extract a value from a JSON document
    1189    COLON_IS_JSON_EXTRACT = False
    1190
    1191    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1192    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1193    VALUES_FOLLOWED_BY_PAREN = True
    1194
    1195    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1196    SUPPORTS_IMPLICIT_UNNEST = False
    1197
    1198    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1199    INTERVAL_SPANS = True
    1200
    1201    # Whether a PARTITION clause can follow a table reference
    1202    SUPPORTS_PARTITION_SELECTION = False
    1203
    1204    __slots__ = (
    1205        "error_level",
    1206        "error_message_context",
    1207        "max_errors",
    1208        "dialect",
    1209        "sql",
    1210        "errors",
    1211        "_tokens",
    1212        "_index",
    1213        "_curr",
    1214        "_next",
    1215        "_prev",
    1216        "_prev_comments",
    1217    )
    1218
    1219    # Autofilled
    1220    SHOW_TRIE: t.Dict = {}
    1221    SET_TRIE: t.Dict = {}
    1222
    1223    def __init__(
    1224        self,
    1225        error_level: t.Optional[ErrorLevel] = None,
    1226        error_message_context: int = 100,
    1227        max_errors: int = 3,
    1228        dialect: DialectType = None,
    1229    ):
    1230        from sqlglot.dialects import Dialect
    1231
    1232        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1233        self.error_message_context = error_message_context
    1234        self.max_errors = max_errors
    1235        self.dialect = Dialect.get_or_raise(dialect)
    1236        self.reset()
    1237
    1238    def reset(self):
    1239        self.sql = ""
    1240        self.errors = []
    1241        self._tokens = []
    1242        self._index = 0
    1243        self._curr = None
    1244        self._next = None
    1245        self._prev = None
    1246        self._prev_comments = None
    1247
    1248    def parse(
    1249        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1250    ) -> t.List[t.Optional[exp.Expression]]:
    1251        """
    1252        Parses a list of tokens and returns a list of syntax trees, one tree
    1253        per parsed SQL statement.
    1254
    1255        Args:
    1256            raw_tokens: The list of tokens.
    1257            sql: The original SQL string, used to produce helpful debug messages.
    1258
    1259        Returns:
    1260            The list of the produced syntax trees.
    1261        """
    1262        return self._parse(
    1263            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1264        )
    1265
    1266    def parse_into(
    1267        self,
    1268        expression_types: exp.IntoType,
    1269        raw_tokens: t.List[Token],
    1270        sql: t.Optional[str] = None,
    1271    ) -> t.List[t.Optional[exp.Expression]]:
    1272        """
    1273        Parses a list of tokens into a given Expression type. If a collection of Expression
    1274        types is given instead, this method will try to parse the token list into each one
    1275        of them, stopping at the first for which the parsing succeeds.
    1276
    1277        Args:
    1278            expression_types: The expression type(s) to try and parse the token list into.
    1279            raw_tokens: The list of tokens.
    1280            sql: The original SQL string, used to produce helpful debug messages.
    1281
    1282        Returns:
    1283            The target Expression.
    1284        """
    1285        errors = []
    1286        for expression_type in ensure_list(expression_types):
    1287            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1288            if not parser:
    1289                raise TypeError(f"No parser registered for {expression_type}")
    1290
    1291            try:
    1292                return self._parse(parser, raw_tokens, sql)
    1293            except ParseError as e:
    1294                e.errors[0]["into_expression"] = expression_type
    1295                errors.append(e)
    1296
    1297        raise ParseError(
    1298            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1299            errors=merge_errors(errors),
    1300        ) from errors[-1]
    1301
    1302    def _parse(
    1303        self,
    1304        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1305        raw_tokens: t.List[Token],
    1306        sql: t.Optional[str] = None,
    1307    ) -> t.List[t.Optional[exp.Expression]]:
    1308        self.reset()
    1309        self.sql = sql or ""
    1310
    1311        total = len(raw_tokens)
    1312        chunks: t.List[t.List[Token]] = [[]]
    1313
    1314        for i, token in enumerate(raw_tokens):
    1315            if token.token_type == TokenType.SEMICOLON:
    1316                if token.comments:
    1317                    chunks.append([token])
    1318
    1319                if i < total - 1:
    1320                    chunks.append([])
    1321            else:
    1322                chunks[-1].append(token)
    1323
    1324        expressions = []
    1325
    1326        for tokens in chunks:
    1327            self._index = -1
    1328            self._tokens = tokens
    1329            self._advance()
    1330
    1331            expressions.append(parse_method(self))
    1332
    1333            if self._index < len(self._tokens):
    1334                self.raise_error("Invalid expression / Unexpected token")
    1335
    1336            self.check_errors()
    1337
    1338        return expressions
    1339
    1340    def check_errors(self) -> None:
    1341        """Logs or raises any found errors, depending on the chosen error level setting."""
    1342        if self.error_level == ErrorLevel.WARN:
    1343            for error in self.errors:
    1344                logger.error(str(error))
    1345        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1346            raise ParseError(
    1347                concat_messages(self.errors, self.max_errors),
    1348                errors=merge_errors(self.errors),
    1349            )
    1350
    1351    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1352        """
    1353        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1354        error level setting.
    1355        """
    1356        token = token or self._curr or self._prev or Token.string("")
    1357        start = token.start
    1358        end = token.end + 1
    1359        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1360        highlight = self.sql[start:end]
    1361        end_context = self.sql[end : end + self.error_message_context]
    1362
    1363        error = ParseError.new(
    1364            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1365            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1366            description=message,
    1367            line=token.line,
    1368            col=token.col,
    1369            start_context=start_context,
    1370            highlight=highlight,
    1371            end_context=end_context,
    1372        )
    1373
    1374        if self.error_level == ErrorLevel.IMMEDIATE:
    1375            raise error
    1376
    1377        self.errors.append(error)
    1378
    1379    def expression(
    1380        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1381    ) -> E:
    1382        """
    1383        Creates a new, validated Expression.
    1384
    1385        Args:
    1386            exp_class: The expression class to instantiate.
    1387            comments: An optional list of comments to attach to the expression.
    1388            kwargs: The arguments to set for the expression along with their respective values.
    1389
    1390        Returns:
    1391            The target expression.
    1392        """
    1393        instance = exp_class(**kwargs)
    1394        instance.add_comments(comments) if comments else self._add_comments(instance)
    1395        return self.validate_expression(instance)
    1396
    1397    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1398        if expression and self._prev_comments:
    1399            expression.add_comments(self._prev_comments)
    1400            self._prev_comments = None
    1401
    1402    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1403        """
    1404        Validates an Expression, making sure that all its mandatory arguments are set.
    1405
    1406        Args:
    1407            expression: The expression to validate.
    1408            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1409
    1410        Returns:
    1411            The validated expression.
    1412        """
    1413        if self.error_level != ErrorLevel.IGNORE:
    1414            for error_message in expression.error_messages(args):
    1415                self.raise_error(error_message)
    1416
    1417        return expression
    1418
    1419    def _find_sql(self, start: Token, end: Token) -> str:
    1420        return self.sql[start.start : end.end + 1]
    1421
    1422    def _is_connected(self) -> bool:
    1423        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1424
    1425    def _advance(self, times: int = 1) -> None:
    1426        self._index += times
    1427        self._curr = seq_get(self._tokens, self._index)
    1428        self._next = seq_get(self._tokens, self._index + 1)
    1429
    1430        if self._index > 0:
    1431            self._prev = self._tokens[self._index - 1]
    1432            self._prev_comments = self._prev.comments
    1433        else:
    1434            self._prev = None
    1435            self._prev_comments = None
    1436
    1437    def _retreat(self, index: int) -> None:
    1438        if index != self._index:
    1439            self._advance(index - self._index)
    1440
    1441    def _warn_unsupported(self) -> None:
    1442        if len(self._tokens) <= 1:
    1443            return
    1444
    1445        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1446        # interested in emitting a warning for the one being currently processed.
    1447        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1448
    1449        logger.warning(
    1450            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1451        )
    1452
    1453    def _parse_command(self) -> exp.Command:
    1454        self._warn_unsupported()
    1455        return self.expression(
    1456            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
    1457        )
    1458
    1459    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1460        """
    1461        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
    1462        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
    1463        the parser state accordingly
    1464        """
    1465        index = self._index
    1466        error_level = self.error_level
    1467
    1468        self.error_level = ErrorLevel.IMMEDIATE
    1469        try:
    1470            this = parse_method()
    1471        except ParseError:
    1472            this = None
    1473        finally:
    1474            if not this or retreat:
    1475                self._retreat(index)
    1476            self.error_level = error_level
    1477
    1478        return this
    1479
    1480    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1481        start = self._prev
    1482        exists = self._parse_exists() if allow_exists else None
    1483
    1484        self._match(TokenType.ON)
    1485
    1486        materialized = self._match_text_seq("MATERIALIZED")
    1487        kind = self._match_set(self.CREATABLES) and self._prev
    1488        if not kind:
    1489            return self._parse_as_command(start)
    1490
    1491        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1492            this = self._parse_user_defined_function(kind=kind.token_type)
    1493        elif kind.token_type == TokenType.TABLE:
    1494            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1495        elif kind.token_type == TokenType.COLUMN:
    1496            this = self._parse_column()
    1497        else:
    1498            this = self._parse_id_var()
    1499
    1500        self._match(TokenType.IS)
    1501
    1502        return self.expression(
    1503            exp.Comment,
    1504            this=this,
    1505            kind=kind.text,
    1506            expression=self._parse_string(),
    1507            exists=exists,
    1508            materialized=materialized,
    1509        )
    1510
    1511    def _parse_to_table(
    1512        self,
    1513    ) -> exp.ToTableProperty:
    1514        table = self._parse_table_parts(schema=True)
    1515        return self.expression(exp.ToTableProperty, this=table)
    1516
    1517    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1518    def _parse_ttl(self) -> exp.Expression:
    1519        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1520            this = self._parse_bitwise()
    1521
    1522            if self._match_text_seq("DELETE"):
    1523                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1524            if self._match_text_seq("RECOMPRESS"):
    1525                return self.expression(
    1526                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1527                )
    1528            if self._match_text_seq("TO", "DISK"):
    1529                return self.expression(
    1530                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1531                )
    1532            if self._match_text_seq("TO", "VOLUME"):
    1533                return self.expression(
    1534                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1535                )
    1536
    1537            return this
    1538
    1539        expressions = self._parse_csv(_parse_ttl_action)
    1540        where = self._parse_where()
    1541        group = self._parse_group()
    1542
    1543        aggregates = None
    1544        if group and self._match(TokenType.SET):
    1545            aggregates = self._parse_csv(self._parse_set_item)
    1546
    1547        return self.expression(
    1548            exp.MergeTreeTTL,
    1549            expressions=expressions,
    1550            where=where,
    1551            group=group,
    1552            aggregates=aggregates,
    1553        )
    1554
    1555    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1556        if self._curr is None:
    1557            return None
    1558
    1559        if self._match_set(self.STATEMENT_PARSERS):
    1560            return self.STATEMENT_PARSERS[self._prev.token_type](self)
    1561
    1562        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1563            return self._parse_command()
    1564
    1565        expression = self._parse_expression()
    1566        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1567        return self._parse_query_modifiers(expression)
    1568
    1569    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1570        start = self._prev
    1571        temporary = self._match(TokenType.TEMPORARY)
    1572        materialized = self._match_text_seq("MATERIALIZED")
    1573
    1574        kind = self._match_set(self.CREATABLES) and self._prev.text
    1575        if not kind:
    1576            return self._parse_as_command(start)
    1577
    1578        if_exists = exists or self._parse_exists()
    1579        table = self._parse_table_parts(
    1580            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1581        )
    1582
    1583        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1584
    1585        if self._match(TokenType.L_PAREN, advance=False):
    1586            expressions = self._parse_wrapped_csv(self._parse_types)
    1587        else:
    1588            expressions = None
    1589
    1590        return self.expression(
    1591            exp.Drop,
    1592            comments=start.comments,
    1593            exists=if_exists,
    1594            this=table,
    1595            expressions=expressions,
    1596            kind=kind.upper(),
    1597            temporary=temporary,
    1598            materialized=materialized,
    1599            cascade=self._match_text_seq("CASCADE"),
    1600            constraints=self._match_text_seq("CONSTRAINTS"),
    1601            purge=self._match_text_seq("PURGE"),
    1602            cluster=cluster,
    1603        )
    1604
    1605    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1606        return (
    1607            self._match_text_seq("IF")
    1608            and (not not_ or self._match(TokenType.NOT))
    1609            and self._match(TokenType.EXISTS)
    1610        )
    1611
    1612    def _parse_create(self) -> exp.Create | exp.Command:
    1613        # Note: this can't be None because we've matched a statement parser
    1614        start = self._prev
    1615        comments = self._prev_comments
    1616
    1617        replace = (
    1618            start.token_type == TokenType.REPLACE
    1619            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1620            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1621        )
    1622
    1623        unique = self._match(TokenType.UNIQUE)
    1624
    1625        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1626            self._advance()
    1627
    1628        properties = None
    1629        create_token = self._match_set(self.CREATABLES) and self._prev
    1630
    1631        if not create_token:
    1632            # exp.Properties.Location.POST_CREATE
    1633            properties = self._parse_properties()
    1634            create_token = self._match_set(self.CREATABLES) and self._prev
    1635
    1636            if not properties or not create_token:
    1637                return self._parse_as_command(start)
    1638
    1639        exists = self._parse_exists(not_=True)
    1640        this = None
    1641        expression: t.Optional[exp.Expression] = None
    1642        indexes = None
    1643        no_schema_binding = None
    1644        begin = None
    1645        end = None
    1646        clone = None
    1647
    1648        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1649            nonlocal properties
    1650            if properties and temp_props:
    1651                properties.expressions.extend(temp_props.expressions)
    1652            elif temp_props:
    1653                properties = temp_props
    1654
    1655        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1656            this = self._parse_user_defined_function(kind=create_token.token_type)
    1657
    1658            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1659            extend_props(self._parse_properties())
    1660
    1661            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1662            extend_props(self._parse_properties())
    1663
    1664            if not expression:
    1665                if self._match(TokenType.COMMAND):
    1666                    expression = self._parse_as_command(self._prev)
    1667                else:
    1668                    begin = self._match(TokenType.BEGIN)
    1669                    return_ = self._match_text_seq("RETURN")
    1670
    1671                    if self._match(TokenType.STRING, advance=False):
    1672                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1673                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1674                        expression = self._parse_string()
    1675                        extend_props(self._parse_properties())
    1676                    else:
    1677                        expression = self._parse_statement()
    1678
    1679                    end = self._match_text_seq("END")
    1680
    1681                    if return_:
    1682                        expression = self.expression(exp.Return, this=expression)
    1683        elif create_token.token_type == TokenType.INDEX:
    1684            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1685            if not self._match(TokenType.ON):
    1686                index = self._parse_id_var()
    1687                anonymous = False
    1688            else:
    1689                index = None
    1690                anonymous = True
    1691
    1692            this = self._parse_index(index=index, anonymous=anonymous)
    1693        elif create_token.token_type in self.DB_CREATABLES:
    1694            table_parts = self._parse_table_parts(
    1695                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1696            )
    1697
    1698            # exp.Properties.Location.POST_NAME
    1699            self._match(TokenType.COMMA)
    1700            extend_props(self._parse_properties(before=True))
    1701
    1702            this = self._parse_schema(this=table_parts)
    1703
    1704            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1705            extend_props(self._parse_properties())
    1706
    1707            self._match(TokenType.ALIAS)
    1708            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1709                # exp.Properties.Location.POST_ALIAS
    1710                extend_props(self._parse_properties())
    1711
    1712            if create_token.token_type == TokenType.SEQUENCE:
    1713                expression = self._parse_types()
    1714                extend_props(self._parse_properties())
    1715            else:
    1716                expression = self._parse_ddl_select()
    1717
    1718            if create_token.token_type == TokenType.TABLE:
    1719                # exp.Properties.Location.POST_EXPRESSION
    1720                extend_props(self._parse_properties())
    1721
    1722                indexes = []
    1723                while True:
    1724                    index = self._parse_index()
    1725
    1726                    # exp.Properties.Location.POST_INDEX
    1727                    extend_props(self._parse_properties())
    1728
    1729                    if not index:
    1730                        break
    1731                    else:
    1732                        self._match(TokenType.COMMA)
    1733                        indexes.append(index)
    1734            elif create_token.token_type == TokenType.VIEW:
    1735                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1736                    no_schema_binding = True
    1737
    1738            shallow = self._match_text_seq("SHALLOW")
    1739
    1740            if self._match_texts(self.CLONE_KEYWORDS):
    1741                copy = self._prev.text.lower() == "copy"
    1742                clone = self.expression(
    1743                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    1744                )
    1745
    1746        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    1747            return self._parse_as_command(start)
    1748
    1749        return self.expression(
    1750            exp.Create,
    1751            comments=comments,
    1752            this=this,
    1753            kind=create_token.text.upper(),
    1754            replace=replace,
    1755            unique=unique,
    1756            expression=expression,
    1757            exists=exists,
    1758            properties=properties,
    1759            indexes=indexes,
    1760            no_schema_binding=no_schema_binding,
    1761            begin=begin,
    1762            end=end,
    1763            clone=clone,
    1764        )
    1765
    1766    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    1767        seq = exp.SequenceProperties()
    1768
    1769        options = []
    1770        index = self._index
    1771
    1772        while self._curr:
    1773            self._match(TokenType.COMMA)
    1774            if self._match_text_seq("INCREMENT"):
    1775                self._match_text_seq("BY")
    1776                self._match_text_seq("=")
    1777                seq.set("increment", self._parse_term())
    1778            elif self._match_text_seq("MINVALUE"):
    1779                seq.set("minvalue", self._parse_term())
    1780            elif self._match_text_seq("MAXVALUE"):
    1781                seq.set("maxvalue", self._parse_term())
    1782            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    1783                self._match_text_seq("=")
    1784                seq.set("start", self._parse_term())
    1785            elif self._match_text_seq("CACHE"):
    1786                # T-SQL allows empty CACHE which is initialized dynamically
    1787                seq.set("cache", self._parse_number() or True)
    1788            elif self._match_text_seq("OWNED", "BY"):
    1789                # "OWNED BY NONE" is the default
    1790                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    1791            else:
    1792                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    1793                if opt:
    1794                    options.append(opt)
    1795                else:
    1796                    break
    1797
    1798        seq.set("options", options if options else None)
    1799        return None if self._index == index else seq
    1800
    1801    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    1802        # only used for teradata currently
    1803        self._match(TokenType.COMMA)
    1804
    1805        kwargs = {
    1806            "no": self._match_text_seq("NO"),
    1807            "dual": self._match_text_seq("DUAL"),
    1808            "before": self._match_text_seq("BEFORE"),
    1809            "default": self._match_text_seq("DEFAULT"),
    1810            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    1811            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    1812            "after": self._match_text_seq("AFTER"),
    1813            "minimum": self._match_texts(("MIN", "MINIMUM")),
    1814            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    1815        }
    1816
    1817        if self._match_texts(self.PROPERTY_PARSERS):
    1818            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    1819            try:
    1820                return parser(self, **{k: v for k, v in kwargs.items() if v})
    1821            except TypeError:
    1822                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    1823
    1824        return None
    1825
    1826    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    1827        return self._parse_wrapped_csv(self._parse_property)
    1828
    1829    def _parse_property(self) -> t.Optional[exp.Expression]:
    1830        if self._match_texts(self.PROPERTY_PARSERS):
    1831            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    1832
    1833        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    1834            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    1835
    1836        if self._match_text_seq("COMPOUND", "SORTKEY"):
    1837            return self._parse_sortkey(compound=True)
    1838
    1839        if self._match_text_seq("SQL", "SECURITY"):
    1840            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    1841
    1842        index = self._index
    1843        key = self._parse_column()
    1844
    1845        if not self._match(TokenType.EQ):
    1846            self._retreat(index)
    1847            return self._parse_sequence_properties()
    1848
    1849        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    1850        if isinstance(key, exp.Column):
    1851            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    1852
    1853        value = self._parse_bitwise() or self._parse_var(any_token=True)
    1854
    1855        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    1856        if isinstance(value, exp.Column):
    1857            value = exp.var(value.name)
    1858
    1859        return self.expression(exp.Property, this=key, value=value)
    1860
    1861    def _parse_stored(self) -> exp.FileFormatProperty:
    1862        self._match(TokenType.ALIAS)
    1863
    1864        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    1865        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    1866
    1867        return self.expression(
    1868            exp.FileFormatProperty,
    1869            this=(
    1870                self.expression(
    1871                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
    1872                )
    1873                if input_format or output_format
    1874                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    1875            ),
    1876        )
    1877
    1878    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    1879        field = self._parse_field()
    1880        if isinstance(field, exp.Identifier) and not field.quoted:
    1881            field = exp.var(field)
    1882
    1883        return field
    1884
    1885    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    1886        self._match(TokenType.EQ)
    1887        self._match(TokenType.ALIAS)
    1888
    1889        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    1890
    1891    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    1892        properties = []
    1893        while True:
    1894            if before:
    1895                prop = self._parse_property_before()
    1896            else:
    1897                prop = self._parse_property()
    1898            if not prop:
    1899                break
    1900            for p in ensure_list(prop):
    1901                properties.append(p)
    1902
    1903        if properties:
    1904            return self.expression(exp.Properties, expressions=properties)
    1905
    1906        return None
    1907
    1908    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    1909        return self.expression(
    1910            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    1911        )
    1912
    1913    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    1914        if self._index >= 2:
    1915            pre_volatile_token = self._tokens[self._index - 2]
    1916        else:
    1917            pre_volatile_token = None
    1918
    1919        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    1920            return exp.VolatileProperty()
    1921
    1922        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    1923
    1924    def _parse_retention_period(self) -> exp.Var:
    1925        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    1926        number = self._parse_number()
    1927        number_str = f"{number} " if number else ""
    1928        unit = self._parse_var(any_token=True)
    1929        return exp.var(f"{number_str}{unit}")
    1930
    1931    def _parse_system_versioning_property(
    1932        self, with_: bool = False
    1933    ) -> exp.WithSystemVersioningProperty:
    1934        self._match(TokenType.EQ)
    1935        prop = self.expression(
    1936            exp.WithSystemVersioningProperty,
    1937            **{  # type: ignore
    1938                "on": True,
    1939                "with": with_,
    1940            },
    1941        )
    1942
    1943        if self._match_text_seq("OFF"):
    1944            prop.set("on", False)
    1945            return prop
    1946
    1947        self._match(TokenType.ON)
    1948        if self._match(TokenType.L_PAREN):
    1949            while self._curr and not self._match(TokenType.R_PAREN):
    1950                if self._match_text_seq("HISTORY_TABLE", "="):
    1951                    prop.set("this", self._parse_table_parts())
    1952                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    1953                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    1954                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    1955                    prop.set("retention_period", self._parse_retention_period())
    1956
    1957                self._match(TokenType.COMMA)
    1958
    1959        return prop
    1960
    1961    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    1962        self._match(TokenType.EQ)
    1963        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    1964        prop = self.expression(exp.DataDeletionProperty, on=on)
    1965
    1966        if self._match(TokenType.L_PAREN):
    1967            while self._curr and not self._match(TokenType.R_PAREN):
    1968                if self._match_text_seq("FILTER_COLUMN", "="):
    1969                    prop.set("filter_column", self._parse_column())
    1970                elif self._match_text_seq("RETENTION_PERIOD", "="):
    1971                    prop.set("retention_period", self._parse_retention_period())
    1972
    1973                self._match(TokenType.COMMA)
    1974
    1975        return prop
    1976
    1977    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    1978        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    1979            prop = self._parse_system_versioning_property(with_=True)
    1980            self._match_r_paren()
    1981            return prop
    1982
    1983        if self._match(TokenType.L_PAREN, advance=False):
    1984            return self._parse_wrapped_properties()
    1985
    1986        if self._match_text_seq("JOURNAL"):
    1987            return self._parse_withjournaltable()
    1988
    1989        if self._match_texts(self.VIEW_ATTRIBUTES):
    1990            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    1991
    1992        if self._match_text_seq("DATA"):
    1993            return self._parse_withdata(no=False)
    1994        elif self._match_text_seq("NO", "DATA"):
    1995            return self._parse_withdata(no=True)
    1996
    1997        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    1998            return self._parse_serde_properties(with_=True)
    1999
    2000        if not self._next:
    2001            return None
    2002
    2003        return self._parse_withisolatedloading()
    2004
    2005    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2006    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2007        self._match(TokenType.EQ)
    2008
    2009        user = self._parse_id_var()
    2010        self._match(TokenType.PARAMETER)
    2011        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2012
    2013        if not user or not host:
    2014            return None
    2015
    2016        return exp.DefinerProperty(this=f"{user}@{host}")
    2017
    2018    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2019        self._match(TokenType.TABLE)
    2020        self._match(TokenType.EQ)
    2021        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2022
    2023    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2024        return self.expression(exp.LogProperty, no=no)
    2025
    2026    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2027        return self.expression(exp.JournalProperty, **kwargs)
    2028
    2029    def _parse_checksum(self) -> exp.ChecksumProperty:
    2030        self._match(TokenType.EQ)
    2031
    2032        on = None
    2033        if self._match(TokenType.ON):
    2034            on = True
    2035        elif self._match_text_seq("OFF"):
    2036            on = False
    2037
    2038        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2039
    2040    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2041        return self.expression(
    2042            exp.Cluster,
    2043            expressions=(
    2044                self._parse_wrapped_csv(self._parse_ordered)
    2045                if wrapped
    2046                else self._parse_csv(self._parse_ordered)
    2047            ),
    2048        )
    2049
    2050    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2051        self._match_text_seq("BY")
    2052
    2053        self._match_l_paren()
    2054        expressions = self._parse_csv(self._parse_column)
    2055        self._match_r_paren()
    2056
    2057        if self._match_text_seq("SORTED", "BY"):
    2058            self._match_l_paren()
    2059            sorted_by = self._parse_csv(self._parse_ordered)
    2060            self._match_r_paren()
    2061        else:
    2062            sorted_by = None
    2063
    2064        self._match(TokenType.INTO)
    2065        buckets = self._parse_number()
    2066        self._match_text_seq("BUCKETS")
    2067
    2068        return self.expression(
    2069            exp.ClusteredByProperty,
    2070            expressions=expressions,
    2071            sorted_by=sorted_by,
    2072            buckets=buckets,
    2073        )
    2074
    2075    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2076        if not self._match_text_seq("GRANTS"):
    2077            self._retreat(self._index - 1)
    2078            return None
    2079
    2080        return self.expression(exp.CopyGrantsProperty)
    2081
    2082    def _parse_freespace(self) -> exp.FreespaceProperty:
    2083        self._match(TokenType.EQ)
    2084        return self.expression(
    2085            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2086        )
    2087
    2088    def _parse_mergeblockratio(
    2089        self, no: bool = False, default: bool = False
    2090    ) -> exp.MergeBlockRatioProperty:
    2091        if self._match(TokenType.EQ):
    2092            return self.expression(
    2093                exp.MergeBlockRatioProperty,
    2094                this=self._parse_number(),
    2095                percent=self._match(TokenType.PERCENT),
    2096            )
    2097
    2098        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2099
    2100    def _parse_datablocksize(
    2101        self,
    2102        default: t.Optional[bool] = None,
    2103        minimum: t.Optional[bool] = None,
    2104        maximum: t.Optional[bool] = None,
    2105    ) -> exp.DataBlocksizeProperty:
    2106        self._match(TokenType.EQ)
    2107        size = self._parse_number()
    2108
    2109        units = None
    2110        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2111            units = self._prev.text
    2112
    2113        return self.expression(
    2114            exp.DataBlocksizeProperty,
    2115            size=size,
    2116            units=units,
    2117            default=default,
    2118            minimum=minimum,
    2119            maximum=maximum,
    2120        )
    2121
    2122    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2123        self._match(TokenType.EQ)
    2124        always = self._match_text_seq("ALWAYS")
    2125        manual = self._match_text_seq("MANUAL")
    2126        never = self._match_text_seq("NEVER")
    2127        default = self._match_text_seq("DEFAULT")
    2128
    2129        autotemp = None
    2130        if self._match_text_seq("AUTOTEMP"):
    2131            autotemp = self._parse_schema()
    2132
    2133        return self.expression(
    2134            exp.BlockCompressionProperty,
    2135            always=always,
    2136            manual=manual,
    2137            never=never,
    2138            default=default,
    2139            autotemp=autotemp,
    2140        )
    2141
    2142    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2143        index = self._index
    2144        no = self._match_text_seq("NO")
    2145        concurrent = self._match_text_seq("CONCURRENT")
    2146
    2147        if not self._match_text_seq("ISOLATED", "LOADING"):
    2148            self._retreat(index)
    2149            return None
    2150
    2151        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2152        return self.expression(
    2153            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2154        )
    2155
    2156    def _parse_locking(self) -> exp.LockingProperty:
    2157        if self._match(TokenType.TABLE):
    2158            kind = "TABLE"
    2159        elif self._match(TokenType.VIEW):
    2160            kind = "VIEW"
    2161        elif self._match(TokenType.ROW):
    2162            kind = "ROW"
    2163        elif self._match_text_seq("DATABASE"):
    2164            kind = "DATABASE"
    2165        else:
    2166            kind = None
    2167
    2168        if kind in ("DATABASE", "TABLE", "VIEW"):
    2169            this = self._parse_table_parts()
    2170        else:
    2171            this = None
    2172
    2173        if self._match(TokenType.FOR):
    2174            for_or_in = "FOR"
    2175        elif self._match(TokenType.IN):
    2176            for_or_in = "IN"
    2177        else:
    2178            for_or_in = None
    2179
    2180        if self._match_text_seq("ACCESS"):
    2181            lock_type = "ACCESS"
    2182        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2183            lock_type = "EXCLUSIVE"
    2184        elif self._match_text_seq("SHARE"):
    2185            lock_type = "SHARE"
    2186        elif self._match_text_seq("READ"):
    2187            lock_type = "READ"
    2188        elif self._match_text_seq("WRITE"):
    2189            lock_type = "WRITE"
    2190        elif self._match_text_seq("CHECKSUM"):
    2191            lock_type = "CHECKSUM"
    2192        else:
    2193            lock_type = None
    2194
    2195        override = self._match_text_seq("OVERRIDE")
    2196
    2197        return self.expression(
    2198            exp.LockingProperty,
    2199            this=this,
    2200            kind=kind,
    2201            for_or_in=for_or_in,
    2202            lock_type=lock_type,
    2203            override=override,
    2204        )
    2205
    2206    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2207        if self._match(TokenType.PARTITION_BY):
    2208            return self._parse_csv(self._parse_assignment)
    2209        return []
    2210
    2211    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2212        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2213            if self._match_text_seq("MINVALUE"):
    2214                return exp.var("MINVALUE")
    2215            if self._match_text_seq("MAXVALUE"):
    2216                return exp.var("MAXVALUE")
    2217            return self._parse_bitwise()
    2218
    2219        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2220        expression = None
    2221        from_expressions = None
    2222        to_expressions = None
    2223
    2224        if self._match(TokenType.IN):
    2225            this = self._parse_wrapped_csv(self._parse_bitwise)
    2226        elif self._match(TokenType.FROM):
    2227            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2228            self._match_text_seq("TO")
    2229            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2230        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2231            this = self._parse_number()
    2232            self._match_text_seq(",", "REMAINDER")
    2233            expression = self._parse_number()
    2234            self._match_r_paren()
    2235        else:
    2236            self.raise_error("Failed to parse partition bound spec.")
    2237
    2238        return self.expression(
    2239            exp.PartitionBoundSpec,
    2240            this=this,
    2241            expression=expression,
    2242            from_expressions=from_expressions,
    2243            to_expressions=to_expressions,
    2244        )
    2245
    2246    # https://www.postgresql.org/docs/current/sql-createtable.html
    2247    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2248        if not self._match_text_seq("OF"):
    2249            self._retreat(self._index - 1)
    2250            return None
    2251
    2252        this = self._parse_table(schema=True)
    2253
    2254        if self._match(TokenType.DEFAULT):
    2255            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2256        elif self._match_text_seq("FOR", "VALUES"):
    2257            expression = self._parse_partition_bound_spec()
    2258        else:
    2259            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2260
    2261        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2262
    2263    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2264        self._match(TokenType.EQ)
    2265        return self.expression(
    2266            exp.PartitionedByProperty,
    2267            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2268        )
    2269
    2270    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2271        if self._match_text_seq("AND", "STATISTICS"):
    2272            statistics = True
    2273        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2274            statistics = False
    2275        else:
    2276            statistics = None
    2277
    2278        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2279
    2280    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2281        if self._match_text_seq("SQL"):
    2282            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2283        return None
    2284
    2285    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2286        if self._match_text_seq("SQL", "DATA"):
    2287            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2288        return None
    2289
    2290    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2291        if self._match_text_seq("PRIMARY", "INDEX"):
    2292            return exp.NoPrimaryIndexProperty()
    2293        if self._match_text_seq("SQL"):
    2294            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2295        return None
    2296
    2297    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2298        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2299            return exp.OnCommitProperty()
    2300        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2301            return exp.OnCommitProperty(delete=True)
    2302        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2303
    2304    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2305        if self._match_text_seq("SQL", "DATA"):
    2306            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2307        return None
    2308
    2309    def _parse_distkey(self) -> exp.DistKeyProperty:
    2310        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2311
    2312    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2313        table = self._parse_table(schema=True)
    2314
    2315        options = []
    2316        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2317            this = self._prev.text.upper()
    2318
    2319            id_var = self._parse_id_var()
    2320            if not id_var:
    2321                return None
    2322
    2323            options.append(
    2324                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2325            )
    2326
    2327        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2328
    2329    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2330        return self.expression(
    2331            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2332        )
    2333
    2334    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2335        self._match(TokenType.EQ)
    2336        return self.expression(
    2337            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2338        )
    2339
    2340    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2341        self._match_text_seq("WITH", "CONNECTION")
    2342        return self.expression(
    2343            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2344        )
    2345
    2346    def _parse_returns(self) -> exp.ReturnsProperty:
    2347        value: t.Optional[exp.Expression]
    2348        null = None
    2349        is_table = self._match(TokenType.TABLE)
    2350
    2351        if is_table:
    2352            if self._match(TokenType.LT):
    2353                value = self.expression(
    2354                    exp.Schema,
    2355                    this="TABLE",
    2356                    expressions=self._parse_csv(self._parse_struct_types),
    2357                )
    2358                if not self._match(TokenType.GT):
    2359                    self.raise_error("Expecting >")
    2360            else:
    2361                value = self._parse_schema(exp.var("TABLE"))
    2362        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2363            null = True
    2364            value = None
    2365        else:
    2366            value = self._parse_types()
    2367
    2368        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2369
    2370    def _parse_describe(self) -> exp.Describe:
    2371        kind = self._match_set(self.CREATABLES) and self._prev.text
    2372        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
    2373        if self._match(TokenType.DOT):
    2374            style = None
    2375            self._retreat(self._index - 2)
    2376        this = self._parse_table(schema=True)
    2377        properties = self._parse_properties()
    2378        expressions = properties.expressions if properties else None
    2379        return self.expression(
    2380            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
    2381        )
    2382
    2383    def _parse_insert(self) -> exp.Insert:
    2384        comments = ensure_list(self._prev_comments)
    2385        hint = self._parse_hint()
    2386        overwrite = self._match(TokenType.OVERWRITE)
    2387        ignore = self._match(TokenType.IGNORE)
    2388        local = self._match_text_seq("LOCAL")
    2389        alternative = None
    2390        is_function = None
    2391
    2392        if self._match_text_seq("DIRECTORY"):
    2393            this: t.Optional[exp.Expression] = self.expression(
    2394                exp.Directory,
    2395                this=self._parse_var_or_string(),
    2396                local=local,
    2397                row_format=self._parse_row_format(match_row=True),
    2398            )
    2399        else:
    2400            if self._match(TokenType.OR):
    2401                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2402
    2403            self._match(TokenType.INTO)
    2404            comments += ensure_list(self._prev_comments)
    2405            self._match(TokenType.TABLE)
    2406            is_function = self._match(TokenType.FUNCTION)
    2407
    2408            this = (
    2409                self._parse_table(schema=True, parse_partition=True)
    2410                if not is_function
    2411                else self._parse_function()
    2412            )
    2413
    2414        returning = self._parse_returning()
    2415
    2416        return self.expression(
    2417            exp.Insert,
    2418            comments=comments,
    2419            hint=hint,
    2420            is_function=is_function,
    2421            this=this,
    2422            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2423            by_name=self._match_text_seq("BY", "NAME"),
    2424            exists=self._parse_exists(),
    2425            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2426            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2427            conflict=self._parse_on_conflict(),
    2428            returning=returning or self._parse_returning(),
    2429            overwrite=overwrite,
    2430            alternative=alternative,
    2431            ignore=ignore,
    2432        )
    2433
    2434    def _parse_kill(self) -> exp.Kill:
    2435        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2436
    2437        return self.expression(
    2438            exp.Kill,
    2439            this=self._parse_primary(),
    2440            kind=kind,
    2441        )
    2442
    2443    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2444        conflict = self._match_text_seq("ON", "CONFLICT")
    2445        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2446
    2447        if not conflict and not duplicate:
    2448            return None
    2449
    2450        conflict_keys = None
    2451        constraint = None
    2452
    2453        if conflict:
    2454            if self._match_text_seq("ON", "CONSTRAINT"):
    2455                constraint = self._parse_id_var()
    2456            elif self._match(TokenType.L_PAREN):
    2457                conflict_keys = self._parse_csv(self._parse_id_var)
    2458                self._match_r_paren()
    2459
    2460        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2461        if self._prev.token_type == TokenType.UPDATE:
    2462            self._match(TokenType.SET)
    2463            expressions = self._parse_csv(self._parse_equality)
    2464        else:
    2465            expressions = None
    2466
    2467        return self.expression(
    2468            exp.OnConflict,
    2469            duplicate=duplicate,
    2470            expressions=expressions,
    2471            action=action,
    2472            conflict_keys=conflict_keys,
    2473            constraint=constraint,
    2474        )
    2475
    2476    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2477        if not self._match(TokenType.RETURNING):
    2478            return None
    2479        return self.expression(
    2480            exp.Returning,
    2481            expressions=self._parse_csv(self._parse_expression),
    2482            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2483        )
    2484
    2485    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2486        if not self._match(TokenType.FORMAT):
    2487            return None
    2488        return self._parse_row_format()
    2489
    2490    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2491        index = self._index
    2492        with_ = with_ or self._match_text_seq("WITH")
    2493
    2494        if not self._match(TokenType.SERDE_PROPERTIES):
    2495            self._retreat(index)
    2496            return None
    2497        return self.expression(
    2498            exp.SerdeProperties,
    2499            **{  # type: ignore
    2500                "expressions": self._parse_wrapped_properties(),
    2501                "with": with_,
    2502            },
    2503        )
    2504
    2505    def _parse_row_format(
    2506        self, match_row: bool = False
    2507    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2508        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2509            return None
    2510
    2511        if self._match_text_seq("SERDE"):
    2512            this = self._parse_string()
    2513
    2514            serde_properties = self._parse_serde_properties()
    2515
    2516            return self.expression(
    2517                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2518            )
    2519
    2520        self._match_text_seq("DELIMITED")
    2521
    2522        kwargs = {}
    2523
    2524        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2525            kwargs["fields"] = self._parse_string()
    2526            if self._match_text_seq("ESCAPED", "BY"):
    2527                kwargs["escaped"] = self._parse_string()
    2528        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2529            kwargs["collection_items"] = self._parse_string()
    2530        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2531            kwargs["map_keys"] = self._parse_string()
    2532        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2533            kwargs["lines"] = self._parse_string()
    2534        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2535            kwargs["null"] = self._parse_string()
    2536
    2537        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2538
    2539    def _parse_load(self) -> exp.LoadData | exp.Command:
    2540        if self._match_text_seq("DATA"):
    2541            local = self._match_text_seq("LOCAL")
    2542            self._match_text_seq("INPATH")
    2543            inpath = self._parse_string()
    2544            overwrite = self._match(TokenType.OVERWRITE)
    2545            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2546
    2547            return self.expression(
    2548                exp.LoadData,
    2549                this=self._parse_table(schema=True),
    2550                local=local,
    2551                overwrite=overwrite,
    2552                inpath=inpath,
    2553                partition=self._parse_partition(),
    2554                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2555                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2556            )
    2557        return self._parse_as_command(self._prev)
    2558
    2559    def _parse_delete(self) -> exp.Delete:
    2560        # This handles MySQL's "Multiple-Table Syntax"
    2561        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2562        tables = None
    2563        comments = self._prev_comments
    2564        if not self._match(TokenType.FROM, advance=False):
    2565            tables = self._parse_csv(self._parse_table) or None
    2566
    2567        returning = self._parse_returning()
    2568
    2569        return self.expression(
    2570            exp.Delete,
    2571            comments=comments,
    2572            tables=tables,
    2573            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    2574            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    2575            where=self._parse_where(),
    2576            returning=returning or self._parse_returning(),
    2577            limit=self._parse_limit(),
    2578        )
    2579
    2580    def _parse_update(self) -> exp.Update:
    2581        comments = self._prev_comments
    2582        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    2583        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    2584        returning = self._parse_returning()
    2585        return self.expression(
    2586            exp.Update,
    2587            comments=comments,
    2588            **{  # type: ignore
    2589                "this": this,
    2590                "expressions": expressions,
    2591                "from": self._parse_from(joins=True),
    2592                "where": self._parse_where(),
    2593                "returning": returning or self._parse_returning(),
    2594                "order": self._parse_order(),
    2595                "limit": self._parse_limit(),
    2596            },
    2597        )
    2598
    2599    def _parse_uncache(self) -> exp.Uncache:
    2600        if not self._match(TokenType.TABLE):
    2601            self.raise_error("Expecting TABLE after UNCACHE")
    2602
    2603        return self.expression(
    2604            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    2605        )
    2606
    2607    def _parse_cache(self) -> exp.Cache:
    2608        lazy = self._match_text_seq("LAZY")
    2609        self._match(TokenType.TABLE)
    2610        table = self._parse_table(schema=True)
    2611
    2612        options = []
    2613        if self._match_text_seq("OPTIONS"):
    2614            self._match_l_paren()
    2615            k = self._parse_string()
    2616            self._match(TokenType.EQ)
    2617            v = self._parse_string()
    2618            options = [k, v]
    2619            self._match_r_paren()
    2620
    2621        self._match(TokenType.ALIAS)
    2622        return self.expression(
    2623            exp.Cache,
    2624            this=table,
    2625            lazy=lazy,
    2626            options=options,
    2627            expression=self._parse_select(nested=True),
    2628        )
    2629
    2630    def _parse_partition(self) -> t.Optional[exp.Partition]:
    2631        if not self._match(TokenType.PARTITION):
    2632            return None
    2633
    2634        return self.expression(
    2635            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
    2636        )
    2637
    2638    def _parse_value(self) -> t.Optional[exp.Tuple]:
    2639        if self._match(TokenType.L_PAREN):
    2640            expressions = self._parse_csv(self._parse_expression)
    2641            self._match_r_paren()
    2642            return self.expression(exp.Tuple, expressions=expressions)
    2643
    2644        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    2645        expression = self._parse_expression()
    2646        if expression:
    2647            return self.expression(exp.Tuple, expressions=[expression])
    2648        return None
    2649
    2650    def _parse_projections(self) -> t.List[exp.Expression]:
    2651        return self._parse_expressions()
    2652
    2653    def _parse_select(
    2654        self,
    2655        nested: bool = False,
    2656        table: bool = False,
    2657        parse_subquery_alias: bool = True,
    2658        parse_set_operation: bool = True,
    2659    ) -> t.Optional[exp.Expression]:
    2660        cte = self._parse_with()
    2661
    2662        if cte:
    2663            this = self._parse_statement()
    2664
    2665            if not this:
    2666                self.raise_error("Failed to parse any statement following CTE")
    2667                return cte
    2668
    2669            if "with" in this.arg_types:
    2670                this.set("with", cte)
    2671            else:
    2672                self.raise_error(f"{this.key} does not support CTE")
    2673                this = cte
    2674
    2675            return this
    2676
    2677        # duckdb supports leading with FROM x
    2678        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    2679
    2680        if self._match(TokenType.SELECT):
    2681            comments = self._prev_comments
    2682
    2683            hint = self._parse_hint()
    2684            all_ = self._match(TokenType.ALL)
    2685            distinct = self._match_set(self.DISTINCT_TOKENS)
    2686
    2687            kind = (
    2688                self._match(TokenType.ALIAS)
    2689                and self._match_texts(("STRUCT", "VALUE"))
    2690                and self._prev.text.upper()
    2691            )
    2692
    2693            if distinct:
    2694                distinct = self.expression(
    2695                    exp.Distinct,
    2696                    on=self._parse_value() if self._match(TokenType.ON) else None,
    2697                )
    2698
    2699            if all_ and distinct:
    2700                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    2701
    2702            limit = self._parse_limit(top=True)
    2703            projections = self._parse_projections()
    2704
    2705            this = self.expression(
    2706                exp.Select,
    2707                kind=kind,
    2708                hint=hint,
    2709                distinct=distinct,
    2710                expressions=projections,
    2711                limit=limit,
    2712            )
    2713            this.comments = comments
    2714
    2715            into = self._parse_into()
    2716            if into:
    2717                this.set("into", into)
    2718
    2719            if not from_:
    2720                from_ = self._parse_from()
    2721
    2722            if from_:
    2723                this.set("from", from_)
    2724
    2725            this = self._parse_query_modifiers(this)
    2726        elif (table or nested) and self._match(TokenType.L_PAREN):
    2727            if self._match(TokenType.PIVOT):
    2728                this = self._parse_simplified_pivot()
    2729            elif self._match(TokenType.FROM):
    2730                this = exp.select("*").from_(
    2731                    t.cast(exp.From, self._parse_from(skip_from_token=True))
    2732                )
    2733            else:
    2734                this = (
    2735                    self._parse_table()
    2736                    if table
    2737                    else self._parse_select(nested=True, parse_set_operation=False)
    2738                )
    2739                this = self._parse_query_modifiers(self._parse_set_operations(this))
    2740
    2741            self._match_r_paren()
    2742
    2743            # We return early here so that the UNION isn't attached to the subquery by the
    2744            # following call to _parse_set_operations, but instead becomes the parent node
    2745            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    2746        elif self._match(TokenType.VALUES, advance=False):
    2747            this = self._parse_derived_table_values()
    2748        elif from_:
    2749            this = exp.select("*").from_(from_.this, copy=False)
    2750        else:
    2751            this = None
    2752
    2753        if parse_set_operation:
    2754            return self._parse_set_operations(this)
    2755        return this
    2756
    2757    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    2758        if not skip_with_token and not self._match(TokenType.WITH):
    2759            return None
    2760
    2761        comments = self._prev_comments
    2762        recursive = self._match(TokenType.RECURSIVE)
    2763
    2764        expressions = []
    2765        while True:
    2766            expressions.append(self._parse_cte())
    2767
    2768            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    2769                break
    2770            else:
    2771                self._match(TokenType.WITH)
    2772
    2773        return self.expression(
    2774            exp.With, comments=comments, expressions=expressions, recursive=recursive
    2775        )
    2776
    2777    def _parse_cte(self) -> exp.CTE:
    2778        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    2779        if not alias or not alias.this:
    2780            self.raise_error("Expected CTE to have alias")
    2781
    2782        self._match(TokenType.ALIAS)
    2783
    2784        if self._match_text_seq("NOT", "MATERIALIZED"):
    2785            materialized = False
    2786        elif self._match_text_seq("MATERIALIZED"):
    2787            materialized = True
    2788        else:
    2789            materialized = None
    2790
    2791        return self.expression(
    2792            exp.CTE,
    2793            this=self._parse_wrapped(self._parse_statement),
    2794            alias=alias,
    2795            materialized=materialized,
    2796        )
    2797
    2798    def _parse_table_alias(
    2799        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    2800    ) -> t.Optional[exp.TableAlias]:
    2801        any_token = self._match(TokenType.ALIAS)
    2802        alias = (
    2803            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    2804            or self._parse_string_as_identifier()
    2805        )
    2806
    2807        index = self._index
    2808        if self._match(TokenType.L_PAREN):
    2809            columns = self._parse_csv(self._parse_function_parameter)
    2810            self._match_r_paren() if columns else self._retreat(index)
    2811        else:
    2812            columns = None
    2813
    2814        if not alias and not columns:
    2815            return None
    2816
    2817        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    2818
    2819        # We bubble up comments from the Identifier to the TableAlias
    2820        if isinstance(alias, exp.Identifier):
    2821            table_alias.add_comments(alias.pop_comments())
    2822
    2823        return table_alias
    2824
    2825    def _parse_subquery(
    2826        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    2827    ) -> t.Optional[exp.Subquery]:
    2828        if not this:
    2829            return None
    2830
    2831        return self.expression(
    2832            exp.Subquery,
    2833            this=this,
    2834            pivots=self._parse_pivots(),
    2835            alias=self._parse_table_alias() if parse_alias else None,
    2836        )
    2837
    2838    def _implicit_unnests_to_explicit(self, this: E) -> E:
    2839        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    2840
    2841        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    2842        for i, join in enumerate(this.args.get("joins") or []):
    2843            table = join.this
    2844            normalized_table = table.copy()
    2845            normalized_table.meta["maybe_column"] = True
    2846            normalized_table = _norm(normalized_table, dialect=self.dialect)
    2847
    2848            if isinstance(table, exp.Table) and not join.args.get("on"):
    2849                if normalized_table.parts[0].name in refs:
    2850                    table_as_column = table.to_column()
    2851                    unnest = exp.Unnest(expressions=[table_as_column])
    2852
    2853                    # Table.to_column creates a parent Alias node that we want to convert to
    2854                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    2855                    if isinstance(table.args.get("alias"), exp.TableAlias):
    2856                        table_as_column.replace(table_as_column.this)
    2857                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    2858
    2859                    table.replace(unnest)
    2860
    2861            refs.add(normalized_table.alias_or_name)
    2862
    2863        return this
    2864
    2865    def _parse_query_modifiers(
    2866        self, this: t.Optional[exp.Expression]
    2867    ) -> t.Optional[exp.Expression]:
    2868        if isinstance(this, (exp.Query, exp.Table)):
    2869            for join in self._parse_joins():
    2870                this.append("joins", join)
    2871            for lateral in iter(self._parse_lateral, None):
    2872                this.append("laterals", lateral)
    2873
    2874            while True:
    2875                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    2876                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    2877                    key, expression = parser(self)
    2878
    2879                    if expression:
    2880                        this.set(key, expression)
    2881                        if key == "limit":
    2882                            offset = expression.args.pop("offset", None)
    2883
    2884                            if offset:
    2885                                offset = exp.Offset(expression=offset)
    2886                                this.set("offset", offset)
    2887
    2888                                limit_by_expressions = expression.expressions
    2889                                expression.set("expressions", None)
    2890                                offset.set("expressions", limit_by_expressions)
    2891                        continue
    2892                break
    2893
    2894        if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
    2895            this = self._implicit_unnests_to_explicit(this)
    2896
    2897        return this
    2898
    2899    def _parse_hint(self) -> t.Optional[exp.Hint]:
    2900        if self._match(TokenType.HINT):
    2901            hints = []
    2902            for hint in iter(
    2903                lambda: self._parse_csv(
    2904                    lambda: self._parse_function() or self._parse_var(upper=True)
    2905                ),
    2906                [],
    2907            ):
    2908                hints.extend(hint)
    2909
    2910            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
    2911                self.raise_error("Expected */ after HINT")
    2912
    2913            return self.expression(exp.Hint, expressions=hints)
    2914
    2915        return None
    2916
    2917    def _parse_into(self) -> t.Optional[exp.Into]:
    2918        if not self._match(TokenType.INTO):
    2919            return None
    2920
    2921        temp = self._match(TokenType.TEMPORARY)
    2922        unlogged = self._match_text_seq("UNLOGGED")
    2923        self._match(TokenType.TABLE)
    2924
    2925        return self.expression(
    2926            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    2927        )
    2928
    2929    def _parse_from(
    2930        self, joins: bool = False, skip_from_token: bool = False
    2931    ) -> t.Optional[exp.From]:
    2932        if not skip_from_token and not self._match(TokenType.FROM):
    2933            return None
    2934
    2935        return self.expression(
    2936            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    2937        )
    2938
    2939    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    2940        return self.expression(
    2941            exp.MatchRecognizeMeasure,
    2942            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    2943            this=self._parse_expression(),
    2944        )
    2945
    2946    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    2947        if not self._match(TokenType.MATCH_RECOGNIZE):
    2948            return None
    2949
    2950        self._match_l_paren()
    2951
    2952        partition = self._parse_partition_by()
    2953        order = self._parse_order()
    2954
    2955        measures = (
    2956            self._parse_csv(self._parse_match_recognize_measure)
    2957            if self._match_text_seq("MEASURES")
    2958            else None
    2959        )
    2960
    2961        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    2962            rows = exp.var("ONE ROW PER MATCH")
    2963        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    2964            text = "ALL ROWS PER MATCH"
    2965            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    2966                text += " SHOW EMPTY MATCHES"
    2967            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    2968                text += " OMIT EMPTY MATCHES"
    2969            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    2970                text += " WITH UNMATCHED ROWS"
    2971            rows = exp.var(text)
    2972        else:
    2973            rows = None
    2974
    2975        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    2976            text = "AFTER MATCH SKIP"
    2977            if self._match_text_seq("PAST", "LAST", "ROW"):
    2978                text += " PAST LAST ROW"
    2979            elif self._match_text_seq("TO", "NEXT", "ROW"):
    2980                text += " TO NEXT ROW"
    2981            elif self._match_text_seq("TO", "FIRST"):
    2982                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    2983            elif self._match_text_seq("TO", "LAST"):
    2984                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    2985            after = exp.var(text)
    2986        else:
    2987            after = None
    2988
    2989        if self._match_text_seq("PATTERN"):
    2990            self._match_l_paren()
    2991
    2992            if not self._curr:
    2993                self.raise_error("Expecting )", self._curr)
    2994
    2995            paren = 1
    2996            start = self._curr
    2997
    2998            while self._curr and paren > 0:
    2999                if self._curr.token_type == TokenType.L_PAREN:
    3000                    paren += 1
    3001                if self._curr.token_type == TokenType.R_PAREN:
    3002                    paren -= 1
    3003
    3004                end = self._prev
    3005                self._advance()
    3006
    3007            if paren > 0:
    3008                self.raise_error("Expecting )", self._curr)
    3009
    3010            pattern = exp.var(self._find_sql(start, end))
    3011        else:
    3012            pattern = None
    3013
    3014        define = (
    3015            self._parse_csv(self._parse_name_as_expression)
    3016            if self._match_text_seq("DEFINE")
    3017            else None
    3018        )
    3019
    3020        self._match_r_paren()
    3021
    3022        return self.expression(
    3023            exp.MatchRecognize,
    3024            partition_by=partition,
    3025            order=order,
    3026            measures=measures,
    3027            rows=rows,
    3028            after=after,
    3029            pattern=pattern,
    3030            define=define,
    3031            alias=self._parse_table_alias(),
    3032        )
    3033
    3034    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3035        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3036        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3037            cross_apply = False
    3038
    3039        if cross_apply is not None:
    3040            this = self._parse_select(table=True)
    3041            view = None
    3042            outer = None
    3043        elif self._match(TokenType.LATERAL):
    3044            this = self._parse_select(table=True)
    3045            view = self._match(TokenType.VIEW)
    3046            outer = self._match(TokenType.OUTER)
    3047        else:
    3048            return None
    3049
    3050        if not this:
    3051            this = (
    3052                self._parse_unnest()
    3053                or self._parse_function()
    3054                or self._parse_id_var(any_token=False)
    3055            )
    3056
    3057            while self._match(TokenType.DOT):
    3058                this = exp.Dot(
    3059                    this=this,
    3060                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3061                )
    3062
    3063        if view:
    3064            table = self._parse_id_var(any_token=False)
    3065            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3066            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3067                exp.TableAlias, this=table, columns=columns
    3068            )
    3069        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3070            # We move the alias from the lateral's child node to the lateral itself
    3071            table_alias = this.args["alias"].pop()
    3072        else:
    3073            table_alias = self._parse_table_alias()
    3074
    3075        return self.expression(
    3076            exp.Lateral,
    3077            this=this,
    3078            view=view,
    3079            outer=outer,
    3080            alias=table_alias,
    3081            cross_apply=cross_apply,
    3082        )
    3083
    3084    def _parse_join_parts(
    3085        self,
    3086    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3087        return (
    3088            self._match_set(self.JOIN_METHODS) and self._prev,
    3089            self._match_set(self.JOIN_SIDES) and self._prev,
    3090            self._match_set(self.JOIN_KINDS) and self._prev,
    3091        )
    3092
    3093    def _parse_join(
    3094        self, skip_join_token: bool = False, parse_bracket: bool = False
    3095    ) -> t.Optional[exp.Join]:
    3096        if self._match(TokenType.COMMA):
    3097            return self.expression(exp.Join, this=self._parse_table())
    3098
    3099        index = self._index
    3100        method, side, kind = self._parse_join_parts()
    3101        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3102        join = self._match(TokenType.JOIN)
    3103
    3104        if not skip_join_token and not join:
    3105            self._retreat(index)
    3106            kind = None
    3107            method = None
    3108            side = None
    3109
    3110        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3111        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3112
    3113        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3114            return None
    3115
    3116        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3117
    3118        if method:
    3119            kwargs["method"] = method.text
    3120        if side:
    3121            kwargs["side"] = side.text
    3122        if kind:
    3123            kwargs["kind"] = kind.text
    3124        if hint:
    3125            kwargs["hint"] = hint
    3126
    3127        if self._match(TokenType.MATCH_CONDITION):
    3128            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3129
    3130        if self._match(TokenType.ON):
    3131            kwargs["on"] = self._parse_assignment()
    3132        elif self._match(TokenType.USING):
    3133            kwargs["using"] = self._parse_wrapped_id_vars()
    3134        elif not isinstance(kwargs["this"], exp.Unnest) and not (
    3135            kind and kind.token_type == TokenType.CROSS
    3136        ):
    3137            index = self._index
    3138            joins: t.Optional[list] = list(self._parse_joins())
    3139
    3140            if joins and self._match(TokenType.ON):
    3141                kwargs["on"] = self._parse_assignment()
    3142            elif joins and self._match(TokenType.USING):
    3143                kwargs["using"] = self._parse_wrapped_id_vars()
    3144            else:
    3145                joins = None
    3146                self._retreat(index)
    3147
    3148            kwargs["this"].set("joins", joins if joins else None)
    3149
    3150        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3151        return self.expression(exp.Join, comments=comments, **kwargs)
    3152
    3153    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3154        this = self._parse_assignment()
    3155
    3156        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3157            return this
    3158
    3159        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3160            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3161
    3162        return this
    3163
    3164    def _parse_index_params(self) -> exp.IndexParameters:
    3165        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3166
    3167        if self._match(TokenType.L_PAREN, advance=False):
    3168            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3169        else:
    3170            columns = None
    3171
    3172        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3173        partition_by = self._parse_partition_by()
    3174        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3175        tablespace = (
    3176            self._parse_var(any_token=True)
    3177            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3178            else None
    3179        )
    3180        where = self._parse_where()
    3181
    3182        return self.expression(
    3183            exp.IndexParameters,
    3184            using=using,
    3185            columns=columns,
    3186            include=include,
    3187            partition_by=partition_by,
    3188            where=where,
    3189            with_storage=with_storage,
    3190            tablespace=tablespace,
    3191        )
    3192
    3193    def _parse_index(
    3194        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3195    ) -> t.Optional[exp.Index]:
    3196        if index or anonymous:
    3197            unique = None
    3198            primary = None
    3199            amp = None
    3200
    3201            self._match(TokenType.ON)
    3202            self._match(TokenType.TABLE)  # hive
    3203            table = self._parse_table_parts(schema=True)
    3204        else:
    3205            unique = self._match(TokenType.UNIQUE)
    3206            primary = self._match_text_seq("PRIMARY")
    3207            amp = self._match_text_seq("AMP")
    3208
    3209            if not self._match(TokenType.INDEX):
    3210                return None
    3211
    3212            index = self._parse_id_var()
    3213            table = None
    3214
    3215        params = self._parse_index_params()
    3216
    3217        return self.expression(
    3218            exp.Index,
    3219            this=index,
    3220            table=table,
    3221            unique=unique,
    3222            primary=primary,
    3223            amp=amp,
    3224            params=params,
    3225        )
    3226
    3227    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3228        hints: t.List[exp.Expression] = []
    3229        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3230            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3231            hints.append(
    3232                self.expression(
    3233                    exp.WithTableHint,
    3234                    expressions=self._parse_csv(
    3235                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3236                    ),
    3237                )
    3238            )
    3239            self._match_r_paren()
    3240        else:
    3241            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3242            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3243                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3244
    3245                self._match_texts(("INDEX", "KEY"))
    3246                if self._match(TokenType.FOR):
    3247                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3248
    3249                hint.set("expressions", self._parse_wrapped_id_vars())
    3250                hints.append(hint)
    3251
    3252        return hints or None
    3253
    3254    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3255        return (
    3256            (not schema and self._parse_function(optional_parens=False))
    3257            or self._parse_id_var(any_token=False)
    3258            or self._parse_string_as_identifier()
    3259            or self._parse_placeholder()
    3260        )
    3261
    3262    def _parse_table_parts(
    3263        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3264    ) -> exp.Table:
    3265        catalog = None
    3266        db = None
    3267        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3268
    3269        while self._match(TokenType.DOT):
    3270            if catalog:
    3271                # This allows nesting the table in arbitrarily many dot expressions if needed
    3272                table = self.expression(
    3273                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3274                )
    3275            else:
    3276                catalog = db
    3277                db = table
    3278                # "" used for tsql FROM a..b case
    3279                table = self._parse_table_part(schema=schema) or ""
    3280
    3281        if (
    3282            wildcard
    3283            and self._is_connected()
    3284            and (isinstance(table, exp.Identifier) or not table)
    3285            and self._match(TokenType.STAR)
    3286        ):
    3287            if isinstance(table, exp.Identifier):
    3288                table.args["this"] += "*"
    3289            else:
    3290                table = exp.Identifier(this="*")
    3291
    3292        # We bubble up comments from the Identifier to the Table
    3293        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3294
    3295        if is_db_reference:
    3296            catalog = db
    3297            db = table
    3298            table = None
    3299
    3300        if not table and not is_db_reference:
    3301            self.raise_error(f"Expected table name but got {self._curr}")
    3302        if not db and is_db_reference:
    3303            self.raise_error(f"Expected database name but got {self._curr}")
    3304
    3305        return self.expression(
    3306            exp.Table,
    3307            comments=comments,
    3308            this=table,
    3309            db=db,
    3310            catalog=catalog,
    3311            pivots=self._parse_pivots(),
    3312        )
    3313
    3314    def _parse_table(
    3315        self,
    3316        schema: bool = False,
    3317        joins: bool = False,
    3318        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3319        parse_bracket: bool = False,
    3320        is_db_reference: bool = False,
    3321        parse_partition: bool = False,
    3322    ) -> t.Optional[exp.Expression]:
    3323        lateral = self._parse_lateral()
    3324        if lateral:
    3325            return lateral
    3326
    3327        unnest = self._parse_unnest()
    3328        if unnest:
    3329            return unnest
    3330
    3331        values = self._parse_derived_table_values()
    3332        if values:
    3333            return values
    3334
    3335        subquery = self._parse_select(table=True)
    3336        if subquery:
    3337            if not subquery.args.get("pivots"):
    3338                subquery.set("pivots", self._parse_pivots())
    3339            return subquery
    3340
    3341        bracket = parse_bracket and self._parse_bracket(None)
    3342        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3343
    3344        only = self._match(TokenType.ONLY)
    3345
    3346        this = t.cast(
    3347            exp.Expression,
    3348            bracket
    3349            or self._parse_bracket(
    3350                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3351            ),
    3352        )
    3353
    3354        if only:
    3355            this.set("only", only)
    3356
    3357        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3358        self._match_text_seq("*")
    3359
    3360        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3361        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3362            this.set("partition", self._parse_partition())
    3363
    3364        if schema:
    3365            return self._parse_schema(this=this)
    3366
    3367        version = self._parse_version()
    3368
    3369        if version:
    3370            this.set("version", version)
    3371
    3372        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3373            table_sample = self._parse_table_sample()
    3374
    3375        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3376        if alias:
    3377            this.set("alias", alias)
    3378
    3379        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3380            return self.expression(
    3381                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3382            )
    3383
    3384        this.set("hints", self._parse_table_hints())
    3385
    3386        if not this.args.get("pivots"):
    3387            this.set("pivots", self._parse_pivots())
    3388
    3389        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3390            table_sample = self._parse_table_sample()
    3391
    3392        if table_sample:
    3393            table_sample.set("this", this)
    3394            this = table_sample
    3395
    3396        if joins:
    3397            for join in self._parse_joins():
    3398                this.append("joins", join)
    3399
    3400        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3401            this.set("ordinality", True)
    3402            this.set("alias", self._parse_table_alias())
    3403
    3404        return this
    3405
    3406    def _parse_version(self) -> t.Optional[exp.Version]:
    3407        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    3408            this = "TIMESTAMP"
    3409        elif self._match(TokenType.VERSION_SNAPSHOT):
    3410            this = "VERSION"
    3411        else:
    3412            return None
    3413
    3414        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    3415            kind = self._prev.text.upper()
    3416            start = self._parse_bitwise()
    3417            self._match_texts(("TO", "AND"))
    3418            end = self._parse_bitwise()
    3419            expression: t.Optional[exp.Expression] = self.expression(
    3420                exp.Tuple, expressions=[start, end]
    3421            )
    3422        elif self._match_text_seq("CONTAINED", "IN"):
    3423            kind = "CONTAINED IN"
    3424            expression = self.expression(
    3425                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    3426            )
    3427        elif self._match(TokenType.ALL):
    3428            kind = "ALL"
    3429            expression = None
    3430        else:
    3431            self._match_text_seq("AS", "OF")
    3432            kind = "AS OF"
    3433            expression = self._parse_type()
    3434
    3435        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    3436
    3437    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    3438        if not self._match(TokenType.UNNEST):
    3439            return None
    3440
    3441        expressions = self._parse_wrapped_csv(self._parse_equality)
    3442        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    3443
    3444        alias = self._parse_table_alias() if with_alias else None
    3445
    3446        if alias:
    3447            if self.dialect.UNNEST_COLUMN_ONLY:
    3448                if alias.args.get("columns"):
    3449                    self.raise_error("Unexpected extra column alias in unnest.")
    3450
    3451                alias.set("columns", [alias.this])
    3452                alias.set("this", None)
    3453
    3454            columns = alias.args.get("columns") or []
    3455            if offset and len(expressions) < len(columns):
    3456                offset = columns.pop()
    3457
    3458        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    3459            self._match(TokenType.ALIAS)
    3460            offset = self._parse_id_var(
    3461                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    3462            ) or exp.to_identifier("offset")
    3463
    3464        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    3465
    3466    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    3467        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    3468        if not is_derived and not self._match_text_seq("VALUES"):
    3469            return None
    3470
    3471        expressions = self._parse_csv(self._parse_value)
    3472        alias = self._parse_table_alias()
    3473
    3474        if is_derived:
    3475            self._match_r_paren()
    3476
    3477        return self.expression(
    3478            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    3479        )
    3480
    3481    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    3482        if not self._match(TokenType.TABLE_SAMPLE) and not (
    3483            as_modifier and self._match_text_seq("USING", "SAMPLE")
    3484        ):
    3485            return None
    3486
    3487        bucket_numerator = None
    3488        bucket_denominator = None
    3489        bucket_field = None
    3490        percent = None
    3491        size = None
    3492        seed = None
    3493
    3494        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    3495        matched_l_paren = self._match(TokenType.L_PAREN)
    3496
    3497        if self.TABLESAMPLE_CSV:
    3498            num = None
    3499            expressions = self._parse_csv(self._parse_primary)
    3500        else:
    3501            expressions = None
    3502            num = (
    3503                self._parse_factor()
    3504                if self._match(TokenType.NUMBER, advance=False)
    3505                else self._parse_primary() or self._parse_placeholder()
    3506            )
    3507
    3508        if self._match_text_seq("BUCKET"):
    3509            bucket_numerator = self._parse_number()
    3510            self._match_text_seq("OUT", "OF")
    3511            bucket_denominator = bucket_denominator = self._parse_number()
    3512            self._match(TokenType.ON)
    3513            bucket_field = self._parse_field()
    3514        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    3515            percent = num
    3516        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    3517            size = num
    3518        else:
    3519            percent = num
    3520
    3521        if matched_l_paren:
    3522            self._match_r_paren()
    3523
    3524        if self._match(TokenType.L_PAREN):
    3525            method = self._parse_var(upper=True)
    3526            seed = self._match(TokenType.COMMA) and self._parse_number()
    3527            self._match_r_paren()
    3528        elif self._match_texts(("SEED", "REPEATABLE")):
    3529            seed = self._parse_wrapped(self._parse_number)
    3530
    3531        if not method and self.DEFAULT_SAMPLING_METHOD:
    3532            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    3533
    3534        return self.expression(
    3535            exp.TableSample,
    3536            expressions=expressions,
    3537            method=method,
    3538            bucket_numerator=bucket_numerator,
    3539            bucket_denominator=bucket_denominator,
    3540            bucket_field=bucket_field,
    3541            percent=percent,
    3542            size=size,
    3543            seed=seed,
    3544        )
    3545
    3546    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    3547        return list(iter(self._parse_pivot, None)) or None
    3548
    3549    def _parse_joins(self) -> t.Iterator[exp.Join]:
    3550        return iter(self._parse_join, None)
    3551
    3552    # https://duckdb.org/docs/sql/statements/pivot
    3553    def _parse_simplified_pivot(self) -> exp.Pivot:
    3554        def _parse_on() -> t.Optional[exp.Expression]:
    3555            this = self._parse_bitwise()
    3556            return self._parse_in(this) if self._match(TokenType.IN) else this
    3557
    3558        this = self._parse_table()
    3559        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    3560        using = self._match(TokenType.USING) and self._parse_csv(
    3561            lambda: self._parse_alias(self._parse_function())
    3562        )
    3563        group = self._parse_group()
    3564        return self.expression(
    3565            exp.Pivot, this=this, expressions=expressions, using=using, group=group
    3566        )
    3567
    3568    def _parse_pivot_in(self) -> exp.In:
    3569        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    3570            this = self._parse_assignment()
    3571
    3572            self._match(TokenType.ALIAS)
    3573            alias = self._parse_field()
    3574            if alias:
    3575                return self.expression(exp.PivotAlias, this=this, alias=alias)
    3576
    3577            return this
    3578
    3579        value = self._parse_column()
    3580
    3581        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    3582            self.raise_error("Expecting IN (")
    3583
    3584        aliased_expressions = self._parse_csv(_parse_aliased_expression)
    3585
    3586        self._match_r_paren()
    3587        return self.expression(exp.In, this=value, expressions=aliased_expressions)
    3588
    3589    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    3590        index = self._index
    3591        include_nulls = None
    3592
    3593        if self._match(TokenType.PIVOT):
    3594            unpivot = False
    3595        elif self._match(TokenType.UNPIVOT):
    3596            unpivot = True
    3597
    3598            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    3599            if self._match_text_seq("INCLUDE", "NULLS"):
    3600                include_nulls = True
    3601            elif self._match_text_seq("EXCLUDE", "NULLS"):
    3602                include_nulls = False
    3603        else:
    3604            return None
    3605
    3606        expressions = []
    3607
    3608        if not self._match(TokenType.L_PAREN):
    3609            self._retreat(index)
    3610            return None
    3611
    3612        if unpivot:
    3613            expressions = self._parse_csv(self._parse_column)
    3614        else:
    3615            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    3616
    3617        if not expressions:
    3618            self.raise_error("Failed to parse PIVOT's aggregation list")
    3619
    3620        if not self._match(TokenType.FOR):
    3621            self.raise_error("Expecting FOR")
    3622
    3623        field = self._parse_pivot_in()
    3624
    3625        self._match_r_paren()
    3626
    3627        pivot = self.expression(
    3628            exp.Pivot,
    3629            expressions=expressions,
    3630            field=field,
    3631            unpivot=unpivot,
    3632            include_nulls=include_nulls,
    3633        )
    3634
    3635        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    3636            pivot.set("alias", self._parse_table_alias())
    3637
    3638        if not unpivot:
    3639            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    3640
    3641            columns: t.List[exp.Expression] = []
    3642            for fld in pivot.args["field"].expressions:
    3643                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    3644                for name in names:
    3645                    if self.PREFIXED_PIVOT_COLUMNS:
    3646                        name = f"{name}_{field_name}" if name else field_name
    3647                    else:
    3648                        name = f"{field_name}_{name}" if name else field_name
    3649
    3650                    columns.append(exp.to_identifier(name))
    3651
    3652            pivot.set("columns", columns)
    3653
    3654        return pivot
    3655
    3656    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    3657        return [agg.alias for agg in aggregations]
    3658
    3659    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    3660        if not skip_where_token and not self._match(TokenType.PREWHERE):
    3661            return None
    3662
    3663        return self.expression(
    3664            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    3665        )
    3666
    3667    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    3668        if not skip_where_token and not self._match(TokenType.WHERE):
    3669            return None
    3670
    3671        return self.expression(
    3672            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    3673        )
    3674
    3675    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    3676        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    3677            return None
    3678
    3679        elements: t.Dict[str, t.Any] = defaultdict(list)
    3680
    3681        if self._match(TokenType.ALL):
    3682            elements["all"] = True
    3683        elif self._match(TokenType.DISTINCT):
    3684            elements["all"] = False
    3685
    3686        while True:
    3687            expressions = self._parse_csv(
    3688                lambda: None
    3689                if self._match(TokenType.ROLLUP, advance=False)
    3690                else self._parse_assignment()
    3691            )
    3692            if expressions:
    3693                elements["expressions"].extend(expressions)
    3694
    3695            grouping_sets = self._parse_grouping_sets()
    3696            if grouping_sets:
    3697                elements["grouping_sets"].extend(grouping_sets)
    3698
    3699            rollup = None
    3700            cube = None
    3701            totals = None
    3702
    3703            index = self._index
    3704            with_ = self._match(TokenType.WITH)
    3705            if self._match(TokenType.ROLLUP):
    3706                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
    3707                elements["rollup"].extend(ensure_list(rollup))
    3708
    3709            if self._match(TokenType.CUBE):
    3710                cube = with_ or self._parse_wrapped_csv(self._parse_column)
    3711                elements["cube"].extend(ensure_list(cube))
    3712
    3713            if self._match_text_seq("TOTALS"):
    3714                totals = True
    3715                elements["totals"] = True  # type: ignore
    3716
    3717            if not (grouping_sets or rollup or cube or totals):
    3718                if with_:
    3719                    self._retreat(index)
    3720                break
    3721
    3722        return self.expression(exp.Group, **elements)  # type: ignore
    3723
    3724    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
    3725        if not self._match(TokenType.GROUPING_SETS):
    3726            return None
    3727
    3728        return self._parse_wrapped_csv(self._parse_grouping_set)
    3729
    3730    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    3731        if self._match(TokenType.L_PAREN):
    3732            grouping_set = self._parse_csv(self._parse_column)
    3733            self._match_r_paren()
    3734            return self.expression(exp.Tuple, expressions=grouping_set)
    3735
    3736        return self._parse_column()
    3737
    3738    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    3739        if not skip_having_token and not self._match(TokenType.HAVING):
    3740            return None
    3741        return self.expression(exp.Having, this=self._parse_assignment())
    3742
    3743    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    3744        if not self._match(TokenType.QUALIFY):
    3745            return None
    3746        return self.expression(exp.Qualify, this=self._parse_assignment())
    3747
    3748    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    3749        if skip_start_token:
    3750            start = None
    3751        elif self._match(TokenType.START_WITH):
    3752            start = self._parse_assignment()
    3753        else:
    3754            return None
    3755
    3756        self._match(TokenType.CONNECT_BY)
    3757        nocycle = self._match_text_seq("NOCYCLE")
    3758        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    3759            exp.Prior, this=self._parse_bitwise()
    3760        )
    3761        connect = self._parse_assignment()
    3762        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    3763
    3764        if not start and self._match(TokenType.START_WITH):
    3765            start = self._parse_assignment()
    3766
    3767        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    3768
    3769    def _parse_name_as_expression(self) -> exp.Alias:
    3770        return self.expression(
    3771            exp.Alias,
    3772            alias=self._parse_id_var(any_token=True),
    3773            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
    3774        )
    3775
    3776    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    3777        if self._match_text_seq("INTERPOLATE"):
    3778            return self._parse_wrapped_csv(self._parse_name_as_expression)
    3779        return None
    3780
    3781    def _parse_order(
    3782        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    3783    ) -> t.Optional[exp.Expression]:
    3784        siblings = None
    3785        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    3786            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    3787                return this
    3788
    3789            siblings = True
    3790
    3791        return self.expression(
    3792            exp.Order,
    3793            this=this,
    3794            expressions=self._parse_csv(self._parse_ordered),
    3795            interpolate=self._parse_interpolate(),
    3796            siblings=siblings,
    3797        )
    3798
    3799    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    3800        if not self._match(token):
    3801            return None
    3802        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    3803
    3804    def _parse_ordered(
    3805        self, parse_method: t.Optional[t.Callable] = None
    3806    ) -> t.Optional[exp.Ordered]:
    3807        this = parse_method() if parse_method else self._parse_assignment()
    3808        if not this:
    3809            return None
    3810
    3811        asc = self._match(TokenType.ASC)
    3812        desc = self._match(TokenType.DESC) or (asc and False)
    3813
    3814        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    3815        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    3816
    3817        nulls_first = is_nulls_first or False
    3818        explicitly_null_ordered = is_nulls_first or is_nulls_last
    3819
    3820        if (
    3821            not explicitly_null_ordered
    3822            and (
    3823                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    3824                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    3825            )
    3826            and self.dialect.NULL_ORDERING != "nulls_are_last"
    3827        ):
    3828            nulls_first = True
    3829
    3830        if self._match_text_seq("WITH", "FILL"):
    3831            with_fill = self.expression(
    3832                exp.WithFill,
    3833                **{  # type: ignore
    3834                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    3835                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    3836                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    3837                },
    3838            )
    3839        else:
    3840            with_fill = None
    3841
    3842        return self.expression(
    3843            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    3844        )
    3845
    3846    def _parse_limit(
    3847        self,
    3848        this: t.Optional[exp.Expression] = None,
    3849        top: bool = False,
    3850        skip_limit_token: bool = False,
    3851    ) -> t.Optional[exp.Expression]:
    3852        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    3853            comments = self._prev_comments
    3854            if top:
    3855                limit_paren = self._match(TokenType.L_PAREN)
    3856                expression = self._parse_term() if limit_paren else self._parse_number()
    3857
    3858                if limit_paren:
    3859                    self._match_r_paren()
    3860            else:
    3861                expression = self._parse_term()
    3862
    3863            if self._match(TokenType.COMMA):
    3864                offset = expression
    3865                expression = self._parse_term()
    3866            else:
    3867                offset = None
    3868
    3869            limit_exp = self.expression(
    3870                exp.Limit,
    3871                this=this,
    3872                expression=expression,
    3873                offset=offset,
    3874                comments=comments,
    3875                expressions=self._parse_limit_by(),
    3876            )
    3877
    3878            return limit_exp
    3879
    3880        if self._match(TokenType.FETCH):
    3881            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    3882            direction = self._prev.text.upper() if direction else "FIRST"
    3883
    3884            count = self._parse_field(tokens=self.FETCH_TOKENS)
    3885            percent = self._match(TokenType.PERCENT)
    3886
    3887            self._match_set((TokenType.ROW, TokenType.ROWS))
    3888
    3889            only = self._match_text_seq("ONLY")
    3890            with_ties = self._match_text_seq("WITH", "TIES")
    3891
    3892            if only and with_ties:
    3893                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
    3894
    3895            return self.expression(
    3896                exp.Fetch,
    3897                direction=direction,
    3898                count=count,
    3899                percent=percent,
    3900                with_ties=with_ties,
    3901            )
    3902
    3903        return this
    3904
    3905    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    3906        if not self._match(TokenType.OFFSET):
    3907            return this
    3908
    3909        count = self._parse_term()
    3910        self._match_set((TokenType.ROW, TokenType.ROWS))
    3911
    3912        return self.expression(
    3913            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    3914        )
    3915
    3916    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    3917        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    3918
    3919    def _parse_locks(self) -> t.List[exp.Lock]:
    3920        locks = []
    3921        while True:
    3922            if self._match_text_seq("FOR", "UPDATE"):
    3923                update = True
    3924            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    3925                "LOCK", "IN", "SHARE", "MODE"
    3926            ):
    3927                update = False
    3928            else:
    3929                break
    3930
    3931            expressions = None
    3932            if self._match_text_seq("OF"):
    3933                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    3934
    3935            wait: t.Optional[bool | exp.Expression] = None
    3936            if self._match_text_seq("NOWAIT"):
    3937                wait = True
    3938            elif self._match_text_seq("WAIT"):
    3939                wait = self._parse_primary()
    3940            elif self._match_text_seq("SKIP", "LOCKED"):
    3941                wait = False
    3942
    3943            locks.append(
    3944                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    3945            )
    3946
    3947        return locks
    3948
    3949    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3950        while this and self._match_set(self.SET_OPERATIONS):
    3951            token_type = self._prev.token_type
    3952
    3953            if token_type == TokenType.UNION:
    3954                operation = exp.Union
    3955            elif token_type == TokenType.EXCEPT:
    3956                operation = exp.Except
    3957            else:
    3958                operation = exp.Intersect
    3959
    3960            comments = self._prev.comments
    3961            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
    3962            by_name = self._match_text_seq("BY", "NAME")
    3963            expression = self._parse_select(nested=True, parse_set_operation=False)
    3964
    3965            this = self.expression(
    3966                operation,
    3967                comments=comments,
    3968                this=this,
    3969                distinct=distinct,
    3970                by_name=by_name,
    3971                expression=expression,
    3972            )
    3973
    3974        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
    3975            expression = this.expression
    3976
    3977            if expression:
    3978                for arg in self.UNION_MODIFIERS:
    3979                    expr = expression.args.get(arg)
    3980                    if expr:
    3981                        this.set(arg, expr.pop())
    3982
    3983        return this
    3984
    3985    def _parse_expression(self) -> t.Optional[exp.Expression]:
    3986        return self._parse_alias(self._parse_assignment())
    3987
    3988    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    3989        this = self._parse_disjunction()
    3990
    3991        while self._match_set(self.ASSIGNMENT):
    3992            this = self.expression(
    3993                self.ASSIGNMENT[self._prev.token_type],
    3994                this=this,
    3995                comments=self._prev_comments,
    3996                expression=self._parse_assignment(),
    3997            )
    3998
    3999        return this
    4000
    4001    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4002        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4003
    4004    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4005        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4006
    4007    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4008        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4009
    4010    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4011        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4012
    4013    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4014        this = this or self._parse_bitwise()
    4015        negate = self._match(TokenType.NOT)
    4016
    4017        if self._match_set(self.RANGE_PARSERS):
    4018            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4019            if not expression:
    4020                return this
    4021
    4022            this = expression
    4023        elif self._match(TokenType.ISNULL):
    4024            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4025
    4026        # Postgres supports ISNULL and NOTNULL for conditions.
    4027        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4028        if self._match(TokenType.NOTNULL):
    4029            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4030            this = self.expression(exp.Not, this=this)
    4031
    4032        if negate:
    4033            this = self.expression(exp.Not, this=this)
    4034
    4035        if self._match(TokenType.IS):
    4036            this = self._parse_is(this)
    4037
    4038        return this
    4039
    4040    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4041        index = self._index - 1
    4042        negate = self._match(TokenType.NOT)
    4043
    4044        if self._match_text_seq("DISTINCT", "FROM"):
    4045            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4046            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4047
    4048        expression = self._parse_null() or self._parse_boolean()
    4049        if not expression:
    4050            self._retreat(index)
    4051            return None
    4052
    4053        this = self.expression(exp.Is, this=this, expression=expression)
    4054        return self.expression(exp.Not, this=this) if negate else this
    4055
    4056    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4057        unnest = self._parse_unnest(with_alias=False)
    4058        if unnest:
    4059            this = self.expression(exp.In, this=this, unnest=unnest)
    4060        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4061            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4062            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4063
    4064            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4065                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4066            else:
    4067                this = self.expression(exp.In, this=this, expressions=expressions)
    4068
    4069            if matched_l_paren:
    4070                self._match_r_paren(this)
    4071            elif not self._match(TokenType.R_BRACKET, expression=this):
    4072                self.raise_error("Expecting ]")
    4073        else:
    4074            this = self.expression(exp.In, this=this, field=self._parse_field())
    4075
    4076        return this
    4077
    4078    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4079        low = self._parse_bitwise()
    4080        self._match(TokenType.AND)
    4081        high = self._parse_bitwise()
    4082        return self.expression(exp.Between, this=this, low=low, high=high)
    4083
    4084    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4085        if not self._match(TokenType.ESCAPE):
    4086            return this
    4087        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4088
    4089    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4090        index = self._index
    4091
    4092        if not self._match(TokenType.INTERVAL) and match_interval:
    4093            return None
    4094
    4095        if self._match(TokenType.STRING, advance=False):
    4096            this = self._parse_primary()
    4097        else:
    4098            this = self._parse_term()
    4099
    4100        if not this or (
    4101            isinstance(this, exp.Column)
    4102            and not this.table
    4103            and not this.this.quoted
    4104            and this.name.upper() == "IS"
    4105        ):
    4106            self._retreat(index)
    4107            return None
    4108
    4109        unit = self._parse_function() or (
    4110            not self._match(TokenType.ALIAS, advance=False)
    4111            and self._parse_var(any_token=True, upper=True)
    4112        )
    4113
    4114        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4115        # each INTERVAL expression into this canonical form so it's easy to transpile
    4116        if this and this.is_number:
    4117            this = exp.Literal.string(this.name)
    4118        elif this and this.is_string:
    4119            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4120            if len(parts) == 1:
    4121                if unit:
    4122                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4123                    self._retreat(self._index - 1)
    4124
    4125                this = exp.Literal.string(parts[0][0])
    4126                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4127
    4128        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4129            unit = self.expression(
    4130                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4131            )
    4132
    4133        interval = self.expression(exp.Interval, this=this, unit=unit)
    4134
    4135        index = self._index
    4136        self._match(TokenType.PLUS)
    4137
    4138        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4139        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4140            return self.expression(
    4141                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4142            )
    4143
    4144        self._retreat(index)
    4145        return interval
    4146
    4147    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4148        this = self._parse_term()
    4149
    4150        while True:
    4151            if self._match_set(self.BITWISE):
    4152                this = self.expression(
    4153                    self.BITWISE[self._prev.token_type],
    4154                    this=this,
    4155                    expression=self._parse_term(),
    4156                )
    4157            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4158                this = self.expression(
    4159                    exp.DPipe,
    4160                    this=this,
    4161                    expression=self._parse_term(),
    4162                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4163                )
    4164            elif self._match(TokenType.DQMARK):
    4165                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
    4166            elif self._match_pair(TokenType.LT, TokenType.LT):
    4167                this = self.expression(
    4168                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4169                )
    4170            elif self._match_pair(TokenType.GT, TokenType.GT):
    4171                this = self.expression(
    4172                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4173                )
    4174            else:
    4175                break
    4176
    4177        return this
    4178
    4179    def _parse_term(self) -> t.Optional[exp.Expression]:
    4180        return self._parse_tokens(self._parse_factor, self.TERM)
    4181
    4182    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4183        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4184        this = parse_method()
    4185
    4186        while self._match_set(self.FACTOR):
    4187            klass = self.FACTOR[self._prev.token_type]
    4188            comments = self._prev_comments
    4189            expression = parse_method()
    4190
    4191            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4192                self._retreat(self._index - 1)
    4193                return this
    4194
    4195            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4196
    4197            if isinstance(this, exp.Div):
    4198                this.args["typed"] = self.dialect.TYPED_DIVISION
    4199                this.args["safe"] = self.dialect.SAFE_DIVISION
    4200
    4201        return this
    4202
    4203    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    4204        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    4205
    4206    def _parse_unary(self) -> t.Optional[exp.Expression]:
    4207        if self._match_set(self.UNARY_PARSERS):
    4208            return self.UNARY_PARSERS[self._prev.token_type](self)
    4209        return self._parse_at_time_zone(self._parse_type())
    4210
    4211    def _parse_type(
    4212        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    4213    ) -> t.Optional[exp.Expression]:
    4214        interval = parse_interval and self._parse_interval()
    4215        if interval:
    4216            return interval
    4217
    4218        index = self._index
    4219        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    4220
    4221        if data_type:
    4222            index2 = self._index
    4223            this = self._parse_primary()
    4224
    4225            if isinstance(this, exp.Literal):
    4226                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    4227                if parser:
    4228                    return parser(self, this, data_type)
    4229
    4230                return self.expression(exp.Cast, this=this, to=data_type)
    4231
    4232            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    4233            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    4234            #
    4235            # If the index difference here is greater than 1, that means the parser itself must have
    4236            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    4237            #
    4238            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    4239            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    4240            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    4241            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    4242            #
    4243            # In these cases, we don't really want to return the converted type, but instead retreat
    4244            # and try to parse a Column or Identifier in the section below.
    4245            if data_type.expressions and index2 - index > 1:
    4246                self._retreat(index2)
    4247                return self._parse_column_ops(data_type)
    4248
    4249            self._retreat(index)
    4250
    4251        if fallback_to_identifier:
    4252            return self._parse_id_var()
    4253
    4254        this = self._parse_column()
    4255        return this and self._parse_column_ops(this)
    4256
    4257    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    4258        this = self._parse_type()
    4259        if not this:
    4260            return None
    4261
    4262        if isinstance(this, exp.Column) and not this.table:
    4263            this = exp.var(this.name.upper())
    4264
    4265        return self.expression(
    4266            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    4267        )
    4268
    4269    def _parse_types(
    4270        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    4271    ) -> t.Optional[exp.Expression]:
    4272        index = self._index
    4273
    4274        this: t.Optional[exp.Expression] = None
    4275        prefix = self._match_text_seq("SYSUDTLIB", ".")
    4276
    4277        if not self._match_set(self.TYPE_TOKENS):
    4278            identifier = allow_identifiers and self._parse_id_var(
    4279                any_token=False, tokens=(TokenType.VAR,)
    4280            )
    4281            if identifier:
    4282                tokens = self.dialect.tokenize(identifier.name)
    4283
    4284                if len(tokens) != 1:
    4285                    self.raise_error("Unexpected identifier", self._prev)
    4286
    4287                if tokens[0].token_type in self.TYPE_TOKENS:
    4288                    self._prev = tokens[0]
    4289                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    4290                    type_name = identifier.name
    4291
    4292                    while self._match(TokenType.DOT):
    4293                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    4294
    4295                    this = exp.DataType.build(type_name, udt=True)
    4296                else:
    4297                    self._retreat(self._index - 1)
    4298                    return None
    4299            else:
    4300                return None
    4301
    4302        type_token = self._prev.token_type
    4303
    4304        if type_token == TokenType.PSEUDO_TYPE:
    4305            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    4306
    4307        if type_token == TokenType.OBJECT_IDENTIFIER:
    4308            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    4309
    4310        # https://materialize.com/docs/sql/types/map/
    4311        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    4312            key_type = self._parse_types(
    4313                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4314            )
    4315            if not self._match(TokenType.FARROW):
    4316                self._retreat(index)
    4317                return None
    4318
    4319            value_type = self._parse_types(
    4320                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4321            )
    4322            if not self._match(TokenType.R_BRACKET):
    4323                self._retreat(index)
    4324                return None
    4325
    4326            return exp.DataType(
    4327                this=exp.DataType.Type.MAP,
    4328                expressions=[key_type, value_type],
    4329                nested=True,
    4330                prefix=prefix,
    4331            )
    4332
    4333        nested = type_token in self.NESTED_TYPE_TOKENS
    4334        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    4335        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    4336        expressions = None
    4337        maybe_func = False
    4338
    4339        if self._match(TokenType.L_PAREN):
    4340            if is_struct:
    4341                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    4342            elif nested:
    4343                expressions = self._parse_csv(
    4344                    lambda: self._parse_types(
    4345                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4346                    )
    4347                )
    4348            elif type_token in self.ENUM_TYPE_TOKENS:
    4349                expressions = self._parse_csv(self._parse_equality)
    4350            elif is_aggregate:
    4351                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    4352                    any_token=False, tokens=(TokenType.VAR,)
    4353                )
    4354                if not func_or_ident or not self._match(TokenType.COMMA):
    4355                    return None
    4356                expressions = self._parse_csv(
    4357                    lambda: self._parse_types(
    4358                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4359                    )
    4360                )
    4361                expressions.insert(0, func_or_ident)
    4362            else:
    4363                expressions = self._parse_csv(self._parse_type_size)
    4364
    4365            if not expressions or not self._match(TokenType.R_PAREN):
    4366                self._retreat(index)
    4367                return None
    4368
    4369            maybe_func = True
    4370
    4371        values: t.Optional[t.List[exp.Expression]] = None
    4372
    4373        if nested and self._match(TokenType.LT):
    4374            if is_struct:
    4375                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    4376            else:
    4377                expressions = self._parse_csv(
    4378                    lambda: self._parse_types(
    4379                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4380                    )
    4381                )
    4382
    4383            if not self._match(TokenType.GT):
    4384                self.raise_error("Expecting >")
    4385
    4386            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    4387                values = self._parse_csv(self._parse_assignment)
    4388                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    4389
    4390        if type_token in self.TIMESTAMPS:
    4391            if self._match_text_seq("WITH", "TIME", "ZONE"):
    4392                maybe_func = False
    4393                tz_type = (
    4394                    exp.DataType.Type.TIMETZ
    4395                    if type_token in self.TIMES
    4396                    else exp.DataType.Type.TIMESTAMPTZ
    4397                )
    4398                this = exp.DataType(this=tz_type, expressions=expressions)
    4399            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    4400                maybe_func = False
    4401                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    4402            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    4403                maybe_func = False
    4404        elif type_token == TokenType.INTERVAL:
    4405            unit = self._parse_var(upper=True)
    4406            if unit:
    4407                if self._match_text_seq("TO"):
    4408                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    4409
    4410                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    4411            else:
    4412                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    4413
    4414        if maybe_func and check_func:
    4415            index2 = self._index
    4416            peek = self._parse_string()
    4417
    4418            if not peek:
    4419                self._retreat(index)
    4420                return None
    4421
    4422            self._retreat(index2)
    4423
    4424        if not this:
    4425            if self._match_text_seq("UNSIGNED"):
    4426                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    4427                if not unsigned_type_token:
    4428                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    4429
    4430                type_token = unsigned_type_token or type_token
    4431
    4432            this = exp.DataType(
    4433                this=exp.DataType.Type[type_token.value],
    4434                expressions=expressions,
    4435                nested=nested,
    4436                values=values,
    4437                prefix=prefix,
    4438            )
    4439        elif expressions:
    4440            this.set("expressions", expressions)
    4441
    4442        # https://materialize.com/docs/sql/types/list/#type-name
    4443        while self._match(TokenType.LIST):
    4444            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    4445
    4446        index = self._index
    4447
    4448        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    4449        matched_array = self._match(TokenType.ARRAY)
    4450
    4451        while self._curr:
    4452            matched_l_bracket = self._match(TokenType.L_BRACKET)
    4453            if not matched_l_bracket and not matched_array:
    4454                break
    4455
    4456            matched_array = False
    4457            values = self._parse_csv(self._parse_assignment) or None
    4458            if values and not schema:
    4459                self._retreat(index)
    4460                break
    4461
    4462            this = exp.DataType(
    4463                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    4464            )
    4465            self._match(TokenType.R_BRACKET)
    4466
    4467        if self.TYPE_CONVERTER and isinstance(this.this, exp.DataType.Type):
    4468            converter = self.TYPE_CONVERTER.get(this.this)
    4469            if converter:
    4470                this = converter(t.cast(exp.DataType, this))
    4471
    4472        return this
    4473
    4474    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    4475        index = self._index
    4476        this = (
    4477            self._parse_type(parse_interval=False, fallback_to_identifier=True)
    4478            or self._parse_id_var()
    4479        )
    4480        self._match(TokenType.COLON)
    4481
    4482        if (
    4483            type_required
    4484            and not isinstance(this, exp.DataType)
    4485            and not self._match_set(self.TYPE_TOKENS, advance=False)
    4486        ):
    4487            self._retreat(index)
    4488            return self._parse_types()
    4489
    4490        return self._parse_column_def(this)
    4491
    4492    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4493        if not self._match_text_seq("AT", "TIME", "ZONE"):
    4494            return this
    4495        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    4496
    4497    def _parse_column(self) -> t.Optional[exp.Expression]:
    4498        this = self._parse_column_reference()
    4499        return self._parse_column_ops(this) if this else self._parse_bracket(this)
    4500
    4501    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    4502        this = self._parse_field()
    4503        if (
    4504            not this
    4505            and self._match(TokenType.VALUES, advance=False)
    4506            and self.VALUES_FOLLOWED_BY_PAREN
    4507            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    4508        ):
    4509            this = self._parse_id_var()
    4510
    4511        if isinstance(this, exp.Identifier):
    4512            # We bubble up comments from the Identifier to the Column
    4513            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    4514
    4515        return this
    4516
    4517    def _parse_colon_as_json_extract(
    4518        self, this: t.Optional[exp.Expression]
    4519    ) -> t.Optional[exp.Expression]:
    4520        casts = []
    4521        json_path = []
    4522
    4523        while self._match(TokenType.COLON):
    4524            start_index = self._index
    4525            path = self._parse_column_ops(self._parse_field(any_token=True))
    4526
    4527            # The cast :: operator has a lower precedence than the extraction operator :, so
    4528            # we rearrange the AST appropriately to avoid casting the JSON path
    4529            while isinstance(path, exp.Cast):
    4530                casts.append(path.to)
    4531                path = path.this
    4532
    4533            if casts:
    4534                dcolon_offset = next(
    4535                    i
    4536                    for i, t in enumerate(self._tokens[start_index:])
    4537                    if t.token_type == TokenType.DCOLON
    4538                )
    4539                end_token = self._tokens[start_index + dcolon_offset - 1]
    4540            else:
    4541                end_token = self._prev
    4542
    4543            if path:
    4544                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    4545
    4546        if json_path:
    4547            this = self.expression(
    4548                exp.JSONExtract,
    4549                this=this,
    4550                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
    4551            )
    4552
    4553            while casts:
    4554                this = self.expression(exp.Cast, this=this, to=casts.pop())
    4555
    4556        return this
    4557
    4558    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4559        this = self._parse_bracket(this)
    4560
    4561        while self._match_set(self.COLUMN_OPERATORS):
    4562            op_token = self._prev.token_type
    4563            op = self.COLUMN_OPERATORS.get(op_token)
    4564
    4565            if op_token == TokenType.DCOLON:
    4566                field = self._parse_types()
    4567                if not field:
    4568                    self.raise_error("Expected type")
    4569            elif op and self._curr:
    4570                field = self._parse_column_reference()
    4571            else:
    4572                field = self._parse_field(any_token=True, anonymous_func=True)
    4573
    4574            if isinstance(field, exp.Func) and this:
    4575                # bigquery allows function calls like x.y.count(...)
    4576                # SAFE.SUBSTR(...)
    4577                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    4578                this = exp.replace_tree(
    4579                    this,
    4580                    lambda n: (
    4581                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    4582                        if n.table
    4583                        else n.this
    4584                    )
    4585                    if isinstance(n, exp.Column)
    4586                    else n,
    4587                )
    4588
    4589            if op:
    4590                this = op(self, this, field)
    4591            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    4592                this = self.expression(
    4593                    exp.Column,
    4594                    this=field,
    4595                    table=this.this,
    4596                    db=this.args.get("table"),
    4597                    catalog=this.args.get("db"),
    4598                )
    4599            else:
    4600                this = self.expression(exp.Dot, this=this, expression=field)
    4601
    4602            this = self._parse_bracket(this)
    4603
    4604        return self._parse_colon_as_json_extract(this) if self.COLON_IS_JSON_EXTRACT else this
    4605
    4606    def _parse_primary(self) -> t.Optional[exp.Expression]:
    4607        if self._match_set(self.PRIMARY_PARSERS):
    4608            token_type = self._prev.token_type
    4609            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    4610
    4611            if token_type == TokenType.STRING:
    4612                expressions = [primary]
    4613                while self._match(TokenType.STRING):
    4614                    expressions.append(exp.Literal.string(self._prev.text))
    4615
    4616                if len(expressions) > 1:
    4617                    return self.expression(exp.Concat, expressions=expressions)
    4618
    4619            return primary
    4620
    4621        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    4622            return exp.Literal.number(f"0.{self._prev.text}")
    4623
    4624        if self._match(TokenType.L_PAREN):
    4625            comments = self._prev_comments
    4626            query = self._parse_select()
    4627
    4628            if query:
    4629                expressions = [query]
    4630            else:
    4631                expressions = self._parse_expressions()
    4632
    4633            this = self._parse_query_modifiers(seq_get(expressions, 0))
    4634
    4635            if not this and self._match(TokenType.R_PAREN, advance=False):
    4636                this = self.expression(exp.Tuple)
    4637            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    4638                this = self._parse_subquery(this=this, parse_alias=False)
    4639            elif isinstance(this, exp.Subquery):
    4640                this = self._parse_subquery(
    4641                    this=self._parse_set_operations(this), parse_alias=False
    4642                )
    4643            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    4644                this = self.expression(exp.Tuple, expressions=expressions)
    4645            else:
    4646                this = self.expression(exp.Paren, this=this)
    4647
    4648            if this:
    4649                this.add_comments(comments)
    4650
    4651            self._match_r_paren(expression=this)
    4652            return this
    4653
    4654        return None
    4655
    4656    def _parse_field(
    4657        self,
    4658        any_token: bool = False,
    4659        tokens: t.Optional[t.Collection[TokenType]] = None,
    4660        anonymous_func: bool = False,
    4661    ) -> t.Optional[exp.Expression]:
    4662        if anonymous_func:
    4663            field = (
    4664                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    4665                or self._parse_primary()
    4666            )
    4667        else:
    4668            field = self._parse_primary() or self._parse_function(
    4669                anonymous=anonymous_func, any_token=any_token
    4670            )
    4671        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    4672
    4673    def _parse_function(
    4674        self,
    4675        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4676        anonymous: bool = False,
    4677        optional_parens: bool = True,
    4678        any_token: bool = False,
    4679    ) -> t.Optional[exp.Expression]:
    4680        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    4681        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    4682        fn_syntax = False
    4683        if (
    4684            self._match(TokenType.L_BRACE, advance=False)
    4685            and self._next
    4686            and self._next.text.upper() == "FN"
    4687        ):
    4688            self._advance(2)
    4689            fn_syntax = True
    4690
    4691        func = self._parse_function_call(
    4692            functions=functions,
    4693            anonymous=anonymous,
    4694            optional_parens=optional_parens,
    4695            any_token=any_token,
    4696        )
    4697
    4698        if fn_syntax:
    4699            self._match(TokenType.R_BRACE)
    4700
    4701        return func
    4702
    4703    def _parse_function_call(
    4704        self,
    4705        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4706        anonymous: bool = False,
    4707        optional_parens: bool = True,
    4708        any_token: bool = False,
    4709    ) -> t.Optional[exp.Expression]:
    4710        if not self._curr:
    4711            return None
    4712
    4713        comments = self._curr.comments
    4714        token_type = self._curr.token_type
    4715        this = self._curr.text
    4716        upper = this.upper()
    4717
    4718        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    4719        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    4720            self._advance()
    4721            return self._parse_window(parser(self))
    4722
    4723        if not self._next or self._next.token_type != TokenType.L_PAREN:
    4724            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    4725                self._advance()
    4726                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    4727
    4728            return None
    4729
    4730        if any_token:
    4731            if token_type in self.RESERVED_TOKENS:
    4732                return None
    4733        elif token_type not in self.FUNC_TOKENS:
    4734            return None
    4735
    4736        self._advance(2)
    4737
    4738        parser = self.FUNCTION_PARSERS.get(upper)
    4739        if parser and not anonymous:
    4740            this = parser(self)
    4741        else:
    4742            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    4743
    4744            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    4745                this = self.expression(subquery_predicate, this=self._parse_select())
    4746                self._match_r_paren()
    4747                return this
    4748
    4749            if functions is None:
    4750                functions = self.FUNCTIONS
    4751
    4752            function = functions.get(upper)
    4753
    4754            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    4755            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    4756
    4757            if alias:
    4758                args = self._kv_to_prop_eq(args)
    4759
    4760            if function and not anonymous:
    4761                if "dialect" in function.__code__.co_varnames:
    4762                    func = function(args, dialect=self.dialect)
    4763                else:
    4764                    func = function(args)
    4765
    4766                func = self.validate_expression(func, args)
    4767                if not self.dialect.NORMALIZE_FUNCTIONS:
    4768                    func.meta["name"] = this
    4769
    4770                this = func
    4771            else:
    4772                if token_type == TokenType.IDENTIFIER:
    4773                    this = exp.Identifier(this=this, quoted=True)
    4774                this = self.expression(exp.Anonymous, this=this, expressions=args)
    4775
    4776        if isinstance(this, exp.Expression):
    4777            this.add_comments(comments)
    4778
    4779        self._match_r_paren(this)
    4780        return self._parse_window(this)
    4781
    4782    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    4783        transformed = []
    4784
    4785        for e in expressions:
    4786            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    4787                if isinstance(e, exp.Alias):
    4788                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    4789
    4790                if not isinstance(e, exp.PropertyEQ):
    4791                    e = self.expression(
    4792                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    4793                    )
    4794
    4795                if isinstance(e.this, exp.Column):
    4796                    e.this.replace(e.this.this)
    4797
    4798            transformed.append(e)
    4799
    4800        return transformed
    4801
    4802    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    4803        return self._parse_column_def(self._parse_id_var())
    4804
    4805    def _parse_user_defined_function(
    4806        self, kind: t.Optional[TokenType] = None
    4807    ) -> t.Optional[exp.Expression]:
    4808        this = self._parse_id_var()
    4809
    4810        while self._match(TokenType.DOT):
    4811            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    4812
    4813        if not self._match(TokenType.L_PAREN):
    4814            return this
    4815
    4816        expressions = self._parse_csv(self._parse_function_parameter)
    4817        self._match_r_paren()
    4818        return self.expression(
    4819            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    4820        )
    4821
    4822    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    4823        literal = self._parse_primary()
    4824        if literal:
    4825            return self.expression(exp.Introducer, this=token.text, expression=literal)
    4826
    4827        return self.expression(exp.Identifier, this=token.text)
    4828
    4829    def _parse_session_parameter(self) -> exp.SessionParameter:
    4830        kind = None
    4831        this = self._parse_id_var() or self._parse_primary()
    4832
    4833        if this and self._match(TokenType.DOT):
    4834            kind = this.name
    4835            this = self._parse_var() or self._parse_primary()
    4836
    4837        return self.expression(exp.SessionParameter, this=this, kind=kind)
    4838
    4839    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    4840        return self._parse_id_var()
    4841
    4842    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4843        index = self._index
    4844
    4845        if self._match(TokenType.L_PAREN):
    4846            expressions = t.cast(
    4847                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    4848            )
    4849
    4850            if not self._match(TokenType.R_PAREN):
    4851                self._retreat(index)
    4852        else:
    4853            expressions = [self._parse_lambda_arg()]
    4854
    4855        if self._match_set(self.LAMBDAS):
    4856            return self.LAMBDAS[self._prev.token_type](self, expressions)
    4857
    4858        self._retreat(index)
    4859
    4860        this: t.Optional[exp.Expression]
    4861
    4862        if self._match(TokenType.DISTINCT):
    4863            this = self.expression(
    4864                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    4865            )
    4866        else:
    4867            this = self._parse_select_or_expression(alias=alias)
    4868
    4869        return self._parse_limit(
    4870            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    4871        )
    4872
    4873    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4874        index = self._index
    4875        if not self._match(TokenType.L_PAREN):
    4876            return this
    4877
    4878        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    4879        # expr can be of both types
    4880        if self._match_set(self.SELECT_START_TOKENS):
    4881            self._retreat(index)
    4882            return this
    4883        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    4884        self._match_r_paren()
    4885        return self.expression(exp.Schema, this=this, expressions=args)
    4886
    4887    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    4888        return self._parse_column_def(self._parse_field(any_token=True))
    4889
    4890    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4891        # column defs are not really columns, they're identifiers
    4892        if isinstance(this, exp.Column):
    4893            this = this.this
    4894
    4895        kind = self._parse_types(schema=True)
    4896
    4897        if self._match_text_seq("FOR", "ORDINALITY"):
    4898            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    4899
    4900        constraints: t.List[exp.Expression] = []
    4901
    4902        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    4903            ("ALIAS", "MATERIALIZED")
    4904        ):
    4905            persisted = self._prev.text.upper() == "MATERIALIZED"
    4906            constraints.append(
    4907                self.expression(
    4908                    exp.ComputedColumnConstraint,
    4909                    this=self._parse_assignment(),
    4910                    persisted=persisted or self._match_text_seq("PERSISTED"),
    4911                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    4912                )
    4913            )
    4914        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
    4915            self._match(TokenType.ALIAS)
    4916            constraints.append(
    4917                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
    4918            )
    4919
    4920        while True:
    4921            constraint = self._parse_column_constraint()
    4922            if not constraint:
    4923                break
    4924            constraints.append(constraint)
    4925
    4926        if not kind and not constraints:
    4927            return this
    4928
    4929        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    4930
    4931    def _parse_auto_increment(
    4932        self,
    4933    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    4934        start = None
    4935        increment = None
    4936
    4937        if self._match(TokenType.L_PAREN, advance=False):
    4938            args = self._parse_wrapped_csv(self._parse_bitwise)
    4939            start = seq_get(args, 0)
    4940            increment = seq_get(args, 1)
    4941        elif self._match_text_seq("START"):
    4942            start = self._parse_bitwise()
    4943            self._match_text_seq("INCREMENT")
    4944            increment = self._parse_bitwise()
    4945
    4946        if start and increment:
    4947            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    4948
    4949        return exp.AutoIncrementColumnConstraint()
    4950
    4951    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    4952        if not self._match_text_seq("REFRESH"):
    4953            self._retreat(self._index - 1)
    4954            return None
    4955        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    4956
    4957    def _parse_compress(self) -> exp.CompressColumnConstraint:
    4958        if self._match(TokenType.L_PAREN, advance=False):
    4959            return self.expression(
    4960                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    4961            )
    4962
    4963        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    4964
    4965    def _parse_generated_as_identity(
    4966        self,
    4967    ) -> (
    4968        exp.GeneratedAsIdentityColumnConstraint
    4969        | exp.ComputedColumnConstraint
    4970        | exp.GeneratedAsRowColumnConstraint
    4971    ):
    4972        if self._match_text_seq("BY", "DEFAULT"):
    4973            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    4974            this = self.expression(
    4975                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    4976            )
    4977        else:
    4978            self._match_text_seq("ALWAYS")
    4979            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    4980
    4981        self._match(TokenType.ALIAS)
    4982
    4983        if self._match_text_seq("ROW"):
    4984            start = self._match_text_seq("START")
    4985            if not start:
    4986                self._match(TokenType.END)
    4987            hidden = self._match_text_seq("HIDDEN")
    4988            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    4989
    4990        identity = self._match_text_seq("IDENTITY")
    4991
    4992        if self._match(TokenType.L_PAREN):
    4993            if self._match(TokenType.START_WITH):
    4994                this.set("start", self._parse_bitwise())
    4995            if self._match_text_seq("INCREMENT", "BY"):
    4996                this.set("increment", self._parse_bitwise())
    4997            if self._match_text_seq("MINVALUE"):
    4998                this.set("minvalue", self._parse_bitwise())
    4999            if self._match_text_seq("MAXVALUE"):
    5000                this.set("maxvalue", self._parse_bitwise())
    5001
    5002            if self._match_text_seq("CYCLE"):
    5003                this.set("cycle", True)
    5004            elif self._match_text_seq("NO", "CYCLE"):
    5005                this.set("cycle", False)
    5006
    5007            if not identity:
    5008                this.set("expression", self._parse_range())
    5009            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5010                args = self._parse_csv(self._parse_bitwise)
    5011                this.set("start", seq_get(args, 0))
    5012                this.set("increment", seq_get(args, 1))
    5013
    5014            self._match_r_paren()
    5015
    5016        return this
    5017
    5018    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5019        self._match_text_seq("LENGTH")
    5020        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5021
    5022    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5023        if self._match_text_seq("NULL"):
    5024            return self.expression(exp.NotNullColumnConstraint)
    5025        if self._match_text_seq("CASESPECIFIC"):
    5026            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5027        if self._match_text_seq("FOR", "REPLICATION"):
    5028            return self.expression(exp.NotForReplicationColumnConstraint)
    5029        return None
    5030
    5031    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5032        if self._match(TokenType.CONSTRAINT):
    5033            this = self._parse_id_var()
    5034        else:
    5035            this = None
    5036
    5037        if self._match_texts(self.CONSTRAINT_PARSERS):
    5038            return self.expression(
    5039                exp.ColumnConstraint,
    5040                this=this,
    5041                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5042            )
    5043
    5044        return this
    5045
    5046    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5047        if not self._match(TokenType.CONSTRAINT):
    5048            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5049
    5050        return self.expression(
    5051            exp.Constraint,
    5052            this=self._parse_id_var(),
    5053            expressions=self._parse_unnamed_constraints(),
    5054        )
    5055
    5056    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5057        constraints = []
    5058        while True:
    5059            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5060            if not constraint:
    5061                break
    5062            constraints.append(constraint)
    5063
    5064        return constraints
    5065
    5066    def _parse_unnamed_constraint(
    5067        self, constraints: t.Optional[t.Collection[str]] = None
    5068    ) -> t.Optional[exp.Expression]:
    5069        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    5070            constraints or self.CONSTRAINT_PARSERS
    5071        ):
    5072            return None
    5073
    5074        constraint = self._prev.text.upper()
    5075        if constraint not in self.CONSTRAINT_PARSERS:
    5076            self.raise_error(f"No parser found for schema constraint {constraint}.")
    5077
    5078        return self.CONSTRAINT_PARSERS[constraint](self)
    5079
    5080    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    5081        self._match_text_seq("KEY")
    5082        return self.expression(
    5083            exp.UniqueColumnConstraint,
    5084            this=self._parse_schema(self._parse_id_var(any_token=False)),
    5085            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    5086            on_conflict=self._parse_on_conflict(),
    5087        )
    5088
    5089    def _parse_key_constraint_options(self) -> t.List[str]:
    5090        options = []
    5091        while True:
    5092            if not self._curr:
    5093                break
    5094
    5095            if self._match(TokenType.ON):
    5096                action = None
    5097                on = self._advance_any() and self._prev.text
    5098
    5099                if self._match_text_seq("NO", "ACTION"):
    5100                    action = "NO ACTION"
    5101                elif self._match_text_seq("CASCADE"):
    5102                    action = "CASCADE"
    5103                elif self._match_text_seq("RESTRICT"):
    5104                    action = "RESTRICT"
    5105                elif self._match_pair(TokenType.SET, TokenType.NULL):
    5106                    action = "SET NULL"
    5107                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5108                    action = "SET DEFAULT"
    5109                else:
    5110                    self.raise_error("Invalid key constraint")
    5111
    5112                options.append(f"ON {on} {action}")
    5113            elif self._match_text_seq("NOT", "ENFORCED"):
    5114                options.append("NOT ENFORCED")
    5115            elif self._match_text_seq("DEFERRABLE"):
    5116                options.append("DEFERRABLE")
    5117            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    5118                options.append("INITIALLY DEFERRED")
    5119            elif self._match_text_seq("NORELY"):
    5120                options.append("NORELY")
    5121            elif self._match_text_seq("MATCH", "FULL"):
    5122                options.append("MATCH FULL")
    5123            else:
    5124                break
    5125
    5126        return options
    5127
    5128    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    5129        if match and not self._match(TokenType.REFERENCES):
    5130            return None
    5131
    5132        expressions = None
    5133        this = self._parse_table(schema=True)
    5134        options = self._parse_key_constraint_options()
    5135        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    5136
    5137    def _parse_foreign_key(self) -> exp.ForeignKey:
    5138        expressions = self._parse_wrapped_id_vars()
    5139        reference = self._parse_references()
    5140        options = {}
    5141
    5142        while self._match(TokenType.ON):
    5143            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    5144                self.raise_error("Expected DELETE or UPDATE")
    5145
    5146            kind = self._prev.text.lower()
    5147
    5148            if self._match_text_seq("NO", "ACTION"):
    5149                action = "NO ACTION"
    5150            elif self._match(TokenType.SET):
    5151                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    5152                action = "SET " + self._prev.text.upper()
    5153            else:
    5154                self._advance()
    5155                action = self._prev.text.upper()
    5156
    5157            options[kind] = action
    5158
    5159        return self.expression(
    5160            exp.ForeignKey,
    5161            expressions=expressions,
    5162            reference=reference,
    5163            **options,  # type: ignore
    5164        )
    5165
    5166    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    5167        return self._parse_field()
    5168
    5169    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    5170        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    5171            self._retreat(self._index - 1)
    5172            return None
    5173
    5174        id_vars = self._parse_wrapped_id_vars()
    5175        return self.expression(
    5176            exp.PeriodForSystemTimeConstraint,
    5177            this=seq_get(id_vars, 0),
    5178            expression=seq_get(id_vars, 1),
    5179        )
    5180
    5181    def _parse_primary_key(
    5182        self, wrapped_optional: bool = False, in_props: bool = False
    5183    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    5184        desc = (
    5185            self._match_set((TokenType.ASC, TokenType.DESC))
    5186            and self._prev.token_type == TokenType.DESC
    5187        )
    5188
    5189        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    5190            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    5191
    5192        expressions = self._parse_wrapped_csv(
    5193            self._parse_primary_key_part, optional=wrapped_optional
    5194        )
    5195        options = self._parse_key_constraint_options()
    5196        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    5197
    5198    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    5199        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    5200
    5201    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5202        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    5203            return this
    5204
    5205        bracket_kind = self._prev.token_type
    5206        expressions = self._parse_csv(
    5207            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    5208        )
    5209
    5210        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    5211            self.raise_error("Expected ]")
    5212        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    5213            self.raise_error("Expected }")
    5214
    5215        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    5216        if bracket_kind == TokenType.L_BRACE:
    5217            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    5218        elif not this:
    5219            this = self.expression(exp.Array, expressions=expressions)
    5220        else:
    5221            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    5222            if constructor_type:
    5223                return self.expression(constructor_type, expressions=expressions)
    5224
    5225            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    5226            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    5227
    5228        self._add_comments(this)
    5229        return self._parse_bracket(this)
    5230
    5231    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5232        if self._match(TokenType.COLON):
    5233            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    5234        return this
    5235
    5236    def _parse_case(self) -> t.Optional[exp.Expression]:
    5237        ifs = []
    5238        default = None
    5239
    5240        comments = self._prev_comments
    5241        expression = self._parse_assignment()
    5242
    5243        while self._match(TokenType.WHEN):
    5244            this = self._parse_assignment()
    5245            self._match(TokenType.THEN)
    5246            then = self._parse_assignment()
    5247            ifs.append(self.expression(exp.If, this=this, true=then))
    5248
    5249        if self._match(TokenType.ELSE):
    5250            default = self._parse_assignment()
    5251
    5252        if not self._match(TokenType.END):
    5253            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    5254                default = exp.column("interval")
    5255            else:
    5256                self.raise_error("Expected END after CASE", self._prev)
    5257
    5258        return self.expression(
    5259            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    5260        )
    5261
    5262    def _parse_if(self) -> t.Optional[exp.Expression]:
    5263        if self._match(TokenType.L_PAREN):
    5264            args = self._parse_csv(self._parse_assignment)
    5265            this = self.validate_expression(exp.If.from_arg_list(args), args)
    5266            self._match_r_paren()
    5267        else:
    5268            index = self._index - 1
    5269
    5270            if self.NO_PAREN_IF_COMMANDS and index == 0:
    5271                return self._parse_as_command(self._prev)
    5272
    5273            condition = self._parse_assignment()
    5274
    5275            if not condition:
    5276                self._retreat(index)
    5277                return None
    5278
    5279            self._match(TokenType.THEN)
    5280            true = self._parse_assignment()
    5281            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    5282            self._match(TokenType.END)
    5283            this = self.expression(exp.If, this=condition, true=true, false=false)
    5284
    5285        return this
    5286
    5287    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    5288        if not self._match_text_seq("VALUE", "FOR"):
    5289            self._retreat(self._index - 1)
    5290            return None
    5291
    5292        return self.expression(
    5293            exp.NextValueFor,
    5294            this=self._parse_column(),
    5295            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    5296        )
    5297
    5298    def _parse_extract(self) -> exp.Extract:
    5299        this = self._parse_function() or self._parse_var() or self._parse_type()
    5300
    5301        if self._match(TokenType.FROM):
    5302            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    5303
    5304        if not self._match(TokenType.COMMA):
    5305            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    5306
    5307        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    5308
    5309    def _parse_gap_fill(self) -> exp.GapFill:
    5310        self._match(TokenType.TABLE)
    5311        this = self._parse_table()
    5312
    5313        self._match(TokenType.COMMA)
    5314        args = [this, *self._parse_csv(self._parse_lambda)]
    5315
    5316        gap_fill = exp.GapFill.from_arg_list(args)
    5317        return self.validate_expression(gap_fill, args)
    5318
    5319    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    5320        this = self._parse_assignment()
    5321
    5322        if not self._match(TokenType.ALIAS):
    5323            if self._match(TokenType.COMMA):
    5324                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    5325
    5326            self.raise_error("Expected AS after CAST")
    5327
    5328        fmt = None
    5329        to = self._parse_types()
    5330
    5331        if self._match(TokenType.FORMAT):
    5332            fmt_string = self._parse_string()
    5333            fmt = self._parse_at_time_zone(fmt_string)
    5334
    5335            if not to:
    5336                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    5337            if to.this in exp.DataType.TEMPORAL_TYPES:
    5338                this = self.expression(
    5339                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    5340                    this=this,
    5341                    format=exp.Literal.string(
    5342                        format_time(
    5343                            fmt_string.this if fmt_string else "",
    5344                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    5345                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    5346                        )
    5347                    ),
    5348                )
    5349
    5350                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    5351                    this.set("zone", fmt.args["zone"])
    5352                return this
    5353        elif not to:
    5354            self.raise_error("Expected TYPE after CAST")
    5355        elif isinstance(to, exp.Identifier):
    5356            to = exp.DataType.build(to.name, udt=True)
    5357        elif to.this == exp.DataType.Type.CHAR:
    5358            if self._match(TokenType.CHARACTER_SET):
    5359                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    5360
    5361        return self.expression(
    5362            exp.Cast if strict else exp.TryCast,
    5363            this=this,
    5364            to=to,
    5365            format=fmt,
    5366            safe=safe,
    5367            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    5368        )
    5369
    5370    def _parse_string_agg(self) -> exp.Expression:
    5371        if self._match(TokenType.DISTINCT):
    5372            args: t.List[t.Optional[exp.Expression]] = [
    5373                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    5374            ]
    5375            if self._match(TokenType.COMMA):
    5376                args.extend(self._parse_csv(self._parse_assignment))
    5377        else:
    5378            args = self._parse_csv(self._parse_assignment)  # type: ignore
    5379
    5380        index = self._index
    5381        if not self._match(TokenType.R_PAREN) and args:
    5382            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    5383            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    5384            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    5385            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    5386
    5387        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    5388        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    5389        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    5390        if not self._match_text_seq("WITHIN", "GROUP"):
    5391            self._retreat(index)
    5392            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    5393
    5394        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    5395        order = self._parse_order(this=seq_get(args, 0))
    5396        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    5397
    5398    def _parse_convert(
    5399        self, strict: bool, safe: t.Optional[bool] = None
    5400    ) -> t.Optional[exp.Expression]:
    5401        this = self._parse_bitwise()
    5402
    5403        if self._match(TokenType.USING):
    5404            to: t.Optional[exp.Expression] = self.expression(
    5405                exp.CharacterSet, this=self._parse_var()
    5406            )
    5407        elif self._match(TokenType.COMMA):
    5408            to = self._parse_types()
    5409        else:
    5410            to = None
    5411
    5412        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    5413
    5414    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    5415        """
    5416        There are generally two variants of the DECODE function:
    5417
    5418        - DECODE(bin, charset)
    5419        - DECODE(expression, search, result [, search, result] ... [, default])
    5420
    5421        The second variant will always be parsed into a CASE expression. Note that NULL
    5422        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    5423        instead of relying on pattern matching.
    5424        """
    5425        args = self._parse_csv(self._parse_assignment)
    5426
    5427        if len(args) < 3:
    5428            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    5429
    5430        expression, *expressions = args
    5431        if not expression:
    5432            return None
    5433
    5434        ifs = []
    5435        for search, result in zip(expressions[::2], expressions[1::2]):
    5436            if not search or not result:
    5437                return None
    5438
    5439            if isinstance(search, exp.Literal):
    5440                ifs.append(
    5441                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    5442                )
    5443            elif isinstance(search, exp.Null):
    5444                ifs.append(
    5445                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    5446                )
    5447            else:
    5448                cond = exp.or_(
    5449                    exp.EQ(this=expression.copy(), expression=search),
    5450                    exp.and_(
    5451                        exp.Is(this=expression.copy(), expression=exp.Null()),
    5452                        exp.Is(this=search.copy(), expression=exp.Null()),
    5453                        copy=False,
    5454                    ),
    5455                    copy=False,
    5456                )
    5457                ifs.append(exp.If(this=cond, true=result))
    5458
    5459        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    5460
    5461    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    5462        self._match_text_seq("KEY")
    5463        key = self._parse_column()
    5464        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    5465        self._match_text_seq("VALUE")
    5466        value = self._parse_bitwise()
    5467
    5468        if not key and not value:
    5469            return None
    5470        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    5471
    5472    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5473        if not this or not self._match_text_seq("FORMAT", "JSON"):
    5474            return this
    5475
    5476        return self.expression(exp.FormatJson, this=this)
    5477
    5478    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
    5479        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
    5480        for value in values:
    5481            if self._match_text_seq(value, "ON", on):
    5482                return f"{value} ON {on}"
    5483
    5484        return None
    5485
    5486    @t.overload
    5487    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    5488
    5489    @t.overload
    5490    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    5491
    5492    def _parse_json_object(self, agg=False):
    5493        star = self._parse_star()
    5494        expressions = (
    5495            [star]
    5496            if star
    5497            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    5498        )
    5499        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    5500
    5501        unique_keys = None
    5502        if self._match_text_seq("WITH", "UNIQUE"):
    5503            unique_keys = True
    5504        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    5505            unique_keys = False
    5506
    5507        self._match_text_seq("KEYS")
    5508
    5509        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    5510            self._parse_type()
    5511        )
    5512        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    5513
    5514        return self.expression(
    5515            exp.JSONObjectAgg if agg else exp.JSONObject,
    5516            expressions=expressions,
    5517            null_handling=null_handling,
    5518            unique_keys=unique_keys,
    5519            return_type=return_type,
    5520            encoding=encoding,
    5521        )
    5522
    5523    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    5524    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    5525        if not self._match_text_seq("NESTED"):
    5526            this = self._parse_id_var()
    5527            kind = self._parse_types(allow_identifiers=False)
    5528            nested = None
    5529        else:
    5530            this = None
    5531            kind = None
    5532            nested = True
    5533
    5534        path = self._match_text_seq("PATH") and self._parse_string()
    5535        nested_schema = nested and self._parse_json_schema()
    5536
    5537        return self.expression(
    5538            exp.JSONColumnDef,
    5539            this=this,
    5540            kind=kind,
    5541            path=path,
    5542            nested_schema=nested_schema,
    5543        )
    5544
    5545    def _parse_json_schema(self) -> exp.JSONSchema:
    5546        self._match_text_seq("COLUMNS")
    5547        return self.expression(
    5548            exp.JSONSchema,
    5549            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    5550        )
    5551
    5552    def _parse_json_table(self) -> exp.JSONTable:
    5553        this = self._parse_format_json(self._parse_bitwise())
    5554        path = self._match(TokenType.COMMA) and self._parse_string()
    5555        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    5556        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    5557        schema = self._parse_json_schema()
    5558
    5559        return exp.JSONTable(
    5560            this=this,
    5561            schema=schema,
    5562            path=path,
    5563            error_handling=error_handling,
    5564            empty_handling=empty_handling,
    5565        )
    5566
    5567    def _parse_match_against(self) -> exp.MatchAgainst:
    5568        expressions = self._parse_csv(self._parse_column)
    5569
    5570        self._match_text_seq(")", "AGAINST", "(")
    5571
    5572        this = self._parse_string()
    5573
    5574        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    5575            modifier = "IN NATURAL LANGUAGE MODE"
    5576            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5577                modifier = f"{modifier} WITH QUERY EXPANSION"
    5578        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    5579            modifier = "IN BOOLEAN MODE"
    5580        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5581            modifier = "WITH QUERY EXPANSION"
    5582        else:
    5583            modifier = None
    5584
    5585        return self.expression(
    5586            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    5587        )
    5588
    5589    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    5590    def _parse_open_json(self) -> exp.OpenJSON:
    5591        this = self._parse_bitwise()
    5592        path = self._match(TokenType.COMMA) and self._parse_string()
    5593
    5594        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    5595            this = self._parse_field(any_token=True)
    5596            kind = self._parse_types()
    5597            path = self._parse_string()
    5598            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    5599
    5600            return self.expression(
    5601                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    5602            )
    5603
    5604        expressions = None
    5605        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    5606            self._match_l_paren()
    5607            expressions = self._parse_csv(_parse_open_json_column_def)
    5608
    5609        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    5610
    5611    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    5612        args = self._parse_csv(self._parse_bitwise)
    5613
    5614        if self._match(TokenType.IN):
    5615            return self.expression(
    5616                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    5617            )
    5618
    5619        if haystack_first:
    5620            haystack = seq_get(args, 0)
    5621            needle = seq_get(args, 1)
    5622        else:
    5623            needle = seq_get(args, 0)
    5624            haystack = seq_get(args, 1)
    5625
    5626        return self.expression(
    5627            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    5628        )
    5629
    5630    def _parse_predict(self) -> exp.Predict:
    5631        self._match_text_seq("MODEL")
    5632        this = self._parse_table()
    5633
    5634        self._match(TokenType.COMMA)
    5635        self._match_text_seq("TABLE")
    5636
    5637        return self.expression(
    5638            exp.Predict,
    5639            this=this,
    5640            expression=self._parse_table(),
    5641            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    5642        )
    5643
    5644    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    5645        args = self._parse_csv(self._parse_table)
    5646        return exp.JoinHint(this=func_name.upper(), expressions=args)
    5647
    5648    def _parse_substring(self) -> exp.Substring:
    5649        # Postgres supports the form: substring(string [from int] [for int])
    5650        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    5651
    5652        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    5653
    5654        if self._match(TokenType.FROM):
    5655            args.append(self._parse_bitwise())
    5656        if self._match(TokenType.FOR):
    5657            if len(args) == 1:
    5658                args.append(exp.Literal.number(1))
    5659            args.append(self._parse_bitwise())
    5660
    5661        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    5662
    5663    def _parse_trim(self) -> exp.Trim:
    5664        # https://www.w3resource.com/sql/character-functions/trim.php
    5665        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    5666
    5667        position = None
    5668        collation = None
    5669        expression = None
    5670
    5671        if self._match_texts(self.TRIM_TYPES):
    5672            position = self._prev.text.upper()
    5673
    5674        this = self._parse_bitwise()
    5675        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    5676            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    5677            expression = self._parse_bitwise()
    5678
    5679            if invert_order:
    5680                this, expression = expression, this
    5681
    5682        if self._match(TokenType.COLLATE):
    5683            collation = self._parse_bitwise()
    5684
    5685        return self.expression(
    5686            exp.Trim, this=this, position=position, expression=expression, collation=collation
    5687        )
    5688
    5689    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    5690        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    5691
    5692    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    5693        return self._parse_window(self._parse_id_var(), alias=True)
    5694
    5695    def _parse_respect_or_ignore_nulls(
    5696        self, this: t.Optional[exp.Expression]
    5697    ) -> t.Optional[exp.Expression]:
    5698        if self._match_text_seq("IGNORE", "NULLS"):
    5699            return self.expression(exp.IgnoreNulls, this=this)
    5700        if self._match_text_seq("RESPECT", "NULLS"):
    5701            return self.expression(exp.RespectNulls, this=this)
    5702        return this
    5703
    5704    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5705        if self._match(TokenType.HAVING):
    5706            self._match_texts(("MAX", "MIN"))
    5707            max = self._prev.text.upper() != "MIN"
    5708            return self.expression(
    5709                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    5710            )
    5711
    5712        return this
    5713
    5714    def _parse_window(
    5715        self, this: t.Optional[exp.Expression], alias: bool = False
    5716    ) -> t.Optional[exp.Expression]:
    5717        func = this
    5718        comments = func.comments if isinstance(func, exp.Expression) else None
    5719
    5720        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    5721            self._match(TokenType.WHERE)
    5722            this = self.expression(
    5723                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    5724            )
    5725            self._match_r_paren()
    5726
    5727        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    5728        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    5729        if self._match_text_seq("WITHIN", "GROUP"):
    5730            order = self._parse_wrapped(self._parse_order)
    5731            this = self.expression(exp.WithinGroup, this=this, expression=order)
    5732
    5733        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    5734        # Some dialects choose to implement and some do not.
    5735        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    5736
    5737        # There is some code above in _parse_lambda that handles
    5738        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    5739
    5740        # The below changes handle
    5741        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    5742
    5743        # Oracle allows both formats
    5744        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    5745        #   and Snowflake chose to do the same for familiarity
    5746        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    5747        if isinstance(this, exp.AggFunc):
    5748            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    5749
    5750            if ignore_respect and ignore_respect is not this:
    5751                ignore_respect.replace(ignore_respect.this)
    5752                this = self.expression(ignore_respect.__class__, this=this)
    5753
    5754        this = self._parse_respect_or_ignore_nulls(this)
    5755
    5756        # bigquery select from window x AS (partition by ...)
    5757        if alias:
    5758            over = None
    5759            self._match(TokenType.ALIAS)
    5760        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    5761            return this
    5762        else:
    5763            over = self._prev.text.upper()
    5764
    5765        if comments and isinstance(func, exp.Expression):
    5766            func.pop_comments()
    5767
    5768        if not self._match(TokenType.L_PAREN):
    5769            return self.expression(
    5770                exp.Window,
    5771                comments=comments,
    5772                this=this,
    5773                alias=self._parse_id_var(False),
    5774                over=over,
    5775            )
    5776
    5777        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    5778
    5779        first = self._match(TokenType.FIRST)
    5780        if self._match_text_seq("LAST"):
    5781            first = False
    5782
    5783        partition, order = self._parse_partition_and_order()
    5784        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    5785
    5786        if kind:
    5787            self._match(TokenType.BETWEEN)
    5788            start = self._parse_window_spec()
    5789            self._match(TokenType.AND)
    5790            end = self._parse_window_spec()
    5791
    5792            spec = self.expression(
    5793                exp.WindowSpec,
    5794                kind=kind,
    5795                start=start["value"],
    5796                start_side=start["side"],
    5797                end=end["value"],
    5798                end_side=end["side"],
    5799            )
    5800        else:
    5801            spec = None
    5802
    5803        self._match_r_paren()
    5804
    5805        window = self.expression(
    5806            exp.Window,
    5807            comments=comments,
    5808            this=this,
    5809            partition_by=partition,
    5810            order=order,
    5811            spec=spec,
    5812            alias=window_alias,
    5813            over=over,
    5814            first=first,
    5815        )
    5816
    5817        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    5818        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    5819            return self._parse_window(window, alias=alias)
    5820
    5821        return window
    5822
    5823    def _parse_partition_and_order(
    5824        self,
    5825    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    5826        return self._parse_partition_by(), self._parse_order()
    5827
    5828    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    5829        self._match(TokenType.BETWEEN)
    5830
    5831        return {
    5832            "value": (
    5833                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    5834                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    5835                or self._parse_bitwise()
    5836            ),
    5837            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    5838        }
    5839
    5840    def _parse_alias(
    5841        self, this: t.Optional[exp.Expression], explicit: bool = False
    5842    ) -> t.Optional[exp.Expression]:
    5843        any_token = self._match(TokenType.ALIAS)
    5844        comments = self._prev_comments or []
    5845
    5846        if explicit and not any_token:
    5847            return this
    5848
    5849        if self._match(TokenType.L_PAREN):
    5850            aliases = self.expression(
    5851                exp.Aliases,
    5852                comments=comments,
    5853                this=this,
    5854                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    5855            )
    5856            self._match_r_paren(aliases)
    5857            return aliases
    5858
    5859        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    5860            self.STRING_ALIASES and self._parse_string_as_identifier()
    5861        )
    5862
    5863        if alias:
    5864            comments.extend(alias.pop_comments())
    5865            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    5866            column = this.this
    5867
    5868            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    5869            if not this.comments and column and column.comments:
    5870                this.comments = column.pop_comments()
    5871
    5872        return this
    5873
    5874    def _parse_id_var(
    5875        self,
    5876        any_token: bool = True,
    5877        tokens: t.Optional[t.Collection[TokenType]] = None,
    5878    ) -> t.Optional[exp.Expression]:
    5879        expression = self._parse_identifier()
    5880        if not expression and (
    5881            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    5882        ):
    5883            quoted = self._prev.token_type == TokenType.STRING
    5884            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    5885
    5886        return expression
    5887
    5888    def _parse_string(self) -> t.Optional[exp.Expression]:
    5889        if self._match_set(self.STRING_PARSERS):
    5890            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    5891        return self._parse_placeholder()
    5892
    5893    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    5894        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    5895
    5896    def _parse_number(self) -> t.Optional[exp.Expression]:
    5897        if self._match_set(self.NUMERIC_PARSERS):
    5898            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    5899        return self._parse_placeholder()
    5900
    5901    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    5902        if self._match(TokenType.IDENTIFIER):
    5903            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    5904        return self._parse_placeholder()
    5905
    5906    def _parse_var(
    5907        self,
    5908        any_token: bool = False,
    5909        tokens: t.Optional[t.Collection[TokenType]] = None,
    5910        upper: bool = False,
    5911    ) -> t.Optional[exp.Expression]:
    5912        if (
    5913            (any_token and self._advance_any())
    5914            or self._match(TokenType.VAR)
    5915            or (self._match_set(tokens) if tokens else False)
    5916        ):
    5917            return self.expression(
    5918                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    5919            )
    5920        return self._parse_placeholder()
    5921
    5922    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    5923        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    5924            self._advance()
    5925            return self._prev
    5926        return None
    5927
    5928    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    5929        return self._parse_var() or self._parse_string()
    5930
    5931    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    5932        return self._parse_primary() or self._parse_var(any_token=True)
    5933
    5934    def _parse_null(self) -> t.Optional[exp.Expression]:
    5935        if self._match_set(self.NULL_TOKENS):
    5936            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    5937        return self._parse_placeholder()
    5938
    5939    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    5940        if self._match(TokenType.TRUE):
    5941            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    5942        if self._match(TokenType.FALSE):
    5943            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    5944        return self._parse_placeholder()
    5945
    5946    def _parse_star(self) -> t.Optional[exp.Expression]:
    5947        if self._match(TokenType.STAR):
    5948            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    5949        return self._parse_placeholder()
    5950
    5951    def _parse_parameter(self) -> exp.Parameter:
    5952        this = self._parse_identifier() or self._parse_primary_or_var()
    5953        return self.expression(exp.Parameter, this=this)
    5954
    5955    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    5956        if self._match_set(self.PLACEHOLDER_PARSERS):
    5957            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    5958            if placeholder:
    5959                return placeholder
    5960            self._advance(-1)
    5961        return None
    5962
    5963    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    5964        if not self._match_texts(keywords):
    5965            return None
    5966        if self._match(TokenType.L_PAREN, advance=False):
    5967            return self._parse_wrapped_csv(self._parse_expression)
    5968
    5969        expression = self._parse_expression()
    5970        return [expression] if expression else None
    5971
    5972    def _parse_csv(
    5973        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    5974    ) -> t.List[exp.Expression]:
    5975        parse_result = parse_method()
    5976        items = [parse_result] if parse_result is not None else []
    5977
    5978        while self._match(sep):
    5979            self._add_comments(parse_result)
    5980            parse_result = parse_method()
    5981            if parse_result is not None:
    5982                items.append(parse_result)
    5983
    5984        return items
    5985
    5986    def _parse_tokens(
    5987        self, parse_method: t.Callable, expressions: t.Dict
    5988    ) -> t.Optional[exp.Expression]:
    5989        this = parse_method()
    5990
    5991        while self._match_set(expressions):
    5992            this = self.expression(
    5993                expressions[self._prev.token_type],
    5994                this=this,
    5995                comments=self._prev_comments,
    5996                expression=parse_method(),
    5997            )
    5998
    5999        return this
    6000
    6001    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    6002        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    6003
    6004    def _parse_wrapped_csv(
    6005        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    6006    ) -> t.List[exp.Expression]:
    6007        return self._parse_wrapped(
    6008            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    6009        )
    6010
    6011    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    6012        wrapped = self._match(TokenType.L_PAREN)
    6013        if not wrapped and not optional:
    6014            self.raise_error("Expecting (")
    6015        parse_result = parse_method()
    6016        if wrapped:
    6017            self._match_r_paren()
    6018        return parse_result
    6019
    6020    def _parse_expressions(self) -> t.List[exp.Expression]:
    6021        return self._parse_csv(self._parse_expression)
    6022
    6023    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    6024        return self._parse_select() or self._parse_set_operations(
    6025            self._parse_expression() if alias else self._parse_assignment()
    6026        )
    6027
    6028    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    6029        return self._parse_query_modifiers(
    6030            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    6031        )
    6032
    6033    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    6034        this = None
    6035        if self._match_texts(self.TRANSACTION_KIND):
    6036            this = self._prev.text
    6037
    6038        self._match_texts(("TRANSACTION", "WORK"))
    6039
    6040        modes = []
    6041        while True:
    6042            mode = []
    6043            while self._match(TokenType.VAR):
    6044                mode.append(self._prev.text)
    6045
    6046            if mode:
    6047                modes.append(" ".join(mode))
    6048            if not self._match(TokenType.COMMA):
    6049                break
    6050
    6051        return self.expression(exp.Transaction, this=this, modes=modes)
    6052
    6053    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    6054        chain = None
    6055        savepoint = None
    6056        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    6057
    6058        self._match_texts(("TRANSACTION", "WORK"))
    6059
    6060        if self._match_text_seq("TO"):
    6061            self._match_text_seq("SAVEPOINT")
    6062            savepoint = self._parse_id_var()
    6063
    6064        if self._match(TokenType.AND):
    6065            chain = not self._match_text_seq("NO")
    6066            self._match_text_seq("CHAIN")
    6067
    6068        if is_rollback:
    6069            return self.expression(exp.Rollback, savepoint=savepoint)
    6070
    6071        return self.expression(exp.Commit, chain=chain)
    6072
    6073    def _parse_refresh(self) -> exp.Refresh:
    6074        self._match(TokenType.TABLE)
    6075        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    6076
    6077    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    6078        if not self._match_text_seq("ADD"):
    6079            return None
    6080
    6081        self._match(TokenType.COLUMN)
    6082        exists_column = self._parse_exists(not_=True)
    6083        expression = self._parse_field_def()
    6084
    6085        if expression:
    6086            expression.set("exists", exists_column)
    6087
    6088            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    6089            if self._match_texts(("FIRST", "AFTER")):
    6090                position = self._prev.text
    6091                column_position = self.expression(
    6092                    exp.ColumnPosition, this=self._parse_column(), position=position
    6093                )
    6094                expression.set("position", column_position)
    6095
    6096        return expression
    6097
    6098    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    6099        drop = self._match(TokenType.DROP) and self._parse_drop()
    6100        if drop and not isinstance(drop, exp.Command):
    6101            drop.set("kind", drop.args.get("kind", "COLUMN"))
    6102        return drop
    6103
    6104    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    6105    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    6106        return self.expression(
    6107            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    6108        )
    6109
    6110    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    6111        index = self._index - 1
    6112
    6113        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    6114            return self._parse_csv(
    6115                lambda: self.expression(
    6116                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    6117                )
    6118            )
    6119
    6120        self._retreat(index)
    6121        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    6122            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    6123        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    6124
    6125    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    6126        if self._match_texts(self.ALTER_ALTER_PARSERS):
    6127            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    6128
    6129        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    6130        # keyword after ALTER we default to parsing this statement
    6131        self._match(TokenType.COLUMN)
    6132        column = self._parse_field(any_token=True)
    6133
    6134        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    6135            return self.expression(exp.AlterColumn, this=column, drop=True)
    6136        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    6137            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    6138        if self._match(TokenType.COMMENT):
    6139            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    6140        if self._match_text_seq("DROP", "NOT", "NULL"):
    6141            return self.expression(
    6142                exp.AlterColumn,
    6143                this=column,
    6144                drop=True,
    6145                allow_null=True,
    6146            )
    6147        if self._match_text_seq("SET", "NOT", "NULL"):
    6148            return self.expression(
    6149                exp.AlterColumn,
    6150                this=column,
    6151                allow_null=False,
    6152            )
    6153        self._match_text_seq("SET", "DATA")
    6154        self._match_text_seq("TYPE")
    6155        return self.expression(
    6156            exp.AlterColumn,
    6157            this=column,
    6158            dtype=self._parse_types(),
    6159            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    6160            using=self._match(TokenType.USING) and self._parse_assignment(),
    6161        )
    6162
    6163    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    6164        if self._match_texts(("ALL", "EVEN", "AUTO")):
    6165            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    6166
    6167        self._match_text_seq("KEY", "DISTKEY")
    6168        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    6169
    6170    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    6171        if compound:
    6172            self._match_text_seq("SORTKEY")
    6173
    6174        if self._match(TokenType.L_PAREN, advance=False):
    6175            return self.expression(
    6176                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    6177            )
    6178
    6179        self._match_texts(("AUTO", "NONE"))
    6180        return self.expression(
    6181            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    6182        )
    6183
    6184    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    6185        index = self._index - 1
    6186
    6187        partition_exists = self._parse_exists()
    6188        if self._match(TokenType.PARTITION, advance=False):
    6189            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    6190
    6191        self._retreat(index)
    6192        return self._parse_csv(self._parse_drop_column)
    6193
    6194    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
    6195        if self._match(TokenType.COLUMN):
    6196            exists = self._parse_exists()
    6197            old_column = self._parse_column()
    6198            to = self._match_text_seq("TO")
    6199            new_column = self._parse_column()
    6200
    6201            if old_column is None or to is None or new_column is None:
    6202                return None
    6203
    6204            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    6205
    6206        self._match_text_seq("TO")
    6207        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    6208
    6209    def _parse_alter_table_set(self) -> exp.AlterSet:
    6210        alter_set = self.expression(exp.AlterSet)
    6211
    6212        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    6213            "TABLE", "PROPERTIES"
    6214        ):
    6215            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    6216        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    6217            alter_set.set("expressions", [self._parse_assignment()])
    6218        elif self._match_texts(("LOGGED", "UNLOGGED")):
    6219            alter_set.set("option", exp.var(self._prev.text.upper()))
    6220        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    6221            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    6222        elif self._match_text_seq("LOCATION"):
    6223            alter_set.set("location", self._parse_field())
    6224        elif self._match_text_seq("ACCESS", "METHOD"):
    6225            alter_set.set("access_method", self._parse_field())
    6226        elif self._match_text_seq("TABLESPACE"):
    6227            alter_set.set("tablespace", self._parse_field())
    6228        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    6229            alter_set.set("file_format", [self._parse_field()])
    6230        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    6231            alter_set.set("file_format", self._parse_wrapped_options())
    6232        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    6233            alter_set.set("copy_options", self._parse_wrapped_options())
    6234        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    6235            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    6236        else:
    6237            if self._match_text_seq("SERDE"):
    6238                alter_set.set("serde", self._parse_field())
    6239
    6240            alter_set.set("expressions", [self._parse_properties()])
    6241
    6242        return alter_set
    6243
    6244    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    6245        start = self._prev
    6246
    6247        if not self._match(TokenType.TABLE):
    6248            return self._parse_as_command(start)
    6249
    6250        exists = self._parse_exists()
    6251        only = self._match_text_seq("ONLY")
    6252        this = self._parse_table(schema=True)
    6253        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6254
    6255        if self._next:
    6256            self._advance()
    6257
    6258        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    6259        if parser:
    6260            actions = ensure_list(parser(self))
    6261            options = self._parse_csv(self._parse_property)
    6262
    6263            if not self._curr and actions:
    6264                return self.expression(
    6265                    exp.AlterTable,
    6266                    this=this,
    6267                    exists=exists,
    6268                    actions=actions,
    6269                    only=only,
    6270                    options=options,
    6271                    cluster=cluster,
    6272                )
    6273
    6274        return self._parse_as_command(start)
    6275
    6276    def _parse_merge(self) -> exp.Merge:
    6277        self._match(TokenType.INTO)
    6278        target = self._parse_table()
    6279
    6280        if target and self._match(TokenType.ALIAS, advance=False):
    6281            target.set("alias", self._parse_table_alias())
    6282
    6283        self._match(TokenType.USING)
    6284        using = self._parse_table()
    6285
    6286        self._match(TokenType.ON)
    6287        on = self._parse_assignment()
    6288
    6289        return self.expression(
    6290            exp.Merge,
    6291            this=target,
    6292            using=using,
    6293            on=on,
    6294            expressions=self._parse_when_matched(),
    6295        )
    6296
    6297    def _parse_when_matched(self) -> t.List[exp.When]:
    6298        whens = []
    6299
    6300        while self._match(TokenType.WHEN):
    6301            matched = not self._match(TokenType.NOT)
    6302            self._match_text_seq("MATCHED")
    6303            source = (
    6304                False
    6305                if self._match_text_seq("BY", "TARGET")
    6306                else self._match_text_seq("BY", "SOURCE")
    6307            )
    6308            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    6309
    6310            self._match(TokenType.THEN)
    6311
    6312            if self._match(TokenType.INSERT):
    6313                _this = self._parse_star()
    6314                if _this:
    6315                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    6316                else:
    6317                    then = self.expression(
    6318                        exp.Insert,
    6319                        this=self._parse_value(),
    6320                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    6321                    )
    6322            elif self._match(TokenType.UPDATE):
    6323                expressions = self._parse_star()
    6324                if expressions:
    6325                    then = self.expression(exp.Update, expressions=expressions)
    6326                else:
    6327                    then = self.expression(
    6328                        exp.Update,
    6329                        expressions=self._match(TokenType.SET)
    6330                        and self._parse_csv(self._parse_equality),
    6331                    )
    6332            elif self._match(TokenType.DELETE):
    6333                then = self.expression(exp.Var, this=self._prev.text)
    6334            else:
    6335                then = None
    6336
    6337            whens.append(
    6338                self.expression(
    6339                    exp.When,
    6340                    matched=matched,
    6341                    source=source,
    6342                    condition=condition,
    6343                    then=then,
    6344                )
    6345            )
    6346        return whens
    6347
    6348    def _parse_show(self) -> t.Optional[exp.Expression]:
    6349        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    6350        if parser:
    6351            return parser(self)
    6352        return self._parse_as_command(self._prev)
    6353
    6354    def _parse_set_item_assignment(
    6355        self, kind: t.Optional[str] = None
    6356    ) -> t.Optional[exp.Expression]:
    6357        index = self._index
    6358
    6359        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    6360            return self._parse_set_transaction(global_=kind == "GLOBAL")
    6361
    6362        left = self._parse_primary() or self._parse_column()
    6363        assignment_delimiter = self._match_texts(("=", "TO"))
    6364
    6365        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    6366            self._retreat(index)
    6367            return None
    6368
    6369        right = self._parse_statement() or self._parse_id_var()
    6370        if isinstance(right, (exp.Column, exp.Identifier)):
    6371            right = exp.var(right.name)
    6372
    6373        this = self.expression(exp.EQ, this=left, expression=right)
    6374        return self.expression(exp.SetItem, this=this, kind=kind)
    6375
    6376    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    6377        self._match_text_seq("TRANSACTION")
    6378        characteristics = self._parse_csv(
    6379            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    6380        )
    6381        return self.expression(
    6382            exp.SetItem,
    6383            expressions=characteristics,
    6384            kind="TRANSACTION",
    6385            **{"global": global_},  # type: ignore
    6386        )
    6387
    6388    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    6389        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    6390        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    6391
    6392    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    6393        index = self._index
    6394        set_ = self.expression(
    6395            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    6396        )
    6397
    6398        if self._curr:
    6399            self._retreat(index)
    6400            return self._parse_as_command(self._prev)
    6401
    6402        return set_
    6403
    6404    def _parse_var_from_options(
    6405        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    6406    ) -> t.Optional[exp.Var]:
    6407        start = self._curr
    6408        if not start:
    6409            return None
    6410
    6411        option = start.text.upper()
    6412        continuations = options.get(option)
    6413
    6414        index = self._index
    6415        self._advance()
    6416        for keywords in continuations or []:
    6417            if isinstance(keywords, str):
    6418                keywords = (keywords,)
    6419
    6420            if self._match_text_seq(*keywords):
    6421                option = f"{option} {' '.join(keywords)}"
    6422                break
    6423        else:
    6424            if continuations or continuations is None:
    6425                if raise_unmatched:
    6426                    self.raise_error(f"Unknown option {option}")
    6427
    6428                self._retreat(index)
    6429                return None
    6430
    6431        return exp.var(option)
    6432
    6433    def _parse_as_command(self, start: Token) -> exp.Command:
    6434        while self._curr:
    6435            self._advance()
    6436        text = self._find_sql(start, self._prev)
    6437        size = len(start.text)
    6438        self._warn_unsupported()
    6439        return exp.Command(this=text[:size], expression=text[size:])
    6440
    6441    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    6442        settings = []
    6443
    6444        self._match_l_paren()
    6445        kind = self._parse_id_var()
    6446
    6447        if self._match(TokenType.L_PAREN):
    6448            while True:
    6449                key = self._parse_id_var()
    6450                value = self._parse_primary()
    6451
    6452                if not key and value is None:
    6453                    break
    6454                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    6455            self._match(TokenType.R_PAREN)
    6456
    6457        self._match_r_paren()
    6458
    6459        return self.expression(
    6460            exp.DictProperty,
    6461            this=this,
    6462            kind=kind.this if kind else None,
    6463            settings=settings,
    6464        )
    6465
    6466    def _parse_dict_range(self, this: str) -> exp.DictRange:
    6467        self._match_l_paren()
    6468        has_min = self._match_text_seq("MIN")
    6469        if has_min:
    6470            min = self._parse_var() or self._parse_primary()
    6471            self._match_text_seq("MAX")
    6472            max = self._parse_var() or self._parse_primary()
    6473        else:
    6474            max = self._parse_var() or self._parse_primary()
    6475            min = exp.Literal.number(0)
    6476        self._match_r_paren()
    6477        return self.expression(exp.DictRange, this=this, min=min, max=max)
    6478
    6479    def _parse_comprehension(
    6480        self, this: t.Optional[exp.Expression]
    6481    ) -> t.Optional[exp.Comprehension]:
    6482        index = self._index
    6483        expression = self._parse_column()
    6484        if not self._match(TokenType.IN):
    6485            self._retreat(index - 1)
    6486            return None
    6487        iterator = self._parse_column()
    6488        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    6489        return self.expression(
    6490            exp.Comprehension,
    6491            this=this,
    6492            expression=expression,
    6493            iterator=iterator,
    6494            condition=condition,
    6495        )
    6496
    6497    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    6498        if self._match(TokenType.HEREDOC_STRING):
    6499            return self.expression(exp.Heredoc, this=self._prev.text)
    6500
    6501        if not self._match_text_seq("$"):
    6502            return None
    6503
    6504        tags = ["$"]
    6505        tag_text = None
    6506
    6507        if self._is_connected():
    6508            self._advance()
    6509            tags.append(self._prev.text.upper())
    6510        else:
    6511            self.raise_error("No closing $ found")
    6512
    6513        if tags[-1] != "$":
    6514            if self._is_connected() and self._match_text_seq("$"):
    6515                tag_text = tags[-1]
    6516                tags.append("$")
    6517            else:
    6518                self.raise_error("No closing $ found")
    6519
    6520        heredoc_start = self._curr
    6521
    6522        while self._curr:
    6523            if self._match_text_seq(*tags, advance=False):
    6524                this = self._find_sql(heredoc_start, self._prev)
    6525                self._advance(len(tags))
    6526                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    6527
    6528            self._advance()
    6529
    6530        self.raise_error(f"No closing {''.join(tags)} found")
    6531        return None
    6532
    6533    def _find_parser(
    6534        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    6535    ) -> t.Optional[t.Callable]:
    6536        if not self._curr:
    6537            return None
    6538
    6539        index = self._index
    6540        this = []
    6541        while True:
    6542            # The current token might be multiple words
    6543            curr = self._curr.text.upper()
    6544            key = curr.split(" ")
    6545            this.append(curr)
    6546
    6547            self._advance()
    6548            result, trie = in_trie(trie, key)
    6549            if result == TrieResult.FAILED:
    6550                break
    6551
    6552            if result == TrieResult.EXISTS:
    6553                subparser = parsers[" ".join(this)]
    6554                return subparser
    6555
    6556        self._retreat(index)
    6557        return None
    6558
    6559    def _match(self, token_type, advance=True, expression=None):
    6560        if not self._curr:
    6561            return None
    6562
    6563        if self._curr.token_type == token_type:
    6564            if advance:
    6565                self._advance()
    6566            self._add_comments(expression)
    6567            return True
    6568
    6569        return None
    6570
    6571    def _match_set(self, types, advance=True):
    6572        if not self._curr:
    6573            return None
    6574
    6575        if self._curr.token_type in types:
    6576            if advance:
    6577                self._advance()
    6578            return True
    6579
    6580        return None
    6581
    6582    def _match_pair(self, token_type_a, token_type_b, advance=True):
    6583        if not self._curr or not self._next:
    6584            return None
    6585
    6586        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    6587            if advance:
    6588                self._advance(2)
    6589            return True
    6590
    6591        return None
    6592
    6593    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6594        if not self._match(TokenType.L_PAREN, expression=expression):
    6595            self.raise_error("Expecting (")
    6596
    6597    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6598        if not self._match(TokenType.R_PAREN, expression=expression):
    6599            self.raise_error("Expecting )")
    6600
    6601    def _match_texts(self, texts, advance=True):
    6602        if self._curr and self._curr.text.upper() in texts:
    6603            if advance:
    6604                self._advance()
    6605            return True
    6606        return None
    6607
    6608    def _match_text_seq(self, *texts, advance=True):
    6609        index = self._index
    6610        for text in texts:
    6611            if self._curr and self._curr.text.upper() == text:
    6612                self._advance()
    6613            else:
    6614                self._retreat(index)
    6615                return None
    6616
    6617        if not advance:
    6618            self._retreat(index)
    6619
    6620        return True
    6621
    6622    def _replace_lambda(
    6623        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    6624    ) -> t.Optional[exp.Expression]:
    6625        if not node:
    6626            return node
    6627
    6628        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    6629
    6630        for column in node.find_all(exp.Column):
    6631            typ = lambda_types.get(column.parts[0].name)
    6632            if typ is not None:
    6633                dot_or_id = column.to_dot() if column.table else column.this
    6634
    6635                if typ:
    6636                    dot_or_id = self.expression(
    6637                        exp.Cast,
    6638                        this=dot_or_id,
    6639                        to=typ,
    6640                    )
    6641
    6642                parent = column.parent
    6643
    6644                while isinstance(parent, exp.Dot):
    6645                    if not isinstance(parent.parent, exp.Dot):
    6646                        parent.replace(dot_or_id)
    6647                        break
    6648                    parent = parent.parent
    6649                else:
    6650                    if column is node:
    6651                        node = dot_or_id
    6652                    else:
    6653                        column.replace(dot_or_id)
    6654        return node
    6655
    6656    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    6657        start = self._prev
    6658
    6659        # Not to be confused with TRUNCATE(number, decimals) function call
    6660        if self._match(TokenType.L_PAREN):
    6661            self._retreat(self._index - 2)
    6662            return self._parse_function()
    6663
    6664        # Clickhouse supports TRUNCATE DATABASE as well
    6665        is_database = self._match(TokenType.DATABASE)
    6666
    6667        self._match(TokenType.TABLE)
    6668
    6669        exists = self._parse_exists(not_=False)
    6670
    6671        expressions = self._parse_csv(
    6672            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    6673        )
    6674
    6675        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6676
    6677        if self._match_text_seq("RESTART", "IDENTITY"):
    6678            identity = "RESTART"
    6679        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    6680            identity = "CONTINUE"
    6681        else:
    6682            identity = None
    6683
    6684        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    6685            option = self._prev.text
    6686        else:
    6687            option = None
    6688
    6689        partition = self._parse_partition()
    6690
    6691        # Fallback case
    6692        if self._curr:
    6693            return self._parse_as_command(start)
    6694
    6695        return self.expression(
    6696            exp.TruncateTable,
    6697            expressions=expressions,
    6698            is_database=is_database,
    6699            exists=exists,
    6700            cluster=cluster,
    6701            identity=identity,
    6702            option=option,
    6703            partition=partition,
    6704        )
    6705
    6706    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    6707        this = self._parse_ordered(self._parse_opclass)
    6708
    6709        if not self._match(TokenType.WITH):
    6710            return this
    6711
    6712        op = self._parse_var(any_token=True)
    6713
    6714        return self.expression(exp.WithOperator, this=this, op=op)
    6715
    6716    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    6717        self._match(TokenType.EQ)
    6718        self._match(TokenType.L_PAREN)
    6719
    6720        opts: t.List[t.Optional[exp.Expression]] = []
    6721        while self._curr and not self._match(TokenType.R_PAREN):
    6722            if self._match_text_seq("FORMAT_NAME", "="):
    6723                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
    6724                # so we parse it separately to use _parse_field()
    6725                prop = self.expression(
    6726                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
    6727                )
    6728                opts.append(prop)
    6729            else:
    6730                opts.append(self._parse_property())
    6731
    6732            self._match(TokenType.COMMA)
    6733
    6734        return opts
    6735
    6736    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    6737        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    6738
    6739        options = []
    6740        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    6741            option = self._parse_var(any_token=True)
    6742            prev = self._prev.text.upper()
    6743
    6744            # Different dialects might separate options and values by white space, "=" and "AS"
    6745            self._match(TokenType.EQ)
    6746            self._match(TokenType.ALIAS)
    6747
    6748            param = self.expression(exp.CopyParameter, this=option)
    6749
    6750            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    6751                TokenType.L_PAREN, advance=False
    6752            ):
    6753                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    6754                param.set("expressions", self._parse_wrapped_options())
    6755            elif prev == "FILE_FORMAT":
    6756                # T-SQL's external file format case
    6757                param.set("expression", self._parse_field())
    6758            else:
    6759                param.set("expression", self._parse_unquoted_field())
    6760
    6761            options.append(param)
    6762            self._match(sep)
    6763
    6764        return options
    6765
    6766    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    6767        expr = self.expression(exp.Credentials)
    6768
    6769        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    6770            expr.set("storage", self._parse_field())
    6771        if self._match_text_seq("CREDENTIALS"):
    6772            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    6773            creds = (
    6774                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    6775            )
    6776            expr.set("credentials", creds)
    6777        if self._match_text_seq("ENCRYPTION"):
    6778            expr.set("encryption", self._parse_wrapped_options())
    6779        if self._match_text_seq("IAM_ROLE"):
    6780            expr.set("iam_role", self._parse_field())
    6781        if self._match_text_seq("REGION"):
    6782            expr.set("region", self._parse_field())
    6783
    6784        return expr
    6785
    6786    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    6787        return self._parse_field()
    6788
    6789    def _parse_copy(self) -> exp.Copy | exp.Command:
    6790        start = self._prev
    6791
    6792        self._match(TokenType.INTO)
    6793
    6794        this = (
    6795            self._parse_select(nested=True, parse_subquery_alias=False)
    6796            if self._match(TokenType.L_PAREN, advance=False)
    6797            else self._parse_table(schema=True)
    6798        )
    6799
    6800        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    6801
    6802        files = self._parse_csv(self._parse_file_location)
    6803        credentials = self._parse_credentials()
    6804
    6805        self._match_text_seq("WITH")
    6806
    6807        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    6808
    6809        # Fallback case
    6810        if self._curr:
    6811            return self._parse_as_command(start)
    6812
    6813        return self.expression(
    6814            exp.Copy,
    6815            this=this,
    6816            kind=kind,
    6817            credentials=credentials,
    6818            files=files,
    6819            params=params,
    6820        )

logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

    26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    27    if len(args) == 1 and args[0].is_star:
    28        return exp.StarMap(this=args[0])
    29
    30    keys = []
    31    values = []
    32    for i in range(0, len(args), 2):
    33        keys.append(args[i])
    34        values.append(args[i + 1])
    35
    36    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))

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

    39def build_like(args: t.List) -> exp.Escape | exp.Like:
    40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    41    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], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]: View Source

    44def binary_range_parser(
    45    expr_type: t.Type[exp.Expression], reverse_args: bool = False
    46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
    47    def _parse_binary_range(
    48        self: Parser, this: t.Optional[exp.Expression]
    49    ) -> t.Optional[exp.Expression]:
    50        expression = self._parse_bitwise()
    51        if reverse_args:
    52            this, expression = expression, this
    53        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
    54
    55    return _parse_binary_range

def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func: View Source

    58def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    59    # Default argument order is base, expression
    60    this = seq_get(args, 0)
    61    expression = seq_get(args, 1)
    62
    63    if expression:
    64        if not dialect.LOG_BASE_FIRST:
    65            this, expression = expression, this
    66        return exp.Log(this=this, expression=expression)
    67
    68    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)

def build_hex( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex: View Source

    71def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
    72    arg = seq_get(args, 0)
    73    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)

def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex: View Source

    76def build_lower(args: t.List) -> exp.Lower | exp.Hex:
    77    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
    78    arg = seq_get(args, 0)
    79    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)

def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex: View Source

    82def build_upper(args: t.List) -> exp.Upper | exp.Hex:
    83    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
    84    arg = seq_get(args, 0)
    85    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)

def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]: View Source

    88def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
    89    def _builder(args: t.List, dialect: Dialect) -> E:
    90        expression = expr_type(
    91            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
    92        )
    93        if len(args) > 2 and expr_type is exp.JSONExtract:
    94            expression.set("expressions", args[2:])
    95
    96        return expression
    97
    98    return _builder

def build_mod(args: List) -> sqlglot.expressions.Mod: View Source

    101def build_mod(args: t.List) -> exp.Mod:
    102    this = seq_get(args, 0)
    103    expression = seq_get(args, 1)
    104
    105    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
    106    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
    107    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
    108
    109    return exp.Mod(this=this, expression=expression)

class Parser: View Source

     122class Parser(metaclass=_Parser):
     123    """
     124    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     125
     126    Args:
     127        error_level: The desired error level.
     128            Default: ErrorLevel.IMMEDIATE
     129        error_message_context: The amount of context to capture from a query string when displaying
     130            the error message (in number of characters).
     131            Default: 100
     132        max_errors: Maximum number of error messages to include in a raised ParseError.
     133            This is only relevant if error_level is ErrorLevel.RAISE.
     134            Default: 3
     135    """
     136
     137    FUNCTIONS: t.Dict[str, t.Callable] = {
     138        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     139        "CONCAT": lambda args, dialect: exp.Concat(
     140            expressions=args,
     141            safe=not dialect.STRICT_STRING_CONCAT,
     142            coalesce=dialect.CONCAT_COALESCE,
     143        ),
     144        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     145            expressions=args,
     146            safe=not dialect.STRICT_STRING_CONCAT,
     147            coalesce=dialect.CONCAT_COALESCE,
     148        ),
     149        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     150            this=seq_get(args, 0),
     151            to=exp.DataType(this=exp.DataType.Type.TEXT),
     152        ),
     153        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     154        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     155        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     156        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     157        "LIKE": build_like,
     158        "LOG": build_logarithm,
     159        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     160        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     161        "MOD": build_mod,
     162        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     163            this=seq_get(args, 0),
     164            to=exp.DataType(this=exp.DataType.Type.TEXT),
     165        ),
     166        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     167            this=exp.Cast(
     168                this=seq_get(args, 0),
     169                to=exp.DataType(this=exp.DataType.Type.TEXT),
     170            ),
     171            start=exp.Literal.number(1),
     172            length=exp.Literal.number(10),
     173        ),
     174        "VAR_MAP": build_var_map,
     175        "LOWER": build_lower,
     176        "UPPER": build_upper,
     177        "HEX": build_hex,
     178        "TO_HEX": build_hex,
     179    }
     180
     181    NO_PAREN_FUNCTIONS = {
     182        TokenType.CURRENT_DATE: exp.CurrentDate,
     183        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     184        TokenType.CURRENT_TIME: exp.CurrentTime,
     185        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     186        TokenType.CURRENT_USER: exp.CurrentUser,
     187    }
     188
     189    STRUCT_TYPE_TOKENS = {
     190        TokenType.NESTED,
     191        TokenType.OBJECT,
     192        TokenType.STRUCT,
     193    }
     194
     195    NESTED_TYPE_TOKENS = {
     196        TokenType.ARRAY,
     197        TokenType.LIST,
     198        TokenType.LOWCARDINALITY,
     199        TokenType.MAP,
     200        TokenType.NULLABLE,
     201        *STRUCT_TYPE_TOKENS,
     202    }
     203
     204    ENUM_TYPE_TOKENS = {
     205        TokenType.ENUM,
     206        TokenType.ENUM8,
     207        TokenType.ENUM16,
     208    }
     209
     210    AGGREGATE_TYPE_TOKENS = {
     211        TokenType.AGGREGATEFUNCTION,
     212        TokenType.SIMPLEAGGREGATEFUNCTION,
     213    }
     214
     215    TYPE_TOKENS = {
     216        TokenType.BIT,
     217        TokenType.BOOLEAN,
     218        TokenType.TINYINT,
     219        TokenType.UTINYINT,
     220        TokenType.SMALLINT,
     221        TokenType.USMALLINT,
     222        TokenType.INT,
     223        TokenType.UINT,
     224        TokenType.BIGINT,
     225        TokenType.UBIGINT,
     226        TokenType.INT128,
     227        TokenType.UINT128,
     228        TokenType.INT256,
     229        TokenType.UINT256,
     230        TokenType.MEDIUMINT,
     231        TokenType.UMEDIUMINT,
     232        TokenType.FIXEDSTRING,
     233        TokenType.FLOAT,
     234        TokenType.DOUBLE,
     235        TokenType.CHAR,
     236        TokenType.NCHAR,
     237        TokenType.VARCHAR,
     238        TokenType.NVARCHAR,
     239        TokenType.BPCHAR,
     240        TokenType.TEXT,
     241        TokenType.MEDIUMTEXT,
     242        TokenType.LONGTEXT,
     243        TokenType.MEDIUMBLOB,
     244        TokenType.LONGBLOB,
     245        TokenType.BINARY,
     246        TokenType.VARBINARY,
     247        TokenType.JSON,
     248        TokenType.JSONB,
     249        TokenType.INTERVAL,
     250        TokenType.TINYBLOB,
     251        TokenType.TINYTEXT,
     252        TokenType.TIME,
     253        TokenType.TIMETZ,
     254        TokenType.TIMESTAMP,
     255        TokenType.TIMESTAMP_S,
     256        TokenType.TIMESTAMP_MS,
     257        TokenType.TIMESTAMP_NS,
     258        TokenType.TIMESTAMPTZ,
     259        TokenType.TIMESTAMPLTZ,
     260        TokenType.TIMESTAMPNTZ,
     261        TokenType.DATETIME,
     262        TokenType.DATETIME64,
     263        TokenType.DATE,
     264        TokenType.DATE32,
     265        TokenType.INT4RANGE,
     266        TokenType.INT4MULTIRANGE,
     267        TokenType.INT8RANGE,
     268        TokenType.INT8MULTIRANGE,
     269        TokenType.NUMRANGE,
     270        TokenType.NUMMULTIRANGE,
     271        TokenType.TSRANGE,
     272        TokenType.TSMULTIRANGE,
     273        TokenType.TSTZRANGE,
     274        TokenType.TSTZMULTIRANGE,
     275        TokenType.DATERANGE,
     276        TokenType.DATEMULTIRANGE,
     277        TokenType.DECIMAL,
     278        TokenType.UDECIMAL,
     279        TokenType.BIGDECIMAL,
     280        TokenType.UUID,
     281        TokenType.GEOGRAPHY,
     282        TokenType.GEOMETRY,
     283        TokenType.HLLSKETCH,
     284        TokenType.HSTORE,
     285        TokenType.PSEUDO_TYPE,
     286        TokenType.SUPER,
     287        TokenType.SERIAL,
     288        TokenType.SMALLSERIAL,
     289        TokenType.BIGSERIAL,
     290        TokenType.XML,
     291        TokenType.YEAR,
     292        TokenType.UNIQUEIDENTIFIER,
     293        TokenType.USERDEFINED,
     294        TokenType.MONEY,
     295        TokenType.SMALLMONEY,
     296        TokenType.ROWVERSION,
     297        TokenType.IMAGE,
     298        TokenType.VARIANT,
     299        TokenType.OBJECT,
     300        TokenType.OBJECT_IDENTIFIER,
     301        TokenType.INET,
     302        TokenType.IPADDRESS,
     303        TokenType.IPPREFIX,
     304        TokenType.IPV4,
     305        TokenType.IPV6,
     306        TokenType.UNKNOWN,
     307        TokenType.NULL,
     308        TokenType.NAME,
     309        TokenType.TDIGEST,
     310        *ENUM_TYPE_TOKENS,
     311        *NESTED_TYPE_TOKENS,
     312        *AGGREGATE_TYPE_TOKENS,
     313    }
     314
     315    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     316        TokenType.BIGINT: TokenType.UBIGINT,
     317        TokenType.INT: TokenType.UINT,
     318        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     319        TokenType.SMALLINT: TokenType.USMALLINT,
     320        TokenType.TINYINT: TokenType.UTINYINT,
     321        TokenType.DECIMAL: TokenType.UDECIMAL,
     322    }
     323
     324    SUBQUERY_PREDICATES = {
     325        TokenType.ANY: exp.Any,
     326        TokenType.ALL: exp.All,
     327        TokenType.EXISTS: exp.Exists,
     328        TokenType.SOME: exp.Any,
     329    }
     330
     331    RESERVED_TOKENS = {
     332        *Tokenizer.SINGLE_TOKENS.values(),
     333        TokenType.SELECT,
     334    } - {TokenType.IDENTIFIER}
     335
     336    DB_CREATABLES = {
     337        TokenType.DATABASE,
     338        TokenType.DICTIONARY,
     339        TokenType.MODEL,
     340        TokenType.SCHEMA,
     341        TokenType.SEQUENCE,
     342        TokenType.STORAGE_INTEGRATION,
     343        TokenType.TABLE,
     344        TokenType.TAG,
     345        TokenType.VIEW,
     346        TokenType.WAREHOUSE,
     347        TokenType.STREAMLIT,
     348    }
     349
     350    CREATABLES = {
     351        TokenType.COLUMN,
     352        TokenType.CONSTRAINT,
     353        TokenType.FOREIGN_KEY,
     354        TokenType.FUNCTION,
     355        TokenType.INDEX,
     356        TokenType.PROCEDURE,
     357        *DB_CREATABLES,
     358    }
     359
     360    # Tokens that can represent identifiers
     361    ID_VAR_TOKENS = {
     362        TokenType.VAR,
     363        TokenType.ANTI,
     364        TokenType.APPLY,
     365        TokenType.ASC,
     366        TokenType.ASOF,
     367        TokenType.AUTO_INCREMENT,
     368        TokenType.BEGIN,
     369        TokenType.BPCHAR,
     370        TokenType.CACHE,
     371        TokenType.CASE,
     372        TokenType.COLLATE,
     373        TokenType.COMMAND,
     374        TokenType.COMMENT,
     375        TokenType.COMMIT,
     376        TokenType.CONSTRAINT,
     377        TokenType.COPY,
     378        TokenType.DEFAULT,
     379        TokenType.DELETE,
     380        TokenType.DESC,
     381        TokenType.DESCRIBE,
     382        TokenType.DICTIONARY,
     383        TokenType.DIV,
     384        TokenType.END,
     385        TokenType.EXECUTE,
     386        TokenType.ESCAPE,
     387        TokenType.FALSE,
     388        TokenType.FIRST,
     389        TokenType.FILTER,
     390        TokenType.FINAL,
     391        TokenType.FORMAT,
     392        TokenType.FULL,
     393        TokenType.IDENTIFIER,
     394        TokenType.IS,
     395        TokenType.ISNULL,
     396        TokenType.INTERVAL,
     397        TokenType.KEEP,
     398        TokenType.KILL,
     399        TokenType.LEFT,
     400        TokenType.LOAD,
     401        TokenType.MERGE,
     402        TokenType.NATURAL,
     403        TokenType.NEXT,
     404        TokenType.OFFSET,
     405        TokenType.OPERATOR,
     406        TokenType.ORDINALITY,
     407        TokenType.OVERLAPS,
     408        TokenType.OVERWRITE,
     409        TokenType.PARTITION,
     410        TokenType.PERCENT,
     411        TokenType.PIVOT,
     412        TokenType.PRAGMA,
     413        TokenType.RANGE,
     414        TokenType.RECURSIVE,
     415        TokenType.REFERENCES,
     416        TokenType.REFRESH,
     417        TokenType.REPLACE,
     418        TokenType.RIGHT,
     419        TokenType.ROLLUP,
     420        TokenType.ROW,
     421        TokenType.ROWS,
     422        TokenType.SEMI,
     423        TokenType.SET,
     424        TokenType.SETTINGS,
     425        TokenType.SHOW,
     426        TokenType.TEMPORARY,
     427        TokenType.TOP,
     428        TokenType.TRUE,
     429        TokenType.TRUNCATE,
     430        TokenType.UNIQUE,
     431        TokenType.UNNEST,
     432        TokenType.UNPIVOT,
     433        TokenType.UPDATE,
     434        TokenType.USE,
     435        TokenType.VOLATILE,
     436        TokenType.WINDOW,
     437        *CREATABLES,
     438        *SUBQUERY_PREDICATES,
     439        *TYPE_TOKENS,
     440        *NO_PAREN_FUNCTIONS,
     441    }
     442
     443    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
     444
     445    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     446        TokenType.ANTI,
     447        TokenType.APPLY,
     448        TokenType.ASOF,
     449        TokenType.FULL,
     450        TokenType.LEFT,
     451        TokenType.LOCK,
     452        TokenType.NATURAL,
     453        TokenType.OFFSET,
     454        TokenType.RIGHT,
     455        TokenType.SEMI,
     456        TokenType.WINDOW,
     457    }
     458
     459    ALIAS_TOKENS = ID_VAR_TOKENS
     460
     461    ARRAY_CONSTRUCTORS = {
     462        "ARRAY": exp.Array,
     463        "LIST": exp.List,
     464    }
     465
     466    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     467
     468    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     469
     470    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     471
     472    FUNC_TOKENS = {
     473        TokenType.COLLATE,
     474        TokenType.COMMAND,
     475        TokenType.CURRENT_DATE,
     476        TokenType.CURRENT_DATETIME,
     477        TokenType.CURRENT_TIMESTAMP,
     478        TokenType.CURRENT_TIME,
     479        TokenType.CURRENT_USER,
     480        TokenType.FILTER,
     481        TokenType.FIRST,
     482        TokenType.FORMAT,
     483        TokenType.GLOB,
     484        TokenType.IDENTIFIER,
     485        TokenType.INDEX,
     486        TokenType.ISNULL,
     487        TokenType.ILIKE,
     488        TokenType.INSERT,
     489        TokenType.LIKE,
     490        TokenType.MERGE,
     491        TokenType.OFFSET,
     492        TokenType.PRIMARY_KEY,
     493        TokenType.RANGE,
     494        TokenType.REPLACE,
     495        TokenType.RLIKE,
     496        TokenType.ROW,
     497        TokenType.UNNEST,
     498        TokenType.VAR,
     499        TokenType.LEFT,
     500        TokenType.RIGHT,
     501        TokenType.SEQUENCE,
     502        TokenType.DATE,
     503        TokenType.DATETIME,
     504        TokenType.TABLE,
     505        TokenType.TIMESTAMP,
     506        TokenType.TIMESTAMPTZ,
     507        TokenType.TRUNCATE,
     508        TokenType.WINDOW,
     509        TokenType.XOR,
     510        *TYPE_TOKENS,
     511        *SUBQUERY_PREDICATES,
     512    }
     513
     514    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     515        TokenType.AND: exp.And,
     516    }
     517
     518    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     519        TokenType.COLON_EQ: exp.PropertyEQ,
     520    }
     521
     522    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     523        TokenType.OR: exp.Or,
     524    }
     525
     526    EQUALITY = {
     527        TokenType.EQ: exp.EQ,
     528        TokenType.NEQ: exp.NEQ,
     529        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     530    }
     531
     532    COMPARISON = {
     533        TokenType.GT: exp.GT,
     534        TokenType.GTE: exp.GTE,
     535        TokenType.LT: exp.LT,
     536        TokenType.LTE: exp.LTE,
     537    }
     538
     539    BITWISE = {
     540        TokenType.AMP: exp.BitwiseAnd,
     541        TokenType.CARET: exp.BitwiseXor,
     542        TokenType.PIPE: exp.BitwiseOr,
     543    }
     544
     545    TERM = {
     546        TokenType.DASH: exp.Sub,
     547        TokenType.PLUS: exp.Add,
     548        TokenType.MOD: exp.Mod,
     549        TokenType.COLLATE: exp.Collate,
     550    }
     551
     552    FACTOR = {
     553        TokenType.DIV: exp.IntDiv,
     554        TokenType.LR_ARROW: exp.Distance,
     555        TokenType.SLASH: exp.Div,
     556        TokenType.STAR: exp.Mul,
     557    }
     558
     559    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     560
     561    TIMES = {
     562        TokenType.TIME,
     563        TokenType.TIMETZ,
     564    }
     565
     566    TIMESTAMPS = {
     567        TokenType.TIMESTAMP,
     568        TokenType.TIMESTAMPTZ,
     569        TokenType.TIMESTAMPLTZ,
     570        *TIMES,
     571    }
     572
     573    SET_OPERATIONS = {
     574        TokenType.UNION,
     575        TokenType.INTERSECT,
     576        TokenType.EXCEPT,
     577    }
     578
     579    JOIN_METHODS = {
     580        TokenType.ASOF,
     581        TokenType.NATURAL,
     582        TokenType.POSITIONAL,
     583    }
     584
     585    JOIN_SIDES = {
     586        TokenType.LEFT,
     587        TokenType.RIGHT,
     588        TokenType.FULL,
     589    }
     590
     591    JOIN_KINDS = {
     592        TokenType.INNER,
     593        TokenType.OUTER,
     594        TokenType.CROSS,
     595        TokenType.SEMI,
     596        TokenType.ANTI,
     597    }
     598
     599    JOIN_HINTS: t.Set[str] = set()
     600
     601    LAMBDAS = {
     602        TokenType.ARROW: lambda self, expressions: self.expression(
     603            exp.Lambda,
     604            this=self._replace_lambda(
     605                self._parse_assignment(),
     606                expressions,
     607            ),
     608            expressions=expressions,
     609        ),
     610        TokenType.FARROW: lambda self, expressions: self.expression(
     611            exp.Kwarg,
     612            this=exp.var(expressions[0].name),
     613            expression=self._parse_assignment(),
     614        ),
     615    }
     616
     617    COLUMN_OPERATORS = {
     618        TokenType.DOT: None,
     619        TokenType.DCOLON: lambda self, this, to: self.expression(
     620            exp.Cast if self.STRICT_CAST else exp.TryCast,
     621            this=this,
     622            to=to,
     623        ),
     624        TokenType.ARROW: lambda self, this, path: self.expression(
     625            exp.JSONExtract,
     626            this=this,
     627            expression=self.dialect.to_json_path(path),
     628            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     629        ),
     630        TokenType.DARROW: lambda self, this, path: self.expression(
     631            exp.JSONExtractScalar,
     632            this=this,
     633            expression=self.dialect.to_json_path(path),
     634            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     635        ),
     636        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     637            exp.JSONBExtract,
     638            this=this,
     639            expression=path,
     640        ),
     641        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     642            exp.JSONBExtractScalar,
     643            this=this,
     644            expression=path,
     645        ),
     646        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     647            exp.JSONBContains,
     648            this=this,
     649            expression=key,
     650        ),
     651    }
     652
     653    EXPRESSION_PARSERS = {
     654        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     655        exp.Column: lambda self: self._parse_column(),
     656        exp.Condition: lambda self: self._parse_assignment(),
     657        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
     658        exp.Expression: lambda self: self._parse_expression(),
     659        exp.From: lambda self: self._parse_from(joins=True),
     660        exp.Group: lambda self: self._parse_group(),
     661        exp.Having: lambda self: self._parse_having(),
     662        exp.Identifier: lambda self: self._parse_id_var(),
     663        exp.Join: lambda self: self._parse_join(),
     664        exp.Lambda: lambda self: self._parse_lambda(),
     665        exp.Lateral: lambda self: self._parse_lateral(),
     666        exp.Limit: lambda self: self._parse_limit(),
     667        exp.Offset: lambda self: self._parse_offset(),
     668        exp.Order: lambda self: self._parse_order(),
     669        exp.Ordered: lambda self: self._parse_ordered(),
     670        exp.Properties: lambda self: self._parse_properties(),
     671        exp.Qualify: lambda self: self._parse_qualify(),
     672        exp.Returning: lambda self: self._parse_returning(),
     673        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     674        exp.Table: lambda self: self._parse_table_parts(),
     675        exp.TableAlias: lambda self: self._parse_table_alias(),
     676        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
     677        exp.Where: lambda self: self._parse_where(),
     678        exp.Window: lambda self: self._parse_named_window(),
     679        exp.With: lambda self: self._parse_with(),
     680        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     681    }
     682
     683    STATEMENT_PARSERS = {
     684        TokenType.ALTER: lambda self: self._parse_alter(),
     685        TokenType.BEGIN: lambda self: self._parse_transaction(),
     686        TokenType.CACHE: lambda self: self._parse_cache(),
     687        TokenType.COMMENT: lambda self: self._parse_comment(),
     688        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     689        TokenType.COPY: lambda self: self._parse_copy(),
     690        TokenType.CREATE: lambda self: self._parse_create(),
     691        TokenType.DELETE: lambda self: self._parse_delete(),
     692        TokenType.DESC: lambda self: self._parse_describe(),
     693        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     694        TokenType.DROP: lambda self: self._parse_drop(),
     695        TokenType.INSERT: lambda self: self._parse_insert(),
     696        TokenType.KILL: lambda self: self._parse_kill(),
     697        TokenType.LOAD: lambda self: self._parse_load(),
     698        TokenType.MERGE: lambda self: self._parse_merge(),
     699        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     700        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     701        TokenType.REFRESH: lambda self: self._parse_refresh(),
     702        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     703        TokenType.SET: lambda self: self._parse_set(),
     704        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     705        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     706        TokenType.UPDATE: lambda self: self._parse_update(),
     707        TokenType.USE: lambda self: self.expression(
     708            exp.Use,
     709            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
     710            this=self._parse_table(schema=False),
     711        ),
     712        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
     713    }
     714
     715    UNARY_PARSERS = {
     716        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     717        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     718        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     719        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     720        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     721        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     722    }
     723
     724    STRING_PARSERS = {
     725        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     726            exp.RawString, this=token.text
     727        ),
     728        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     729            exp.National, this=token.text
     730        ),
     731        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     732        TokenType.STRING: lambda self, token: self.expression(
     733            exp.Literal, this=token.text, is_string=True
     734        ),
     735        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     736            exp.UnicodeString,
     737            this=token.text,
     738            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     739        ),
     740    }
     741
     742    NUMERIC_PARSERS = {
     743        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     744        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     745        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
     746        TokenType.NUMBER: lambda self, token: self.expression(
     747            exp.Literal, this=token.text, is_string=False
     748        ),
     749    }
     750
     751    PRIMARY_PARSERS = {
     752        **STRING_PARSERS,
     753        **NUMERIC_PARSERS,
     754        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     755        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     756        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     757        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     758        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     759        TokenType.STAR: lambda self, _: self.expression(
     760            exp.Star,
     761            **{
     762                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
     763                "replace": self._parse_star_op("REPLACE"),
     764                "rename": self._parse_star_op("RENAME"),
     765            },
     766        ),
     767    }
     768
     769    PLACEHOLDER_PARSERS = {
     770        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     771        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     772        TokenType.COLON: lambda self: (
     773            self.expression(exp.Placeholder, this=self._prev.text)
     774            if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
     775            else None
     776        ),
     777    }
     778
     779    RANGE_PARSERS = {
     780        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     781        TokenType.GLOB: binary_range_parser(exp.Glob),
     782        TokenType.ILIKE: binary_range_parser(exp.ILike),
     783        TokenType.IN: lambda self, this: self._parse_in(this),
     784        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     785        TokenType.IS: lambda self, this: self._parse_is(this),
     786        TokenType.LIKE: binary_range_parser(exp.Like),
     787        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     788        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     789        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     790        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     791    }
     792
     793    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     794        "ALLOWED_VALUES": lambda self: self.expression(
     795            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     796        ),
     797        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     798        "AUTO": lambda self: self._parse_auto_property(),
     799        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     800        "BACKUP": lambda self: self.expression(
     801            exp.BackupProperty, this=self._parse_var(any_token=True)
     802        ),
     803        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     804        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     805        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     806        "CHECKSUM": lambda self: self._parse_checksum(),
     807        "CLUSTER BY": lambda self: self._parse_cluster(),
     808        "CLUSTERED": lambda self: self._parse_clustered_by(),
     809        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     810            exp.CollateProperty, **kwargs
     811        ),
     812        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     813        "CONTAINS": lambda self: self._parse_contains_property(),
     814        "COPY": lambda self: self._parse_copy_property(),
     815        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     816        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     817        "DEFINER": lambda self: self._parse_definer(),
     818        "DETERMINISTIC": lambda self: self.expression(
     819            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     820        ),
     821        "DISTKEY": lambda self: self._parse_distkey(),
     822        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     823        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     824        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     825        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     826        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     827        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     828        "FREESPACE": lambda self: self._parse_freespace(),
     829        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     830        "HEAP": lambda self: self.expression(exp.HeapProperty),
     831        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     832        "IMMUTABLE": lambda self: self.expression(
     833            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     834        ),
     835        "INHERITS": lambda self: self.expression(
     836            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     837        ),
     838        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     839        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     840        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     841        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     842        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     843        "LIKE": lambda self: self._parse_create_like(),
     844        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     845        "LOCK": lambda self: self._parse_locking(),
     846        "LOCKING": lambda self: self._parse_locking(),
     847        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     848        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     849        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     850        "MODIFIES": lambda self: self._parse_modifies_property(),
     851        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     852        "NO": lambda self: self._parse_no_property(),
     853        "ON": lambda self: self._parse_on_property(),
     854        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     855        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     856        "PARTITION": lambda self: self._parse_partitioned_of(),
     857        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     858        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     859        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     860        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
     861        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
     862        "READS": lambda self: self._parse_reads_property(),
     863        "REMOTE": lambda self: self._parse_remote_with_connection(),
     864        "RETURNS": lambda self: self._parse_returns(),
     865        "STRICT": lambda self: self.expression(exp.StrictProperty),
     866        "ROW": lambda self: self._parse_row(),
     867        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
     868        "SAMPLE": lambda self: self.expression(
     869            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
     870        ),
     871        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
     872        "SETTINGS": lambda self: self.expression(
     873            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
     874        ),
     875        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
     876        "SORTKEY": lambda self: self._parse_sortkey(),
     877        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
     878        "STABLE": lambda self: self.expression(
     879            exp.StabilityProperty, this=exp.Literal.string("STABLE")
     880        ),
     881        "STORED": lambda self: self._parse_stored(),
     882        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
     883        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
     884        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
     885        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
     886        "TO": lambda self: self._parse_to_table(),
     887        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
     888        "TRANSFORM": lambda self: self.expression(
     889            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
     890        ),
     891        "TTL": lambda self: self._parse_ttl(),
     892        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     893        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
     894        "VOLATILE": lambda self: self._parse_volatile_property(),
     895        "WITH": lambda self: self._parse_with_property(),
     896    }
     897
     898    CONSTRAINT_PARSERS = {
     899        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
     900        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
     901        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
     902        "CHARACTER SET": lambda self: self.expression(
     903            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
     904        ),
     905        "CHECK": lambda self: self.expression(
     906            exp.CheckColumnConstraint,
     907            this=self._parse_wrapped(self._parse_assignment),
     908            enforced=self._match_text_seq("ENFORCED"),
     909        ),
     910        "COLLATE": lambda self: self.expression(
     911            exp.CollateColumnConstraint, this=self._parse_var(any_token=True)
     912        ),
     913        "COMMENT": lambda self: self.expression(
     914            exp.CommentColumnConstraint, this=self._parse_string()
     915        ),
     916        "COMPRESS": lambda self: self._parse_compress(),
     917        "CLUSTERED": lambda self: self.expression(
     918            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
     919        ),
     920        "NONCLUSTERED": lambda self: self.expression(
     921            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
     922        ),
     923        "DEFAULT": lambda self: self.expression(
     924            exp.DefaultColumnConstraint, this=self._parse_bitwise()
     925        ),
     926        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
     927        "EPHEMERAL": lambda self: self.expression(
     928            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
     929        ),
     930        "EXCLUDE": lambda self: self.expression(
     931            exp.ExcludeColumnConstraint, this=self._parse_index_params()
     932        ),
     933        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
     934        "FORMAT": lambda self: self.expression(
     935            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
     936        ),
     937        "GENERATED": lambda self: self._parse_generated_as_identity(),
     938        "IDENTITY": lambda self: self._parse_auto_increment(),
     939        "INLINE": lambda self: self._parse_inline(),
     940        "LIKE": lambda self: self._parse_create_like(),
     941        "NOT": lambda self: self._parse_not_constraint(),
     942        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
     943        "ON": lambda self: (
     944            self._match(TokenType.UPDATE)
     945            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
     946        )
     947        or self.expression(exp.OnProperty, this=self._parse_id_var()),
     948        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
     949        "PERIOD": lambda self: self._parse_period_for_system_time(),
     950        "PRIMARY KEY": lambda self: self._parse_primary_key(),
     951        "REFERENCES": lambda self: self._parse_references(match=False),
     952        "TITLE": lambda self: self.expression(
     953            exp.TitleColumnConstraint, this=self._parse_var_or_string()
     954        ),
     955        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
     956        "UNIQUE": lambda self: self._parse_unique(),
     957        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
     958        "WITH": lambda self: self.expression(
     959            exp.Properties, expressions=self._parse_wrapped_properties()
     960        ),
     961    }
     962
     963    ALTER_PARSERS = {
     964        "ADD": lambda self: self._parse_alter_table_add(),
     965        "ALTER": lambda self: self._parse_alter_table_alter(),
     966        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
     967        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
     968        "DROP": lambda self: self._parse_alter_table_drop(),
     969        "RENAME": lambda self: self._parse_alter_table_rename(),
     970        "SET": lambda self: self._parse_alter_table_set(),
     971    }
     972
     973    ALTER_ALTER_PARSERS = {
     974        "DISTKEY": lambda self: self._parse_alter_diststyle(),
     975        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
     976        "SORTKEY": lambda self: self._parse_alter_sortkey(),
     977        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
     978    }
     979
     980    SCHEMA_UNNAMED_CONSTRAINTS = {
     981        "CHECK",
     982        "EXCLUDE",
     983        "FOREIGN KEY",
     984        "LIKE",
     985        "PERIOD",
     986        "PRIMARY KEY",
     987        "UNIQUE",
     988    }
     989
     990    NO_PAREN_FUNCTION_PARSERS = {
     991        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
     992        "CASE": lambda self: self._parse_case(),
     993        "IF": lambda self: self._parse_if(),
     994        "NEXT": lambda self: self._parse_next_value_for(),
     995    }
     996
     997    INVALID_FUNC_NAME_TOKENS = {
     998        TokenType.IDENTIFIER,
     999        TokenType.STRING,
    1000    }
    1001
    1002    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1003
    1004    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1005
    1006    FUNCTION_PARSERS = {
    1007        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1008        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1009        "DECODE": lambda self: self._parse_decode(),
    1010        "EXTRACT": lambda self: self._parse_extract(),
    1011        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1012        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1013        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1014        "JSON_TABLE": lambda self: self._parse_json_table(),
    1015        "MATCH": lambda self: self._parse_match_against(),
    1016        "OPENJSON": lambda self: self._parse_open_json(),
    1017        "POSITION": lambda self: self._parse_position(),
    1018        "PREDICT": lambda self: self._parse_predict(),
    1019        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1020        "STRING_AGG": lambda self: self._parse_string_agg(),
    1021        "SUBSTRING": lambda self: self._parse_substring(),
    1022        "TRIM": lambda self: self._parse_trim(),
    1023        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1024        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1025    }
    1026
    1027    QUERY_MODIFIER_PARSERS = {
    1028        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1029        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1030        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1031        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1032        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1033        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1034        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1035        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1036        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1037        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1038        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1039        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1040        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1041        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1042        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1043        TokenType.CLUSTER_BY: lambda self: (
    1044            "cluster",
    1045            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1046        ),
    1047        TokenType.DISTRIBUTE_BY: lambda self: (
    1048            "distribute",
    1049            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1050        ),
    1051        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1052        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1053        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1054    }
    1055
    1056    SET_PARSERS = {
    1057        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1058        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1059        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1060        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1061    }
    1062
    1063    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1064
    1065    TYPE_LITERAL_PARSERS = {
    1066        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1067    }
    1068
    1069    TYPE_CONVERTER: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1070
    1071    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1072
    1073    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1074
    1075    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1076    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1077        "ISOLATION": (
    1078            ("LEVEL", "REPEATABLE", "READ"),
    1079            ("LEVEL", "READ", "COMMITTED"),
    1080            ("LEVEL", "READ", "UNCOMITTED"),
    1081            ("LEVEL", "SERIALIZABLE"),
    1082        ),
    1083        "READ": ("WRITE", "ONLY"),
    1084    }
    1085
    1086    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1087        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1088    )
    1089    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1090
    1091    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1092        "SCALE": ("EXTEND", "NOEXTEND"),
    1093        "SHARD": ("EXTEND", "NOEXTEND"),
    1094        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1095        **dict.fromkeys(
    1096            (
    1097                "SESSION",
    1098                "GLOBAL",
    1099                "KEEP",
    1100                "NOKEEP",
    1101                "ORDER",
    1102                "NOORDER",
    1103                "NOCACHE",
    1104                "CYCLE",
    1105                "NOCYCLE",
    1106                "NOMINVALUE",
    1107                "NOMAXVALUE",
    1108                "NOSCALE",
    1109                "NOSHARD",
    1110            ),
    1111            tuple(),
    1112        ),
    1113    }
    1114
    1115    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1116
    1117    USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
    1118
    1119    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1120
    1121    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1122
    1123    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1124    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1125
    1126    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1127
    1128    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1129
    1130    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1131
    1132    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1133
    1134    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1135    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1136    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1137
    1138    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1139
    1140    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1141
    1142    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
    1143
    1144    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1145
    1146    NULL_TOKENS = {TokenType.NULL}
    1147
    1148    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
    1149
    1150    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1151
    1152    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1153
    1154    STRICT_CAST = True
    1155
    1156    PREFIXED_PIVOT_COLUMNS = False
    1157    IDENTIFY_PIVOT_STRINGS = False
    1158
    1159    LOG_DEFAULTS_TO_LN = False
    1160
    1161    # Whether ADD is present for each column added by ALTER TABLE
    1162    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1163
    1164    # Whether the table sample clause expects CSV syntax
    1165    TABLESAMPLE_CSV = False
    1166
    1167    # The default method used for table sampling
    1168    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1169
    1170    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1171    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1172
    1173    # Whether the TRIM function expects the characters to trim as its first argument
    1174    TRIM_PATTERN_FIRST = False
    1175
    1176    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1177    STRING_ALIASES = False
    1178
    1179    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1180    MODIFIERS_ATTACHED_TO_UNION = True
    1181    UNION_MODIFIERS = {"order", "limit", "offset"}
    1182
    1183    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1184    NO_PAREN_IF_COMMANDS = True
    1185
    1186    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1187    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1188
    1189    # Whether the `:` operator is used to extract a value from a JSON document
    1190    COLON_IS_JSON_EXTRACT = False
    1191
    1192    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1193    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1194    VALUES_FOLLOWED_BY_PAREN = True
    1195
    1196    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1197    SUPPORTS_IMPLICIT_UNNEST = False
    1198
    1199    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1200    INTERVAL_SPANS = True
    1201
    1202    # Whether a PARTITION clause can follow a table reference
    1203    SUPPORTS_PARTITION_SELECTION = False
    1204
    1205    __slots__ = (
    1206        "error_level",
    1207        "error_message_context",
    1208        "max_errors",
    1209        "dialect",
    1210        "sql",
    1211        "errors",
    1212        "_tokens",
    1213        "_index",
    1214        "_curr",
    1215        "_next",
    1216        "_prev",
    1217        "_prev_comments",
    1218    )
    1219
    1220    # Autofilled
    1221    SHOW_TRIE: t.Dict = {}
    1222    SET_TRIE: t.Dict = {}
    1223
    1224    def __init__(
    1225        self,
    1226        error_level: t.Optional[ErrorLevel] = None,
    1227        error_message_context: int = 100,
    1228        max_errors: int = 3,
    1229        dialect: DialectType = None,
    1230    ):
    1231        from sqlglot.dialects import Dialect
    1232
    1233        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1234        self.error_message_context = error_message_context
    1235        self.max_errors = max_errors
    1236        self.dialect = Dialect.get_or_raise(dialect)
    1237        self.reset()
    1238
    1239    def reset(self):
    1240        self.sql = ""
    1241        self.errors = []
    1242        self._tokens = []
    1243        self._index = 0
    1244        self._curr = None
    1245        self._next = None
    1246        self._prev = None
    1247        self._prev_comments = None
    1248
    1249    def parse(
    1250        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1251    ) -> t.List[t.Optional[exp.Expression]]:
    1252        """
    1253        Parses a list of tokens and returns a list of syntax trees, one tree
    1254        per parsed SQL statement.
    1255
    1256        Args:
    1257            raw_tokens: The list of tokens.
    1258            sql: The original SQL string, used to produce helpful debug messages.
    1259
    1260        Returns:
    1261            The list of the produced syntax trees.
    1262        """
    1263        return self._parse(
    1264            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1265        )
    1266
    1267    def parse_into(
    1268        self,
    1269        expression_types: exp.IntoType,
    1270        raw_tokens: t.List[Token],
    1271        sql: t.Optional[str] = None,
    1272    ) -> t.List[t.Optional[exp.Expression]]:
    1273        """
    1274        Parses a list of tokens into a given Expression type. If a collection of Expression
    1275        types is given instead, this method will try to parse the token list into each one
    1276        of them, stopping at the first for which the parsing succeeds.
    1277
    1278        Args:
    1279            expression_types: The expression type(s) to try and parse the token list into.
    1280            raw_tokens: The list of tokens.
    1281            sql: The original SQL string, used to produce helpful debug messages.
    1282
    1283        Returns:
    1284            The target Expression.
    1285        """
    1286        errors = []
    1287        for expression_type in ensure_list(expression_types):
    1288            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1289            if not parser:
    1290                raise TypeError(f"No parser registered for {expression_type}")
    1291
    1292            try:
    1293                return self._parse(parser, raw_tokens, sql)
    1294            except ParseError as e:
    1295                e.errors[0]["into_expression"] = expression_type
    1296                errors.append(e)
    1297
    1298        raise ParseError(
    1299            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1300            errors=merge_errors(errors),
    1301        ) from errors[-1]
    1302
    1303    def _parse(
    1304        self,
    1305        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1306        raw_tokens: t.List[Token],
    1307        sql: t.Optional[str] = None,
    1308    ) -> t.List[t.Optional[exp.Expression]]:
    1309        self.reset()
    1310        self.sql = sql or ""
    1311
    1312        total = len(raw_tokens)
    1313        chunks: t.List[t.List[Token]] = [[]]
    1314
    1315        for i, token in enumerate(raw_tokens):
    1316            if token.token_type == TokenType.SEMICOLON:
    1317                if token.comments:
    1318                    chunks.append([token])
    1319
    1320                if i < total - 1:
    1321                    chunks.append([])
    1322            else:
    1323                chunks[-1].append(token)
    1324
    1325        expressions = []
    1326
    1327        for tokens in chunks:
    1328            self._index = -1
    1329            self._tokens = tokens
    1330            self._advance()
    1331
    1332            expressions.append(parse_method(self))
    1333
    1334            if self._index < len(self._tokens):
    1335                self.raise_error("Invalid expression / Unexpected token")
    1336
    1337            self.check_errors()
    1338
    1339        return expressions
    1340
    1341    def check_errors(self) -> None:
    1342        """Logs or raises any found errors, depending on the chosen error level setting."""
    1343        if self.error_level == ErrorLevel.WARN:
    1344            for error in self.errors:
    1345                logger.error(str(error))
    1346        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1347            raise ParseError(
    1348                concat_messages(self.errors, self.max_errors),
    1349                errors=merge_errors(self.errors),
    1350            )
    1351
    1352    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1353        """
    1354        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1355        error level setting.
    1356        """
    1357        token = token or self._curr or self._prev or Token.string("")
    1358        start = token.start
    1359        end = token.end + 1
    1360        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1361        highlight = self.sql[start:end]
    1362        end_context = self.sql[end : end + self.error_message_context]
    1363
    1364        error = ParseError.new(
    1365            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1366            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1367            description=message,
    1368            line=token.line,
    1369            col=token.col,
    1370            start_context=start_context,
    1371            highlight=highlight,
    1372            end_context=end_context,
    1373        )
    1374
    1375        if self.error_level == ErrorLevel.IMMEDIATE:
    1376            raise error
    1377
    1378        self.errors.append(error)
    1379
    1380    def expression(
    1381        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1382    ) -> E:
    1383        """
    1384        Creates a new, validated Expression.
    1385
    1386        Args:
    1387            exp_class: The expression class to instantiate.
    1388            comments: An optional list of comments to attach to the expression.
    1389            kwargs: The arguments to set for the expression along with their respective values.
    1390
    1391        Returns:
    1392            The target expression.
    1393        """
    1394        instance = exp_class(**kwargs)
    1395        instance.add_comments(comments) if comments else self._add_comments(instance)
    1396        return self.validate_expression(instance)
    1397
    1398    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1399        if expression and self._prev_comments:
    1400            expression.add_comments(self._prev_comments)
    1401            self._prev_comments = None
    1402
    1403    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1404        """
    1405        Validates an Expression, making sure that all its mandatory arguments are set.
    1406
    1407        Args:
    1408            expression: The expression to validate.
    1409            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1410
    1411        Returns:
    1412            The validated expression.
    1413        """
    1414        if self.error_level != ErrorLevel.IGNORE:
    1415            for error_message in expression.error_messages(args):
    1416                self.raise_error(error_message)
    1417
    1418        return expression
    1419
    1420    def _find_sql(self, start: Token, end: Token) -> str:
    1421        return self.sql[start.start : end.end + 1]
    1422
    1423    def _is_connected(self) -> bool:
    1424        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1425
    1426    def _advance(self, times: int = 1) -> None:
    1427        self._index += times
    1428        self._curr = seq_get(self._tokens, self._index)
    1429        self._next = seq_get(self._tokens, self._index + 1)
    1430
    1431        if self._index > 0:
    1432            self._prev = self._tokens[self._index - 1]
    1433            self._prev_comments = self._prev.comments
    1434        else:
    1435            self._prev = None
    1436            self._prev_comments = None
    1437
    1438    def _retreat(self, index: int) -> None:
    1439        if index != self._index:
    1440            self._advance(index - self._index)
    1441
    1442    def _warn_unsupported(self) -> None:
    1443        if len(self._tokens) <= 1:
    1444            return
    1445
    1446        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1447        # interested in emitting a warning for the one being currently processed.
    1448        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1449
    1450        logger.warning(
    1451            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1452        )
    1453
    1454    def _parse_command(self) -> exp.Command:
    1455        self._warn_unsupported()
    1456        return self.expression(
    1457            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
    1458        )
    1459
    1460    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1461        """
    1462        Attemps to backtrack if a parse function that contains a try/catch internally raises an error. This behavior can
    1463        be different depending on the uset-set ErrorLevel, so _try_parse aims to solve this by setting & resetting
    1464        the parser state accordingly
    1465        """
    1466        index = self._index
    1467        error_level = self.error_level
    1468
    1469        self.error_level = ErrorLevel.IMMEDIATE
    1470        try:
    1471            this = parse_method()
    1472        except ParseError:
    1473            this = None
    1474        finally:
    1475            if not this or retreat:
    1476                self._retreat(index)
    1477            self.error_level = error_level
    1478
    1479        return this
    1480
    1481    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1482        start = self._prev
    1483        exists = self._parse_exists() if allow_exists else None
    1484
    1485        self._match(TokenType.ON)
    1486
    1487        materialized = self._match_text_seq("MATERIALIZED")
    1488        kind = self._match_set(self.CREATABLES) and self._prev
    1489        if not kind:
    1490            return self._parse_as_command(start)
    1491
    1492        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1493            this = self._parse_user_defined_function(kind=kind.token_type)
    1494        elif kind.token_type == TokenType.TABLE:
    1495            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1496        elif kind.token_type == TokenType.COLUMN:
    1497            this = self._parse_column()
    1498        else:
    1499            this = self._parse_id_var()
    1500
    1501        self._match(TokenType.IS)
    1502
    1503        return self.expression(
    1504            exp.Comment,
    1505            this=this,
    1506            kind=kind.text,
    1507            expression=self._parse_string(),
    1508            exists=exists,
    1509            materialized=materialized,
    1510        )
    1511
    1512    def _parse_to_table(
    1513        self,
    1514    ) -> exp.ToTableProperty:
    1515        table = self._parse_table_parts(schema=True)
    1516        return self.expression(exp.ToTableProperty, this=table)
    1517
    1518    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1519    def _parse_ttl(self) -> exp.Expression:
    1520        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1521            this = self._parse_bitwise()
    1522
    1523            if self._match_text_seq("DELETE"):
    1524                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1525            if self._match_text_seq("RECOMPRESS"):
    1526                return self.expression(
    1527                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1528                )
    1529            if self._match_text_seq("TO", "DISK"):
    1530                return self.expression(
    1531                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1532                )
    1533            if self._match_text_seq("TO", "VOLUME"):
    1534                return self.expression(
    1535                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1536                )
    1537
    1538            return this
    1539
    1540        expressions = self._parse_csv(_parse_ttl_action)
    1541        where = self._parse_where()
    1542        group = self._parse_group()
    1543
    1544        aggregates = None
    1545        if group and self._match(TokenType.SET):
    1546            aggregates = self._parse_csv(self._parse_set_item)
    1547
    1548        return self.expression(
    1549            exp.MergeTreeTTL,
    1550            expressions=expressions,
    1551            where=where,
    1552            group=group,
    1553            aggregates=aggregates,
    1554        )
    1555
    1556    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1557        if self._curr is None:
    1558            return None
    1559
    1560        if self._match_set(self.STATEMENT_PARSERS):
    1561            return self.STATEMENT_PARSERS[self._prev.token_type](self)
    1562
    1563        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1564            return self._parse_command()
    1565
    1566        expression = self._parse_expression()
    1567        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1568        return self._parse_query_modifiers(expression)
    1569
    1570    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1571        start = self._prev
    1572        temporary = self._match(TokenType.TEMPORARY)
    1573        materialized = self._match_text_seq("MATERIALIZED")
    1574
    1575        kind = self._match_set(self.CREATABLES) and self._prev.text
    1576        if not kind:
    1577            return self._parse_as_command(start)
    1578
    1579        if_exists = exists or self._parse_exists()
    1580        table = self._parse_table_parts(
    1581            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1582        )
    1583
    1584        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1585
    1586        if self._match(TokenType.L_PAREN, advance=False):
    1587            expressions = self._parse_wrapped_csv(self._parse_types)
    1588        else:
    1589            expressions = None
    1590
    1591        return self.expression(
    1592            exp.Drop,
    1593            comments=start.comments,
    1594            exists=if_exists,
    1595            this=table,
    1596            expressions=expressions,
    1597            kind=kind.upper(),
    1598            temporary=temporary,
    1599            materialized=materialized,
    1600            cascade=self._match_text_seq("CASCADE"),
    1601            constraints=self._match_text_seq("CONSTRAINTS"),
    1602            purge=self._match_text_seq("PURGE"),
    1603            cluster=cluster,
    1604        )
    1605
    1606    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1607        return (
    1608            self._match_text_seq("IF")
    1609            and (not not_ or self._match(TokenType.NOT))
    1610            and self._match(TokenType.EXISTS)
    1611        )
    1612
    1613    def _parse_create(self) -> exp.Create | exp.Command:
    1614        # Note: this can't be None because we've matched a statement parser
    1615        start = self._prev
    1616        comments = self._prev_comments
    1617
    1618        replace = (
    1619            start.token_type == TokenType.REPLACE
    1620            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1621            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1622        )
    1623
    1624        unique = self._match(TokenType.UNIQUE)
    1625
    1626        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1627            self._advance()
    1628
    1629        properties = None
    1630        create_token = self._match_set(self.CREATABLES) and self._prev
    1631
    1632        if not create_token:
    1633            # exp.Properties.Location.POST_CREATE
    1634            properties = self._parse_properties()
    1635            create_token = self._match_set(self.CREATABLES) and self._prev
    1636
    1637            if not properties or not create_token:
    1638                return self._parse_as_command(start)
    1639
    1640        exists = self._parse_exists(not_=True)
    1641        this = None
    1642        expression: t.Optional[exp.Expression] = None
    1643        indexes = None
    1644        no_schema_binding = None
    1645        begin = None
    1646        end = None
    1647        clone = None
    1648
    1649        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1650            nonlocal properties
    1651            if properties and temp_props:
    1652                properties.expressions.extend(temp_props.expressions)
    1653            elif temp_props:
    1654                properties = temp_props
    1655
    1656        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1657            this = self._parse_user_defined_function(kind=create_token.token_type)
    1658
    1659            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1660            extend_props(self._parse_properties())
    1661
    1662            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1663            extend_props(self._parse_properties())
    1664
    1665            if not expression:
    1666                if self._match(TokenType.COMMAND):
    1667                    expression = self._parse_as_command(self._prev)
    1668                else:
    1669                    begin = self._match(TokenType.BEGIN)
    1670                    return_ = self._match_text_seq("RETURN")
    1671
    1672                    if self._match(TokenType.STRING, advance=False):
    1673                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1674                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1675                        expression = self._parse_string()
    1676                        extend_props(self._parse_properties())
    1677                    else:
    1678                        expression = self._parse_statement()
    1679
    1680                    end = self._match_text_seq("END")
    1681
    1682                    if return_:
    1683                        expression = self.expression(exp.Return, this=expression)
    1684        elif create_token.token_type == TokenType.INDEX:
    1685            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1686            if not self._match(TokenType.ON):
    1687                index = self._parse_id_var()
    1688                anonymous = False
    1689            else:
    1690                index = None
    1691                anonymous = True
    1692
    1693            this = self._parse_index(index=index, anonymous=anonymous)
    1694        elif create_token.token_type in self.DB_CREATABLES:
    1695            table_parts = self._parse_table_parts(
    1696                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1697            )
    1698
    1699            # exp.Properties.Location.POST_NAME
    1700            self._match(TokenType.COMMA)
    1701            extend_props(self._parse_properties(before=True))
    1702
    1703            this = self._parse_schema(this=table_parts)
    1704
    1705            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    1706            extend_props(self._parse_properties())
    1707
    1708            self._match(TokenType.ALIAS)
    1709            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    1710                # exp.Properties.Location.POST_ALIAS
    1711                extend_props(self._parse_properties())
    1712
    1713            if create_token.token_type == TokenType.SEQUENCE:
    1714                expression = self._parse_types()
    1715                extend_props(self._parse_properties())
    1716            else:
    1717                expression = self._parse_ddl_select()
    1718
    1719            if create_token.token_type == TokenType.TABLE:
    1720                # exp.Properties.Location.POST_EXPRESSION
    1721                extend_props(self._parse_properties())
    1722
    1723                indexes = []
    1724                while True:
    1725                    index = self._parse_index()
    1726
    1727                    # exp.Properties.Location.POST_INDEX
    1728                    extend_props(self._parse_properties())
    1729
    1730                    if not index:
    1731                        break
    1732                    else:
    1733                        self._match(TokenType.COMMA)
    1734                        indexes.append(index)
    1735            elif create_token.token_type == TokenType.VIEW:
    1736                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    1737                    no_schema_binding = True
    1738
    1739            shallow = self._match_text_seq("SHALLOW")
    1740
    1741            if self._match_texts(self.CLONE_KEYWORDS):
    1742                copy = self._prev.text.lower() == "copy"
    1743                clone = self.expression(
    1744                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    1745                )
    1746
    1747        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    1748            return self._parse_as_command(start)
    1749
    1750        return self.expression(
    1751            exp.Create,
    1752            comments=comments,
    1753            this=this,
    1754            kind=create_token.text.upper(),
    1755            replace=replace,
    1756            unique=unique,
    1757            expression=expression,
    1758            exists=exists,
    1759            properties=properties,
    1760            indexes=indexes,
    1761            no_schema_binding=no_schema_binding,
    1762            begin=begin,
    1763            end=end,
    1764            clone=clone,
    1765        )
    1766
    1767    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    1768        seq = exp.SequenceProperties()
    1769
    1770        options = []
    1771        index = self._index
    1772
    1773        while self._curr:
    1774            self._match(TokenType.COMMA)
    1775            if self._match_text_seq("INCREMENT"):
    1776                self._match_text_seq("BY")
    1777                self._match_text_seq("=")
    1778                seq.set("increment", self._parse_term())
    1779            elif self._match_text_seq("MINVALUE"):
    1780                seq.set("minvalue", self._parse_term())
    1781            elif self._match_text_seq("MAXVALUE"):
    1782                seq.set("maxvalue", self._parse_term())
    1783            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    1784                self._match_text_seq("=")
    1785                seq.set("start", self._parse_term())
    1786            elif self._match_text_seq("CACHE"):
    1787                # T-SQL allows empty CACHE which is initialized dynamically
    1788                seq.set("cache", self._parse_number() or True)
    1789            elif self._match_text_seq("OWNED", "BY"):
    1790                # "OWNED BY NONE" is the default
    1791                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    1792            else:
    1793                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    1794                if opt:
    1795                    options.append(opt)
    1796                else:
    1797                    break
    1798
    1799        seq.set("options", options if options else None)
    1800        return None if self._index == index else seq
    1801
    1802    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    1803        # only used for teradata currently
    1804        self._match(TokenType.COMMA)
    1805
    1806        kwargs = {
    1807            "no": self._match_text_seq("NO"),
    1808            "dual": self._match_text_seq("DUAL"),
    1809            "before": self._match_text_seq("BEFORE"),
    1810            "default": self._match_text_seq("DEFAULT"),
    1811            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    1812            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    1813            "after": self._match_text_seq("AFTER"),
    1814            "minimum": self._match_texts(("MIN", "MINIMUM")),
    1815            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    1816        }
    1817
    1818        if self._match_texts(self.PROPERTY_PARSERS):
    1819            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    1820            try:
    1821                return parser(self, **{k: v for k, v in kwargs.items() if v})
    1822            except TypeError:
    1823                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    1824
    1825        return None
    1826
    1827    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    1828        return self._parse_wrapped_csv(self._parse_property)
    1829
    1830    def _parse_property(self) -> t.Optional[exp.Expression]:
    1831        if self._match_texts(self.PROPERTY_PARSERS):
    1832            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    1833
    1834        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    1835            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    1836
    1837        if self._match_text_seq("COMPOUND", "SORTKEY"):
    1838            return self._parse_sortkey(compound=True)
    1839
    1840        if self._match_text_seq("SQL", "SECURITY"):
    1841            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    1842
    1843        index = self._index
    1844        key = self._parse_column()
    1845
    1846        if not self._match(TokenType.EQ):
    1847            self._retreat(index)
    1848            return self._parse_sequence_properties()
    1849
    1850        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    1851        if isinstance(key, exp.Column):
    1852            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    1853
    1854        value = self._parse_bitwise() or self._parse_var(any_token=True)
    1855
    1856        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    1857        if isinstance(value, exp.Column):
    1858            value = exp.var(value.name)
    1859
    1860        return self.expression(exp.Property, this=key, value=value)
    1861
    1862    def _parse_stored(self) -> exp.FileFormatProperty:
    1863        self._match(TokenType.ALIAS)
    1864
    1865        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    1866        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    1867
    1868        return self.expression(
    1869            exp.FileFormatProperty,
    1870            this=(
    1871                self.expression(
    1872                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
    1873                )
    1874                if input_format or output_format
    1875                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    1876            ),
    1877        )
    1878
    1879    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    1880        field = self._parse_field()
    1881        if isinstance(field, exp.Identifier) and not field.quoted:
    1882            field = exp.var(field)
    1883
    1884        return field
    1885
    1886    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    1887        self._match(TokenType.EQ)
    1888        self._match(TokenType.ALIAS)
    1889
    1890        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    1891
    1892    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    1893        properties = []
    1894        while True:
    1895            if before:
    1896                prop = self._parse_property_before()
    1897            else:
    1898                prop = self._parse_property()
    1899            if not prop:
    1900                break
    1901            for p in ensure_list(prop):
    1902                properties.append(p)
    1903
    1904        if properties:
    1905            return self.expression(exp.Properties, expressions=properties)
    1906
    1907        return None
    1908
    1909    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    1910        return self.expression(
    1911            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    1912        )
    1913
    1914    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    1915        if self._index >= 2:
    1916            pre_volatile_token = self._tokens[self._index - 2]
    1917        else:
    1918            pre_volatile_token = None
    1919
    1920        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    1921            return exp.VolatileProperty()
    1922
    1923        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    1924
    1925    def _parse_retention_period(self) -> exp.Var:
    1926        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    1927        number = self._parse_number()
    1928        number_str = f"{number} " if number else ""
    1929        unit = self._parse_var(any_token=True)
    1930        return exp.var(f"{number_str}{unit}")
    1931
    1932    def _parse_system_versioning_property(
    1933        self, with_: bool = False
    1934    ) -> exp.WithSystemVersioningProperty:
    1935        self._match(TokenType.EQ)
    1936        prop = self.expression(
    1937            exp.WithSystemVersioningProperty,
    1938            **{  # type: ignore
    1939                "on": True,
    1940                "with": with_,
    1941            },
    1942        )
    1943
    1944        if self._match_text_seq("OFF"):
    1945            prop.set("on", False)
    1946            return prop
    1947
    1948        self._match(TokenType.ON)
    1949        if self._match(TokenType.L_PAREN):
    1950            while self._curr and not self._match(TokenType.R_PAREN):
    1951                if self._match_text_seq("HISTORY_TABLE", "="):
    1952                    prop.set("this", self._parse_table_parts())
    1953                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    1954                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    1955                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    1956                    prop.set("retention_period", self._parse_retention_period())
    1957
    1958                self._match(TokenType.COMMA)
    1959
    1960        return prop
    1961
    1962    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    1963        self._match(TokenType.EQ)
    1964        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    1965        prop = self.expression(exp.DataDeletionProperty, on=on)
    1966
    1967        if self._match(TokenType.L_PAREN):
    1968            while self._curr and not self._match(TokenType.R_PAREN):
    1969                if self._match_text_seq("FILTER_COLUMN", "="):
    1970                    prop.set("filter_column", self._parse_column())
    1971                elif self._match_text_seq("RETENTION_PERIOD", "="):
    1972                    prop.set("retention_period", self._parse_retention_period())
    1973
    1974                self._match(TokenType.COMMA)
    1975
    1976        return prop
    1977
    1978    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    1979        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    1980            prop = self._parse_system_versioning_property(with_=True)
    1981            self._match_r_paren()
    1982            return prop
    1983
    1984        if self._match(TokenType.L_PAREN, advance=False):
    1985            return self._parse_wrapped_properties()
    1986
    1987        if self._match_text_seq("JOURNAL"):
    1988            return self._parse_withjournaltable()
    1989
    1990        if self._match_texts(self.VIEW_ATTRIBUTES):
    1991            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    1992
    1993        if self._match_text_seq("DATA"):
    1994            return self._parse_withdata(no=False)
    1995        elif self._match_text_seq("NO", "DATA"):
    1996            return self._parse_withdata(no=True)
    1997
    1998        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    1999            return self._parse_serde_properties(with_=True)
    2000
    2001        if not self._next:
    2002            return None
    2003
    2004        return self._parse_withisolatedloading()
    2005
    2006    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2007    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2008        self._match(TokenType.EQ)
    2009
    2010        user = self._parse_id_var()
    2011        self._match(TokenType.PARAMETER)
    2012        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2013
    2014        if not user or not host:
    2015            return None
    2016
    2017        return exp.DefinerProperty(this=f"{user}@{host}")
    2018
    2019    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2020        self._match(TokenType.TABLE)
    2021        self._match(TokenType.EQ)
    2022        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2023
    2024    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2025        return self.expression(exp.LogProperty, no=no)
    2026
    2027    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2028        return self.expression(exp.JournalProperty, **kwargs)
    2029
    2030    def _parse_checksum(self) -> exp.ChecksumProperty:
    2031        self._match(TokenType.EQ)
    2032
    2033        on = None
    2034        if self._match(TokenType.ON):
    2035            on = True
    2036        elif self._match_text_seq("OFF"):
    2037            on = False
    2038
    2039        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2040
    2041    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2042        return self.expression(
    2043            exp.Cluster,
    2044            expressions=(
    2045                self._parse_wrapped_csv(self._parse_ordered)
    2046                if wrapped
    2047                else self._parse_csv(self._parse_ordered)
    2048            ),
    2049        )
    2050
    2051    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2052        self._match_text_seq("BY")
    2053
    2054        self._match_l_paren()
    2055        expressions = self._parse_csv(self._parse_column)
    2056        self._match_r_paren()
    2057
    2058        if self._match_text_seq("SORTED", "BY"):
    2059            self._match_l_paren()
    2060            sorted_by = self._parse_csv(self._parse_ordered)
    2061            self._match_r_paren()
    2062        else:
    2063            sorted_by = None
    2064
    2065        self._match(TokenType.INTO)
    2066        buckets = self._parse_number()
    2067        self._match_text_seq("BUCKETS")
    2068
    2069        return self.expression(
    2070            exp.ClusteredByProperty,
    2071            expressions=expressions,
    2072            sorted_by=sorted_by,
    2073            buckets=buckets,
    2074        )
    2075
    2076    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2077        if not self._match_text_seq("GRANTS"):
    2078            self._retreat(self._index - 1)
    2079            return None
    2080
    2081        return self.expression(exp.CopyGrantsProperty)
    2082
    2083    def _parse_freespace(self) -> exp.FreespaceProperty:
    2084        self._match(TokenType.EQ)
    2085        return self.expression(
    2086            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2087        )
    2088
    2089    def _parse_mergeblockratio(
    2090        self, no: bool = False, default: bool = False
    2091    ) -> exp.MergeBlockRatioProperty:
    2092        if self._match(TokenType.EQ):
    2093            return self.expression(
    2094                exp.MergeBlockRatioProperty,
    2095                this=self._parse_number(),
    2096                percent=self._match(TokenType.PERCENT),
    2097            )
    2098
    2099        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2100
    2101    def _parse_datablocksize(
    2102        self,
    2103        default: t.Optional[bool] = None,
    2104        minimum: t.Optional[bool] = None,
    2105        maximum: t.Optional[bool] = None,
    2106    ) -> exp.DataBlocksizeProperty:
    2107        self._match(TokenType.EQ)
    2108        size = self._parse_number()
    2109
    2110        units = None
    2111        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2112            units = self._prev.text
    2113
    2114        return self.expression(
    2115            exp.DataBlocksizeProperty,
    2116            size=size,
    2117            units=units,
    2118            default=default,
    2119            minimum=minimum,
    2120            maximum=maximum,
    2121        )
    2122
    2123    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2124        self._match(TokenType.EQ)
    2125        always = self._match_text_seq("ALWAYS")
    2126        manual = self._match_text_seq("MANUAL")
    2127        never = self._match_text_seq("NEVER")
    2128        default = self._match_text_seq("DEFAULT")
    2129
    2130        autotemp = None
    2131        if self._match_text_seq("AUTOTEMP"):
    2132            autotemp = self._parse_schema()
    2133
    2134        return self.expression(
    2135            exp.BlockCompressionProperty,
    2136            always=always,
    2137            manual=manual,
    2138            never=never,
    2139            default=default,
    2140            autotemp=autotemp,
    2141        )
    2142
    2143    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2144        index = self._index
    2145        no = self._match_text_seq("NO")
    2146        concurrent = self._match_text_seq("CONCURRENT")
    2147
    2148        if not self._match_text_seq("ISOLATED", "LOADING"):
    2149            self._retreat(index)
    2150            return None
    2151
    2152        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2153        return self.expression(
    2154            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2155        )
    2156
    2157    def _parse_locking(self) -> exp.LockingProperty:
    2158        if self._match(TokenType.TABLE):
    2159            kind = "TABLE"
    2160        elif self._match(TokenType.VIEW):
    2161            kind = "VIEW"
    2162        elif self._match(TokenType.ROW):
    2163            kind = "ROW"
    2164        elif self._match_text_seq("DATABASE"):
    2165            kind = "DATABASE"
    2166        else:
    2167            kind = None
    2168
    2169        if kind in ("DATABASE", "TABLE", "VIEW"):
    2170            this = self._parse_table_parts()
    2171        else:
    2172            this = None
    2173
    2174        if self._match(TokenType.FOR):
    2175            for_or_in = "FOR"
    2176        elif self._match(TokenType.IN):
    2177            for_or_in = "IN"
    2178        else:
    2179            for_or_in = None
    2180
    2181        if self._match_text_seq("ACCESS"):
    2182            lock_type = "ACCESS"
    2183        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2184            lock_type = "EXCLUSIVE"
    2185        elif self._match_text_seq("SHARE"):
    2186            lock_type = "SHARE"
    2187        elif self._match_text_seq("READ"):
    2188            lock_type = "READ"
    2189        elif self._match_text_seq("WRITE"):
    2190            lock_type = "WRITE"
    2191        elif self._match_text_seq("CHECKSUM"):
    2192            lock_type = "CHECKSUM"
    2193        else:
    2194            lock_type = None
    2195
    2196        override = self._match_text_seq("OVERRIDE")
    2197
    2198        return self.expression(
    2199            exp.LockingProperty,
    2200            this=this,
    2201            kind=kind,
    2202            for_or_in=for_or_in,
    2203            lock_type=lock_type,
    2204            override=override,
    2205        )
    2206
    2207    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2208        if self._match(TokenType.PARTITION_BY):
    2209            return self._parse_csv(self._parse_assignment)
    2210        return []
    2211
    2212    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2213        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2214            if self._match_text_seq("MINVALUE"):
    2215                return exp.var("MINVALUE")
    2216            if self._match_text_seq("MAXVALUE"):
    2217                return exp.var("MAXVALUE")
    2218            return self._parse_bitwise()
    2219
    2220        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2221        expression = None
    2222        from_expressions = None
    2223        to_expressions = None
    2224
    2225        if self._match(TokenType.IN):
    2226            this = self._parse_wrapped_csv(self._parse_bitwise)
    2227        elif self._match(TokenType.FROM):
    2228            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2229            self._match_text_seq("TO")
    2230            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2231        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2232            this = self._parse_number()
    2233            self._match_text_seq(",", "REMAINDER")
    2234            expression = self._parse_number()
    2235            self._match_r_paren()
    2236        else:
    2237            self.raise_error("Failed to parse partition bound spec.")
    2238
    2239        return self.expression(
    2240            exp.PartitionBoundSpec,
    2241            this=this,
    2242            expression=expression,
    2243            from_expressions=from_expressions,
    2244            to_expressions=to_expressions,
    2245        )
    2246
    2247    # https://www.postgresql.org/docs/current/sql-createtable.html
    2248    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2249        if not self._match_text_seq("OF"):
    2250            self._retreat(self._index - 1)
    2251            return None
    2252
    2253        this = self._parse_table(schema=True)
    2254
    2255        if self._match(TokenType.DEFAULT):
    2256            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2257        elif self._match_text_seq("FOR", "VALUES"):
    2258            expression = self._parse_partition_bound_spec()
    2259        else:
    2260            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2261
    2262        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2263
    2264    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2265        self._match(TokenType.EQ)
    2266        return self.expression(
    2267            exp.PartitionedByProperty,
    2268            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2269        )
    2270
    2271    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2272        if self._match_text_seq("AND", "STATISTICS"):
    2273            statistics = True
    2274        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2275            statistics = False
    2276        else:
    2277            statistics = None
    2278
    2279        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2280
    2281    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2282        if self._match_text_seq("SQL"):
    2283            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2284        return None
    2285
    2286    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2287        if self._match_text_seq("SQL", "DATA"):
    2288            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2289        return None
    2290
    2291    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2292        if self._match_text_seq("PRIMARY", "INDEX"):
    2293            return exp.NoPrimaryIndexProperty()
    2294        if self._match_text_seq("SQL"):
    2295            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2296        return None
    2297
    2298    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2299        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2300            return exp.OnCommitProperty()
    2301        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2302            return exp.OnCommitProperty(delete=True)
    2303        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2304
    2305    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2306        if self._match_text_seq("SQL", "DATA"):
    2307            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2308        return None
    2309
    2310    def _parse_distkey(self) -> exp.DistKeyProperty:
    2311        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2312
    2313    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2314        table = self._parse_table(schema=True)
    2315
    2316        options = []
    2317        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2318            this = self._prev.text.upper()
    2319
    2320            id_var = self._parse_id_var()
    2321            if not id_var:
    2322                return None
    2323
    2324            options.append(
    2325                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2326            )
    2327
    2328        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2329
    2330    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2331        return self.expression(
    2332            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2333        )
    2334
    2335    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2336        self._match(TokenType.EQ)
    2337        return self.expression(
    2338            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2339        )
    2340
    2341    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2342        self._match_text_seq("WITH", "CONNECTION")
    2343        return self.expression(
    2344            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2345        )
    2346
    2347    def _parse_returns(self) -> exp.ReturnsProperty:
    2348        value: t.Optional[exp.Expression]
    2349        null = None
    2350        is_table = self._match(TokenType.TABLE)
    2351
    2352        if is_table:
    2353            if self._match(TokenType.LT):
    2354                value = self.expression(
    2355                    exp.Schema,
    2356                    this="TABLE",
    2357                    expressions=self._parse_csv(self._parse_struct_types),
    2358                )
    2359                if not self._match(TokenType.GT):
    2360                    self.raise_error("Expecting >")
    2361            else:
    2362                value = self._parse_schema(exp.var("TABLE"))
    2363        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2364            null = True
    2365            value = None
    2366        else:
    2367            value = self._parse_types()
    2368
    2369        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2370
    2371    def _parse_describe(self) -> exp.Describe:
    2372        kind = self._match_set(self.CREATABLES) and self._prev.text
    2373        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
    2374        if self._match(TokenType.DOT):
    2375            style = None
    2376            self._retreat(self._index - 2)
    2377        this = self._parse_table(schema=True)
    2378        properties = self._parse_properties()
    2379        expressions = properties.expressions if properties else None
    2380        return self.expression(
    2381            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
    2382        )
    2383
    2384    def _parse_insert(self) -> exp.Insert:
    2385        comments = ensure_list(self._prev_comments)
    2386        hint = self._parse_hint()
    2387        overwrite = self._match(TokenType.OVERWRITE)
    2388        ignore = self._match(TokenType.IGNORE)
    2389        local = self._match_text_seq("LOCAL")
    2390        alternative = None
    2391        is_function = None
    2392
    2393        if self._match_text_seq("DIRECTORY"):
    2394            this: t.Optional[exp.Expression] = self.expression(
    2395                exp.Directory,
    2396                this=self._parse_var_or_string(),
    2397                local=local,
    2398                row_format=self._parse_row_format(match_row=True),
    2399            )
    2400        else:
    2401            if self._match(TokenType.OR):
    2402                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2403
    2404            self._match(TokenType.INTO)
    2405            comments += ensure_list(self._prev_comments)
    2406            self._match(TokenType.TABLE)
    2407            is_function = self._match(TokenType.FUNCTION)
    2408
    2409            this = (
    2410                self._parse_table(schema=True, parse_partition=True)
    2411                if not is_function
    2412                else self._parse_function()
    2413            )
    2414
    2415        returning = self._parse_returning()
    2416
    2417        return self.expression(
    2418            exp.Insert,
    2419            comments=comments,
    2420            hint=hint,
    2421            is_function=is_function,
    2422            this=this,
    2423            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2424            by_name=self._match_text_seq("BY", "NAME"),
    2425            exists=self._parse_exists(),
    2426            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2427            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2428            conflict=self._parse_on_conflict(),
    2429            returning=returning or self._parse_returning(),
    2430            overwrite=overwrite,
    2431            alternative=alternative,
    2432            ignore=ignore,
    2433        )
    2434
    2435    def _parse_kill(self) -> exp.Kill:
    2436        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2437
    2438        return self.expression(
    2439            exp.Kill,
    2440            this=self._parse_primary(),
    2441            kind=kind,
    2442        )
    2443
    2444    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2445        conflict = self._match_text_seq("ON", "CONFLICT")
    2446        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2447
    2448        if not conflict and not duplicate:
    2449            return None
    2450
    2451        conflict_keys = None
    2452        constraint = None
    2453
    2454        if conflict:
    2455            if self._match_text_seq("ON", "CONSTRAINT"):
    2456                constraint = self._parse_id_var()
    2457            elif self._match(TokenType.L_PAREN):
    2458                conflict_keys = self._parse_csv(self._parse_id_var)
    2459                self._match_r_paren()
    2460
    2461        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2462        if self._prev.token_type == TokenType.UPDATE:
    2463            self._match(TokenType.SET)
    2464            expressions = self._parse_csv(self._parse_equality)
    2465        else:
    2466            expressions = None
    2467
    2468        return self.expression(
    2469            exp.OnConflict,
    2470            duplicate=duplicate,
    2471            expressions=expressions,
    2472            action=action,
    2473            conflict_keys=conflict_keys,
    2474            constraint=constraint,
    2475        )
    2476
    2477    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2478        if not self._match(TokenType.RETURNING):
    2479            return None
    2480        return self.expression(
    2481            exp.Returning,
    2482            expressions=self._parse_csv(self._parse_expression),
    2483            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2484        )
    2485
    2486    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2487        if not self._match(TokenType.FORMAT):
    2488            return None
    2489        return self._parse_row_format()
    2490
    2491    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2492        index = self._index
    2493        with_ = with_ or self._match_text_seq("WITH")
    2494
    2495        if not self._match(TokenType.SERDE_PROPERTIES):
    2496            self._retreat(index)
    2497            return None
    2498        return self.expression(
    2499            exp.SerdeProperties,
    2500            **{  # type: ignore
    2501                "expressions": self._parse_wrapped_properties(),
    2502                "with": with_,
    2503            },
    2504        )
    2505
    2506    def _parse_row_format(
    2507        self, match_row: bool = False
    2508    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2509        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2510            return None
    2511
    2512        if self._match_text_seq("SERDE"):
    2513            this = self._parse_string()
    2514
    2515            serde_properties = self._parse_serde_properties()
    2516
    2517            return self.expression(
    2518                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2519            )
    2520
    2521        self._match_text_seq("DELIMITED")
    2522
    2523        kwargs = {}
    2524
    2525        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2526            kwargs["fields"] = self._parse_string()
    2527            if self._match_text_seq("ESCAPED", "BY"):
    2528                kwargs["escaped"] = self._parse_string()
    2529        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2530            kwargs["collection_items"] = self._parse_string()
    2531        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2532            kwargs["map_keys"] = self._parse_string()
    2533        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2534            kwargs["lines"] = self._parse_string()
    2535        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2536            kwargs["null"] = self._parse_string()
    2537
    2538        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2539
    2540    def _parse_load(self) -> exp.LoadData | exp.Command:
    2541        if self._match_text_seq("DATA"):
    2542            local = self._match_text_seq("LOCAL")
    2543            self._match_text_seq("INPATH")
    2544            inpath = self._parse_string()
    2545            overwrite = self._match(TokenType.OVERWRITE)
    2546            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2547
    2548            return self.expression(
    2549                exp.LoadData,
    2550                this=self._parse_table(schema=True),
    2551                local=local,
    2552                overwrite=overwrite,
    2553                inpath=inpath,
    2554                partition=self._parse_partition(),
    2555                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2556                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2557            )
    2558        return self._parse_as_command(self._prev)
    2559
    2560    def _parse_delete(self) -> exp.Delete:
    2561        # This handles MySQL's "Multiple-Table Syntax"
    2562        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2563        tables = None
    2564        comments = self._prev_comments
    2565        if not self._match(TokenType.FROM, advance=False):
    2566            tables = self._parse_csv(self._parse_table) or None
    2567
    2568        returning = self._parse_returning()
    2569
    2570        return self.expression(
    2571            exp.Delete,
    2572            comments=comments,
    2573            tables=tables,
    2574            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    2575            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    2576            where=self._parse_where(),
    2577            returning=returning or self._parse_returning(),
    2578            limit=self._parse_limit(),
    2579        )
    2580
    2581    def _parse_update(self) -> exp.Update:
    2582        comments = self._prev_comments
    2583        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    2584        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    2585        returning = self._parse_returning()
    2586        return self.expression(
    2587            exp.Update,
    2588            comments=comments,
    2589            **{  # type: ignore
    2590                "this": this,
    2591                "expressions": expressions,
    2592                "from": self._parse_from(joins=True),
    2593                "where": self._parse_where(),
    2594                "returning": returning or self._parse_returning(),
    2595                "order": self._parse_order(),
    2596                "limit": self._parse_limit(),
    2597            },
    2598        )
    2599
    2600    def _parse_uncache(self) -> exp.Uncache:
    2601        if not self._match(TokenType.TABLE):
    2602            self.raise_error("Expecting TABLE after UNCACHE")
    2603
    2604        return self.expression(
    2605            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    2606        )
    2607
    2608    def _parse_cache(self) -> exp.Cache:
    2609        lazy = self._match_text_seq("LAZY")
    2610        self._match(TokenType.TABLE)
    2611        table = self._parse_table(schema=True)
    2612
    2613        options = []
    2614        if self._match_text_seq("OPTIONS"):
    2615            self._match_l_paren()
    2616            k = self._parse_string()
    2617            self._match(TokenType.EQ)
    2618            v = self._parse_string()
    2619            options = [k, v]
    2620            self._match_r_paren()
    2621
    2622        self._match(TokenType.ALIAS)
    2623        return self.expression(
    2624            exp.Cache,
    2625            this=table,
    2626            lazy=lazy,
    2627            options=options,
    2628            expression=self._parse_select(nested=True),
    2629        )
    2630
    2631    def _parse_partition(self) -> t.Optional[exp.Partition]:
    2632        if not self._match(TokenType.PARTITION):
    2633            return None
    2634
    2635        return self.expression(
    2636            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
    2637        )
    2638
    2639    def _parse_value(self) -> t.Optional[exp.Tuple]:
    2640        if self._match(TokenType.L_PAREN):
    2641            expressions = self._parse_csv(self._parse_expression)
    2642            self._match_r_paren()
    2643            return self.expression(exp.Tuple, expressions=expressions)
    2644
    2645        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    2646        expression = self._parse_expression()
    2647        if expression:
    2648            return self.expression(exp.Tuple, expressions=[expression])
    2649        return None
    2650
    2651    def _parse_projections(self) -> t.List[exp.Expression]:
    2652        return self._parse_expressions()
    2653
    2654    def _parse_select(
    2655        self,
    2656        nested: bool = False,
    2657        table: bool = False,
    2658        parse_subquery_alias: bool = True,
    2659        parse_set_operation: bool = True,
    2660    ) -> t.Optional[exp.Expression]:
    2661        cte = self._parse_with()
    2662
    2663        if cte:
    2664            this = self._parse_statement()
    2665
    2666            if not this:
    2667                self.raise_error("Failed to parse any statement following CTE")
    2668                return cte
    2669
    2670            if "with" in this.arg_types:
    2671                this.set("with", cte)
    2672            else:
    2673                self.raise_error(f"{this.key} does not support CTE")
    2674                this = cte
    2675
    2676            return this
    2677
    2678        # duckdb supports leading with FROM x
    2679        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    2680
    2681        if self._match(TokenType.SELECT):
    2682            comments = self._prev_comments
    2683
    2684            hint = self._parse_hint()
    2685            all_ = self._match(TokenType.ALL)
    2686            distinct = self._match_set(self.DISTINCT_TOKENS)
    2687
    2688            kind = (
    2689                self._match(TokenType.ALIAS)
    2690                and self._match_texts(("STRUCT", "VALUE"))
    2691                and self._prev.text.upper()
    2692            )
    2693
    2694            if distinct:
    2695                distinct = self.expression(
    2696                    exp.Distinct,
    2697                    on=self._parse_value() if self._match(TokenType.ON) else None,
    2698                )
    2699
    2700            if all_ and distinct:
    2701                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    2702
    2703            limit = self._parse_limit(top=True)
    2704            projections = self._parse_projections()
    2705
    2706            this = self.expression(
    2707                exp.Select,
    2708                kind=kind,
    2709                hint=hint,
    2710                distinct=distinct,
    2711                expressions=projections,
    2712                limit=limit,
    2713            )
    2714            this.comments = comments
    2715
    2716            into = self._parse_into()
    2717            if into:
    2718                this.set("into", into)
    2719
    2720            if not from_:
    2721                from_ = self._parse_from()
    2722
    2723            if from_:
    2724                this.set("from", from_)
    2725
    2726            this = self._parse_query_modifiers(this)
    2727        elif (table or nested) and self._match(TokenType.L_PAREN):
    2728            if self._match(TokenType.PIVOT):
    2729                this = self._parse_simplified_pivot()
    2730            elif self._match(TokenType.FROM):
    2731                this = exp.select("*").from_(
    2732                    t.cast(exp.From, self._parse_from(skip_from_token=True))
    2733                )
    2734            else:
    2735                this = (
    2736                    self._parse_table()
    2737                    if table
    2738                    else self._parse_select(nested=True, parse_set_operation=False)
    2739                )
    2740                this = self._parse_query_modifiers(self._parse_set_operations(this))
    2741
    2742            self._match_r_paren()
    2743
    2744            # We return early here so that the UNION isn't attached to the subquery by the
    2745            # following call to _parse_set_operations, but instead becomes the parent node
    2746            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    2747        elif self._match(TokenType.VALUES, advance=False):
    2748            this = self._parse_derived_table_values()
    2749        elif from_:
    2750            this = exp.select("*").from_(from_.this, copy=False)
    2751        else:
    2752            this = None
    2753
    2754        if parse_set_operation:
    2755            return self._parse_set_operations(this)
    2756        return this
    2757
    2758    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    2759        if not skip_with_token and not self._match(TokenType.WITH):
    2760            return None
    2761
    2762        comments = self._prev_comments
    2763        recursive = self._match(TokenType.RECURSIVE)
    2764
    2765        expressions = []
    2766        while True:
    2767            expressions.append(self._parse_cte())
    2768
    2769            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    2770                break
    2771            else:
    2772                self._match(TokenType.WITH)
    2773
    2774        return self.expression(
    2775            exp.With, comments=comments, expressions=expressions, recursive=recursive
    2776        )
    2777
    2778    def _parse_cte(self) -> exp.CTE:
    2779        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    2780        if not alias or not alias.this:
    2781            self.raise_error("Expected CTE to have alias")
    2782
    2783        self._match(TokenType.ALIAS)
    2784
    2785        if self._match_text_seq("NOT", "MATERIALIZED"):
    2786            materialized = False
    2787        elif self._match_text_seq("MATERIALIZED"):
    2788            materialized = True
    2789        else:
    2790            materialized = None
    2791
    2792        return self.expression(
    2793            exp.CTE,
    2794            this=self._parse_wrapped(self._parse_statement),
    2795            alias=alias,
    2796            materialized=materialized,
    2797        )
    2798
    2799    def _parse_table_alias(
    2800        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    2801    ) -> t.Optional[exp.TableAlias]:
    2802        any_token = self._match(TokenType.ALIAS)
    2803        alias = (
    2804            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    2805            or self._parse_string_as_identifier()
    2806        )
    2807
    2808        index = self._index
    2809        if self._match(TokenType.L_PAREN):
    2810            columns = self._parse_csv(self._parse_function_parameter)
    2811            self._match_r_paren() if columns else self._retreat(index)
    2812        else:
    2813            columns = None
    2814
    2815        if not alias and not columns:
    2816            return None
    2817
    2818        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    2819
    2820        # We bubble up comments from the Identifier to the TableAlias
    2821        if isinstance(alias, exp.Identifier):
    2822            table_alias.add_comments(alias.pop_comments())
    2823
    2824        return table_alias
    2825
    2826    def _parse_subquery(
    2827        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    2828    ) -> t.Optional[exp.Subquery]:
    2829        if not this:
    2830            return None
    2831
    2832        return self.expression(
    2833            exp.Subquery,
    2834            this=this,
    2835            pivots=self._parse_pivots(),
    2836            alias=self._parse_table_alias() if parse_alias else None,
    2837        )
    2838
    2839    def _implicit_unnests_to_explicit(self, this: E) -> E:
    2840        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    2841
    2842        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    2843        for i, join in enumerate(this.args.get("joins") or []):
    2844            table = join.this
    2845            normalized_table = table.copy()
    2846            normalized_table.meta["maybe_column"] = True
    2847            normalized_table = _norm(normalized_table, dialect=self.dialect)
    2848
    2849            if isinstance(table, exp.Table) and not join.args.get("on"):
    2850                if normalized_table.parts[0].name in refs:
    2851                    table_as_column = table.to_column()
    2852                    unnest = exp.Unnest(expressions=[table_as_column])
    2853
    2854                    # Table.to_column creates a parent Alias node that we want to convert to
    2855                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    2856                    if isinstance(table.args.get("alias"), exp.TableAlias):
    2857                        table_as_column.replace(table_as_column.this)
    2858                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    2859
    2860                    table.replace(unnest)
    2861
    2862            refs.add(normalized_table.alias_or_name)
    2863
    2864        return this
    2865
    2866    def _parse_query_modifiers(
    2867        self, this: t.Optional[exp.Expression]
    2868    ) -> t.Optional[exp.Expression]:
    2869        if isinstance(this, (exp.Query, exp.Table)):
    2870            for join in self._parse_joins():
    2871                this.append("joins", join)
    2872            for lateral in iter(self._parse_lateral, None):
    2873                this.append("laterals", lateral)
    2874
    2875            while True:
    2876                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    2877                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    2878                    key, expression = parser(self)
    2879
    2880                    if expression:
    2881                        this.set(key, expression)
    2882                        if key == "limit":
    2883                            offset = expression.args.pop("offset", None)
    2884
    2885                            if offset:
    2886                                offset = exp.Offset(expression=offset)
    2887                                this.set("offset", offset)
    2888
    2889                                limit_by_expressions = expression.expressions
    2890                                expression.set("expressions", None)
    2891                                offset.set("expressions", limit_by_expressions)
    2892                        continue
    2893                break
    2894
    2895        if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
    2896            this = self._implicit_unnests_to_explicit(this)
    2897
    2898        return this
    2899
    2900    def _parse_hint(self) -> t.Optional[exp.Hint]:
    2901        if self._match(TokenType.HINT):
    2902            hints = []
    2903            for hint in iter(
    2904                lambda: self._parse_csv(
    2905                    lambda: self._parse_function() or self._parse_var(upper=True)
    2906                ),
    2907                [],
    2908            ):
    2909                hints.extend(hint)
    2910
    2911            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
    2912                self.raise_error("Expected */ after HINT")
    2913
    2914            return self.expression(exp.Hint, expressions=hints)
    2915
    2916        return None
    2917
    2918    def _parse_into(self) -> t.Optional[exp.Into]:
    2919        if not self._match(TokenType.INTO):
    2920            return None
    2921
    2922        temp = self._match(TokenType.TEMPORARY)
    2923        unlogged = self._match_text_seq("UNLOGGED")
    2924        self._match(TokenType.TABLE)
    2925
    2926        return self.expression(
    2927            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    2928        )
    2929
    2930    def _parse_from(
    2931        self, joins: bool = False, skip_from_token: bool = False
    2932    ) -> t.Optional[exp.From]:
    2933        if not skip_from_token and not self._match(TokenType.FROM):
    2934            return None
    2935
    2936        return self.expression(
    2937            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    2938        )
    2939
    2940    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    2941        return self.expression(
    2942            exp.MatchRecognizeMeasure,
    2943            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    2944            this=self._parse_expression(),
    2945        )
    2946
    2947    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    2948        if not self._match(TokenType.MATCH_RECOGNIZE):
    2949            return None
    2950
    2951        self._match_l_paren()
    2952
    2953        partition = self._parse_partition_by()
    2954        order = self._parse_order()
    2955
    2956        measures = (
    2957            self._parse_csv(self._parse_match_recognize_measure)
    2958            if self._match_text_seq("MEASURES")
    2959            else None
    2960        )
    2961
    2962        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    2963            rows = exp.var("ONE ROW PER MATCH")
    2964        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    2965            text = "ALL ROWS PER MATCH"
    2966            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    2967                text += " SHOW EMPTY MATCHES"
    2968            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    2969                text += " OMIT EMPTY MATCHES"
    2970            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    2971                text += " WITH UNMATCHED ROWS"
    2972            rows = exp.var(text)
    2973        else:
    2974            rows = None
    2975
    2976        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    2977            text = "AFTER MATCH SKIP"
    2978            if self._match_text_seq("PAST", "LAST", "ROW"):
    2979                text += " PAST LAST ROW"
    2980            elif self._match_text_seq("TO", "NEXT", "ROW"):
    2981                text += " TO NEXT ROW"
    2982            elif self._match_text_seq("TO", "FIRST"):
    2983                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    2984            elif self._match_text_seq("TO", "LAST"):
    2985                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    2986            after = exp.var(text)
    2987        else:
    2988            after = None
    2989
    2990        if self._match_text_seq("PATTERN"):
    2991            self._match_l_paren()
    2992
    2993            if not self._curr:
    2994                self.raise_error("Expecting )", self._curr)
    2995
    2996            paren = 1
    2997            start = self._curr
    2998
    2999            while self._curr and paren > 0:
    3000                if self._curr.token_type == TokenType.L_PAREN:
    3001                    paren += 1
    3002                if self._curr.token_type == TokenType.R_PAREN:
    3003                    paren -= 1
    3004
    3005                end = self._prev
    3006                self._advance()
    3007
    3008            if paren > 0:
    3009                self.raise_error("Expecting )", self._curr)
    3010
    3011            pattern = exp.var(self._find_sql(start, end))
    3012        else:
    3013            pattern = None
    3014
    3015        define = (
    3016            self._parse_csv(self._parse_name_as_expression)
    3017            if self._match_text_seq("DEFINE")
    3018            else None
    3019        )
    3020
    3021        self._match_r_paren()
    3022
    3023        return self.expression(
    3024            exp.MatchRecognize,
    3025            partition_by=partition,
    3026            order=order,
    3027            measures=measures,
    3028            rows=rows,
    3029            after=after,
    3030            pattern=pattern,
    3031            define=define,
    3032            alias=self._parse_table_alias(),
    3033        )
    3034
    3035    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3036        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3037        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3038            cross_apply = False
    3039
    3040        if cross_apply is not None:
    3041            this = self._parse_select(table=True)
    3042            view = None
    3043            outer = None
    3044        elif self._match(TokenType.LATERAL):
    3045            this = self._parse_select(table=True)
    3046            view = self._match(TokenType.VIEW)
    3047            outer = self._match(TokenType.OUTER)
    3048        else:
    3049            return None
    3050
    3051        if not this:
    3052            this = (
    3053                self._parse_unnest()
    3054                or self._parse_function()
    3055                or self._parse_id_var(any_token=False)
    3056            )
    3057
    3058            while self._match(TokenType.DOT):
    3059                this = exp.Dot(
    3060                    this=this,
    3061                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3062                )
    3063
    3064        if view:
    3065            table = self._parse_id_var(any_token=False)
    3066            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3067            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3068                exp.TableAlias, this=table, columns=columns
    3069            )
    3070        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3071            # We move the alias from the lateral's child node to the lateral itself
    3072            table_alias = this.args["alias"].pop()
    3073        else:
    3074            table_alias = self._parse_table_alias()
    3075
    3076        return self.expression(
    3077            exp.Lateral,
    3078            this=this,
    3079            view=view,
    3080            outer=outer,
    3081            alias=table_alias,
    3082            cross_apply=cross_apply,
    3083        )
    3084
    3085    def _parse_join_parts(
    3086        self,
    3087    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3088        return (
    3089            self._match_set(self.JOIN_METHODS) and self._prev,
    3090            self._match_set(self.JOIN_SIDES) and self._prev,
    3091            self._match_set(self.JOIN_KINDS) and self._prev,
    3092        )
    3093
    3094    def _parse_join(
    3095        self, skip_join_token: bool = False, parse_bracket: bool = False
    3096    ) -> t.Optional[exp.Join]:
    3097        if self._match(TokenType.COMMA):
    3098            return self.expression(exp.Join, this=self._parse_table())
    3099
    3100        index = self._index
    3101        method, side, kind = self._parse_join_parts()
    3102        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3103        join = self._match(TokenType.JOIN)
    3104
    3105        if not skip_join_token and not join:
    3106            self._retreat(index)
    3107            kind = None
    3108            method = None
    3109            side = None
    3110
    3111        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3112        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3113
    3114        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3115            return None
    3116
    3117        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3118
    3119        if method:
    3120            kwargs["method"] = method.text
    3121        if side:
    3122            kwargs["side"] = side.text
    3123        if kind:
    3124            kwargs["kind"] = kind.text
    3125        if hint:
    3126            kwargs["hint"] = hint
    3127
    3128        if self._match(TokenType.MATCH_CONDITION):
    3129            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3130
    3131        if self._match(TokenType.ON):
    3132            kwargs["on"] = self._parse_assignment()
    3133        elif self._match(TokenType.USING):
    3134            kwargs["using"] = self._parse_wrapped_id_vars()
    3135        elif not isinstance(kwargs["this"], exp.Unnest) and not (
    3136            kind and kind.token_type == TokenType.CROSS
    3137        ):
    3138            index = self._index
    3139            joins: t.Optional[list] = list(self._parse_joins())
    3140
    3141            if joins and self._match(TokenType.ON):
    3142                kwargs["on"] = self._parse_assignment()
    3143            elif joins and self._match(TokenType.USING):
    3144                kwargs["using"] = self._parse_wrapped_id_vars()
    3145            else:
    3146                joins = None
    3147                self._retreat(index)
    3148
    3149            kwargs["this"].set("joins", joins if joins else None)
    3150
    3151        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3152        return self.expression(exp.Join, comments=comments, **kwargs)
    3153
    3154    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3155        this = self._parse_assignment()
    3156
    3157        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3158            return this
    3159
    3160        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3161            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3162
    3163        return this
    3164
    3165    def _parse_index_params(self) -> exp.IndexParameters:
    3166        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3167
    3168        if self._match(TokenType.L_PAREN, advance=False):
    3169            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3170        else:
    3171            columns = None
    3172
    3173        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3174        partition_by = self._parse_partition_by()
    3175        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3176        tablespace = (
    3177            self._parse_var(any_token=True)
    3178            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3179            else None
    3180        )
    3181        where = self._parse_where()
    3182
    3183        return self.expression(
    3184            exp.IndexParameters,
    3185            using=using,
    3186            columns=columns,
    3187            include=include,
    3188            partition_by=partition_by,
    3189            where=where,
    3190            with_storage=with_storage,
    3191            tablespace=tablespace,
    3192        )
    3193
    3194    def _parse_index(
    3195        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3196    ) -> t.Optional[exp.Index]:
    3197        if index or anonymous:
    3198            unique = None
    3199            primary = None
    3200            amp = None
    3201
    3202            self._match(TokenType.ON)
    3203            self._match(TokenType.TABLE)  # hive
    3204            table = self._parse_table_parts(schema=True)
    3205        else:
    3206            unique = self._match(TokenType.UNIQUE)
    3207            primary = self._match_text_seq("PRIMARY")
    3208            amp = self._match_text_seq("AMP")
    3209
    3210            if not self._match(TokenType.INDEX):
    3211                return None
    3212
    3213            index = self._parse_id_var()
    3214            table = None
    3215
    3216        params = self._parse_index_params()
    3217
    3218        return self.expression(
    3219            exp.Index,
    3220            this=index,
    3221            table=table,
    3222            unique=unique,
    3223            primary=primary,
    3224            amp=amp,
    3225            params=params,
    3226        )
    3227
    3228    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3229        hints: t.List[exp.Expression] = []
    3230        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3231            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3232            hints.append(
    3233                self.expression(
    3234                    exp.WithTableHint,
    3235                    expressions=self._parse_csv(
    3236                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3237                    ),
    3238                )
    3239            )
    3240            self._match_r_paren()
    3241        else:
    3242            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3243            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3244                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3245
    3246                self._match_texts(("INDEX", "KEY"))
    3247                if self._match(TokenType.FOR):
    3248                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3249
    3250                hint.set("expressions", self._parse_wrapped_id_vars())
    3251                hints.append(hint)
    3252
    3253        return hints or None
    3254
    3255    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3256        return (
    3257            (not schema and self._parse_function(optional_parens=False))
    3258            or self._parse_id_var(any_token=False)
    3259            or self._parse_string_as_identifier()
    3260            or self._parse_placeholder()
    3261        )
    3262
    3263    def _parse_table_parts(
    3264        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3265    ) -> exp.Table:
    3266        catalog = None
    3267        db = None
    3268        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3269
    3270        while self._match(TokenType.DOT):
    3271            if catalog:
    3272                # This allows nesting the table in arbitrarily many dot expressions if needed
    3273                table = self.expression(
    3274                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3275                )
    3276            else:
    3277                catalog = db
    3278                db = table
    3279                # "" used for tsql FROM a..b case
    3280                table = self._parse_table_part(schema=schema) or ""
    3281
    3282        if (
    3283            wildcard
    3284            and self._is_connected()
    3285            and (isinstance(table, exp.Identifier) or not table)
    3286            and self._match(TokenType.STAR)
    3287        ):
    3288            if isinstance(table, exp.Identifier):
    3289                table.args["this"] += "*"
    3290            else:
    3291                table = exp.Identifier(this="*")
    3292
    3293        # We bubble up comments from the Identifier to the Table
    3294        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3295
    3296        if is_db_reference:
    3297            catalog = db
    3298            db = table
    3299            table = None
    3300
    3301        if not table and not is_db_reference:
    3302            self.raise_error(f"Expected table name but got {self._curr}")
    3303        if not db and is_db_reference:
    3304            self.raise_error(f"Expected database name but got {self._curr}")
    3305
    3306        return self.expression(
    3307            exp.Table,
    3308            comments=comments,
    3309            this=table,
    3310            db=db,
    3311            catalog=catalog,
    3312            pivots=self._parse_pivots(),
    3313        )
    3314
    3315    def _parse_table(
    3316        self,
    3317        schema: bool = False,
    3318        joins: bool = False,
    3319        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3320        parse_bracket: bool = False,
    3321        is_db_reference: bool = False,
    3322        parse_partition: bool = False,
    3323    ) -> t.Optional[exp.Expression]:
    3324        lateral = self._parse_lateral()
    3325        if lateral:
    3326            return lateral
    3327
    3328        unnest = self._parse_unnest()
    3329        if unnest:
    3330            return unnest
    3331
    3332        values = self._parse_derived_table_values()
    3333        if values:
    3334            return values
    3335
    3336        subquery = self._parse_select(table=True)
    3337        if subquery:
    3338            if not subquery.args.get("pivots"):
    3339                subquery.set("pivots", self._parse_pivots())
    3340            return subquery
    3341
    3342        bracket = parse_bracket and self._parse_bracket(None)
    3343        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3344
    3345        only = self._match(TokenType.ONLY)
    3346
    3347        this = t.cast(
    3348            exp.Expression,
    3349            bracket
    3350            or self._parse_bracket(
    3351                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3352            ),
    3353        )
    3354
    3355        if only:
    3356            this.set("only", only)
    3357
    3358        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3359        self._match_text_seq("*")
    3360
    3361        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3362        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3363            this.set("partition", self._parse_partition())
    3364
    3365        if schema:
    3366            return self._parse_schema(this=this)
    3367
    3368        version = self._parse_version()
    3369
    3370        if version:
    3371            this.set("version", version)
    3372
    3373        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3374            table_sample = self._parse_table_sample()
    3375
    3376        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3377        if alias:
    3378            this.set("alias", alias)
    3379
    3380        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3381            return self.expression(
    3382                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3383            )
    3384
    3385        this.set("hints", self._parse_table_hints())
    3386
    3387        if not this.args.get("pivots"):
    3388            this.set("pivots", self._parse_pivots())
    3389
    3390        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3391            table_sample = self._parse_table_sample()
    3392
    3393        if table_sample:
    3394            table_sample.set("this", this)
    3395            this = table_sample
    3396
    3397        if joins:
    3398            for join in self._parse_joins():
    3399                this.append("joins", join)
    3400
    3401        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3402            this.set("ordinality", True)
    3403            this.set("alias", self._parse_table_alias())
    3404
    3405        return this
    3406
    3407    def _parse_version(self) -> t.Optional[exp.Version]:
    3408        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    3409            this = "TIMESTAMP"
    3410        elif self._match(TokenType.VERSION_SNAPSHOT):
    3411            this = "VERSION"
    3412        else:
    3413            return None
    3414
    3415        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    3416            kind = self._prev.text.upper()
    3417            start = self._parse_bitwise()
    3418            self._match_texts(("TO", "AND"))
    3419            end = self._parse_bitwise()
    3420            expression: t.Optional[exp.Expression] = self.expression(
    3421                exp.Tuple, expressions=[start, end]
    3422            )
    3423        elif self._match_text_seq("CONTAINED", "IN"):
    3424            kind = "CONTAINED IN"
    3425            expression = self.expression(
    3426                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    3427            )
    3428        elif self._match(TokenType.ALL):
    3429            kind = "ALL"
    3430            expression = None
    3431        else:
    3432            self._match_text_seq("AS", "OF")
    3433            kind = "AS OF"
    3434            expression = self._parse_type()
    3435
    3436        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    3437
    3438    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    3439        if not self._match(TokenType.UNNEST):
    3440            return None
    3441
    3442        expressions = self._parse_wrapped_csv(self._parse_equality)
    3443        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    3444
    3445        alias = self._parse_table_alias() if with_alias else None
    3446
    3447        if alias:
    3448            if self.dialect.UNNEST_COLUMN_ONLY:
    3449                if alias.args.get("columns"):
    3450                    self.raise_error("Unexpected extra column alias in unnest.")
    3451
    3452                alias.set("columns", [alias.this])
    3453                alias.set("this", None)
    3454
    3455            columns = alias.args.get("columns") or []
    3456            if offset and len(expressions) < len(columns):
    3457                offset = columns.pop()
    3458
    3459        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    3460            self._match(TokenType.ALIAS)
    3461            offset = self._parse_id_var(
    3462                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    3463            ) or exp.to_identifier("offset")
    3464
    3465        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    3466
    3467    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    3468        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    3469        if not is_derived and not self._match_text_seq("VALUES"):
    3470            return None
    3471
    3472        expressions = self._parse_csv(self._parse_value)
    3473        alias = self._parse_table_alias()
    3474
    3475        if is_derived:
    3476            self._match_r_paren()
    3477
    3478        return self.expression(
    3479            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    3480        )
    3481
    3482    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    3483        if not self._match(TokenType.TABLE_SAMPLE) and not (
    3484            as_modifier and self._match_text_seq("USING", "SAMPLE")
    3485        ):
    3486            return None
    3487
    3488        bucket_numerator = None
    3489        bucket_denominator = None
    3490        bucket_field = None
    3491        percent = None
    3492        size = None
    3493        seed = None
    3494
    3495        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    3496        matched_l_paren = self._match(TokenType.L_PAREN)
    3497
    3498        if self.TABLESAMPLE_CSV:
    3499            num = None
    3500            expressions = self._parse_csv(self._parse_primary)
    3501        else:
    3502            expressions = None
    3503            num = (
    3504                self._parse_factor()
    3505                if self._match(TokenType.NUMBER, advance=False)
    3506                else self._parse_primary() or self._parse_placeholder()
    3507            )
    3508
    3509        if self._match_text_seq("BUCKET"):
    3510            bucket_numerator = self._parse_number()
    3511            self._match_text_seq("OUT", "OF")
    3512            bucket_denominator = bucket_denominator = self._parse_number()
    3513            self._match(TokenType.ON)
    3514            bucket_field = self._parse_field()
    3515        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    3516            percent = num
    3517        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    3518            size = num
    3519        else:
    3520            percent = num
    3521
    3522        if matched_l_paren:
    3523            self._match_r_paren()
    3524
    3525        if self._match(TokenType.L_PAREN):
    3526            method = self._parse_var(upper=True)
    3527            seed = self._match(TokenType.COMMA) and self._parse_number()
    3528            self._match_r_paren()
    3529        elif self._match_texts(("SEED", "REPEATABLE")):
    3530            seed = self._parse_wrapped(self._parse_number)
    3531
    3532        if not method and self.DEFAULT_SAMPLING_METHOD:
    3533            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    3534
    3535        return self.expression(
    3536            exp.TableSample,
    3537            expressions=expressions,
    3538            method=method,
    3539            bucket_numerator=bucket_numerator,
    3540            bucket_denominator=bucket_denominator,
    3541            bucket_field=bucket_field,
    3542            percent=percent,
    3543            size=size,
    3544            seed=seed,
    3545        )
    3546
    3547    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    3548        return list(iter(self._parse_pivot, None)) or None
    3549
    3550    def _parse_joins(self) -> t.Iterator[exp.Join]:
    3551        return iter(self._parse_join, None)
    3552
    3553    # https://duckdb.org/docs/sql/statements/pivot
    3554    def _parse_simplified_pivot(self) -> exp.Pivot:
    3555        def _parse_on() -> t.Optional[exp.Expression]:
    3556            this = self._parse_bitwise()
    3557            return self._parse_in(this) if self._match(TokenType.IN) else this
    3558
    3559        this = self._parse_table()
    3560        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    3561        using = self._match(TokenType.USING) and self._parse_csv(
    3562            lambda: self._parse_alias(self._parse_function())
    3563        )
    3564        group = self._parse_group()
    3565        return self.expression(
    3566            exp.Pivot, this=this, expressions=expressions, using=using, group=group
    3567        )
    3568
    3569    def _parse_pivot_in(self) -> exp.In:
    3570        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    3571            this = self._parse_assignment()
    3572
    3573            self._match(TokenType.ALIAS)
    3574            alias = self._parse_field()
    3575            if alias:
    3576                return self.expression(exp.PivotAlias, this=this, alias=alias)
    3577
    3578            return this
    3579
    3580        value = self._parse_column()
    3581
    3582        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    3583            self.raise_error("Expecting IN (")
    3584
    3585        aliased_expressions = self._parse_csv(_parse_aliased_expression)
    3586
    3587        self._match_r_paren()
    3588        return self.expression(exp.In, this=value, expressions=aliased_expressions)
    3589
    3590    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    3591        index = self._index
    3592        include_nulls = None
    3593
    3594        if self._match(TokenType.PIVOT):
    3595            unpivot = False
    3596        elif self._match(TokenType.UNPIVOT):
    3597            unpivot = True
    3598
    3599            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    3600            if self._match_text_seq("INCLUDE", "NULLS"):
    3601                include_nulls = True
    3602            elif self._match_text_seq("EXCLUDE", "NULLS"):
    3603                include_nulls = False
    3604        else:
    3605            return None
    3606
    3607        expressions = []
    3608
    3609        if not self._match(TokenType.L_PAREN):
    3610            self._retreat(index)
    3611            return None
    3612
    3613        if unpivot:
    3614            expressions = self._parse_csv(self._parse_column)
    3615        else:
    3616            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    3617
    3618        if not expressions:
    3619            self.raise_error("Failed to parse PIVOT's aggregation list")
    3620
    3621        if not self._match(TokenType.FOR):
    3622            self.raise_error("Expecting FOR")
    3623
    3624        field = self._parse_pivot_in()
    3625
    3626        self._match_r_paren()
    3627
    3628        pivot = self.expression(
    3629            exp.Pivot,
    3630            expressions=expressions,
    3631            field=field,
    3632            unpivot=unpivot,
    3633            include_nulls=include_nulls,
    3634        )
    3635
    3636        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    3637            pivot.set("alias", self._parse_table_alias())
    3638
    3639        if not unpivot:
    3640            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    3641
    3642            columns: t.List[exp.Expression] = []
    3643            for fld in pivot.args["field"].expressions:
    3644                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    3645                for name in names:
    3646                    if self.PREFIXED_PIVOT_COLUMNS:
    3647                        name = f"{name}_{field_name}" if name else field_name
    3648                    else:
    3649                        name = f"{field_name}_{name}" if name else field_name
    3650
    3651                    columns.append(exp.to_identifier(name))
    3652
    3653            pivot.set("columns", columns)
    3654
    3655        return pivot
    3656
    3657    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    3658        return [agg.alias for agg in aggregations]
    3659
    3660    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    3661        if not skip_where_token and not self._match(TokenType.PREWHERE):
    3662            return None
    3663
    3664        return self.expression(
    3665            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    3666        )
    3667
    3668    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    3669        if not skip_where_token and not self._match(TokenType.WHERE):
    3670            return None
    3671
    3672        return self.expression(
    3673            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    3674        )
    3675
    3676    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    3677        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    3678            return None
    3679
    3680        elements: t.Dict[str, t.Any] = defaultdict(list)
    3681
    3682        if self._match(TokenType.ALL):
    3683            elements["all"] = True
    3684        elif self._match(TokenType.DISTINCT):
    3685            elements["all"] = False
    3686
    3687        while True:
    3688            expressions = self._parse_csv(
    3689                lambda: None
    3690                if self._match(TokenType.ROLLUP, advance=False)
    3691                else self._parse_assignment()
    3692            )
    3693            if expressions:
    3694                elements["expressions"].extend(expressions)
    3695
    3696            grouping_sets = self._parse_grouping_sets()
    3697            if grouping_sets:
    3698                elements["grouping_sets"].extend(grouping_sets)
    3699
    3700            rollup = None
    3701            cube = None
    3702            totals = None
    3703
    3704            index = self._index
    3705            with_ = self._match(TokenType.WITH)
    3706            if self._match(TokenType.ROLLUP):
    3707                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
    3708                elements["rollup"].extend(ensure_list(rollup))
    3709
    3710            if self._match(TokenType.CUBE):
    3711                cube = with_ or self._parse_wrapped_csv(self._parse_column)
    3712                elements["cube"].extend(ensure_list(cube))
    3713
    3714            if self._match_text_seq("TOTALS"):
    3715                totals = True
    3716                elements["totals"] = True  # type: ignore
    3717
    3718            if not (grouping_sets or rollup or cube or totals):
    3719                if with_:
    3720                    self._retreat(index)
    3721                break
    3722
    3723        return self.expression(exp.Group, **elements)  # type: ignore
    3724
    3725    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
    3726        if not self._match(TokenType.GROUPING_SETS):
    3727            return None
    3728
    3729        return self._parse_wrapped_csv(self._parse_grouping_set)
    3730
    3731    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    3732        if self._match(TokenType.L_PAREN):
    3733            grouping_set = self._parse_csv(self._parse_column)
    3734            self._match_r_paren()
    3735            return self.expression(exp.Tuple, expressions=grouping_set)
    3736
    3737        return self._parse_column()
    3738
    3739    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    3740        if not skip_having_token and not self._match(TokenType.HAVING):
    3741            return None
    3742        return self.expression(exp.Having, this=self._parse_assignment())
    3743
    3744    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    3745        if not self._match(TokenType.QUALIFY):
    3746            return None
    3747        return self.expression(exp.Qualify, this=self._parse_assignment())
    3748
    3749    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    3750        if skip_start_token:
    3751            start = None
    3752        elif self._match(TokenType.START_WITH):
    3753            start = self._parse_assignment()
    3754        else:
    3755            return None
    3756
    3757        self._match(TokenType.CONNECT_BY)
    3758        nocycle = self._match_text_seq("NOCYCLE")
    3759        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    3760            exp.Prior, this=self._parse_bitwise()
    3761        )
    3762        connect = self._parse_assignment()
    3763        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    3764
    3765        if not start and self._match(TokenType.START_WITH):
    3766            start = self._parse_assignment()
    3767
    3768        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    3769
    3770    def _parse_name_as_expression(self) -> exp.Alias:
    3771        return self.expression(
    3772            exp.Alias,
    3773            alias=self._parse_id_var(any_token=True),
    3774            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
    3775        )
    3776
    3777    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    3778        if self._match_text_seq("INTERPOLATE"):
    3779            return self._parse_wrapped_csv(self._parse_name_as_expression)
    3780        return None
    3781
    3782    def _parse_order(
    3783        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    3784    ) -> t.Optional[exp.Expression]:
    3785        siblings = None
    3786        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    3787            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    3788                return this
    3789
    3790            siblings = True
    3791
    3792        return self.expression(
    3793            exp.Order,
    3794            this=this,
    3795            expressions=self._parse_csv(self._parse_ordered),
    3796            interpolate=self._parse_interpolate(),
    3797            siblings=siblings,
    3798        )
    3799
    3800    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    3801        if not self._match(token):
    3802            return None
    3803        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    3804
    3805    def _parse_ordered(
    3806        self, parse_method: t.Optional[t.Callable] = None
    3807    ) -> t.Optional[exp.Ordered]:
    3808        this = parse_method() if parse_method else self._parse_assignment()
    3809        if not this:
    3810            return None
    3811
    3812        asc = self._match(TokenType.ASC)
    3813        desc = self._match(TokenType.DESC) or (asc and False)
    3814
    3815        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    3816        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    3817
    3818        nulls_first = is_nulls_first or False
    3819        explicitly_null_ordered = is_nulls_first or is_nulls_last
    3820
    3821        if (
    3822            not explicitly_null_ordered
    3823            and (
    3824                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    3825                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    3826            )
    3827            and self.dialect.NULL_ORDERING != "nulls_are_last"
    3828        ):
    3829            nulls_first = True
    3830
    3831        if self._match_text_seq("WITH", "FILL"):
    3832            with_fill = self.expression(
    3833                exp.WithFill,
    3834                **{  # type: ignore
    3835                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    3836                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    3837                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    3838                },
    3839            )
    3840        else:
    3841            with_fill = None
    3842
    3843        return self.expression(
    3844            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    3845        )
    3846
    3847    def _parse_limit(
    3848        self,
    3849        this: t.Optional[exp.Expression] = None,
    3850        top: bool = False,
    3851        skip_limit_token: bool = False,
    3852    ) -> t.Optional[exp.Expression]:
    3853        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    3854            comments = self._prev_comments
    3855            if top:
    3856                limit_paren = self._match(TokenType.L_PAREN)
    3857                expression = self._parse_term() if limit_paren else self._parse_number()
    3858
    3859                if limit_paren:
    3860                    self._match_r_paren()
    3861            else:
    3862                expression = self._parse_term()
    3863
    3864            if self._match(TokenType.COMMA):
    3865                offset = expression
    3866                expression = self._parse_term()
    3867            else:
    3868                offset = None
    3869
    3870            limit_exp = self.expression(
    3871                exp.Limit,
    3872                this=this,
    3873                expression=expression,
    3874                offset=offset,
    3875                comments=comments,
    3876                expressions=self._parse_limit_by(),
    3877            )
    3878
    3879            return limit_exp
    3880
    3881        if self._match(TokenType.FETCH):
    3882            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    3883            direction = self._prev.text.upper() if direction else "FIRST"
    3884
    3885            count = self._parse_field(tokens=self.FETCH_TOKENS)
    3886            percent = self._match(TokenType.PERCENT)
    3887
    3888            self._match_set((TokenType.ROW, TokenType.ROWS))
    3889
    3890            only = self._match_text_seq("ONLY")
    3891            with_ties = self._match_text_seq("WITH", "TIES")
    3892
    3893            if only and with_ties:
    3894                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
    3895
    3896            return self.expression(
    3897                exp.Fetch,
    3898                direction=direction,
    3899                count=count,
    3900                percent=percent,
    3901                with_ties=with_ties,
    3902            )
    3903
    3904        return this
    3905
    3906    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    3907        if not self._match(TokenType.OFFSET):
    3908            return this
    3909
    3910        count = self._parse_term()
    3911        self._match_set((TokenType.ROW, TokenType.ROWS))
    3912
    3913        return self.expression(
    3914            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    3915        )
    3916
    3917    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    3918        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    3919
    3920    def _parse_locks(self) -> t.List[exp.Lock]:
    3921        locks = []
    3922        while True:
    3923            if self._match_text_seq("FOR", "UPDATE"):
    3924                update = True
    3925            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    3926                "LOCK", "IN", "SHARE", "MODE"
    3927            ):
    3928                update = False
    3929            else:
    3930                break
    3931
    3932            expressions = None
    3933            if self._match_text_seq("OF"):
    3934                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    3935
    3936            wait: t.Optional[bool | exp.Expression] = None
    3937            if self._match_text_seq("NOWAIT"):
    3938                wait = True
    3939            elif self._match_text_seq("WAIT"):
    3940                wait = self._parse_primary()
    3941            elif self._match_text_seq("SKIP", "LOCKED"):
    3942                wait = False
    3943
    3944            locks.append(
    3945                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    3946            )
    3947
    3948        return locks
    3949
    3950    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    3951        while this and self._match_set(self.SET_OPERATIONS):
    3952            token_type = self._prev.token_type
    3953
    3954            if token_type == TokenType.UNION:
    3955                operation = exp.Union
    3956            elif token_type == TokenType.EXCEPT:
    3957                operation = exp.Except
    3958            else:
    3959                operation = exp.Intersect
    3960
    3961            comments = self._prev.comments
    3962            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
    3963            by_name = self._match_text_seq("BY", "NAME")
    3964            expression = self._parse_select(nested=True, parse_set_operation=False)
    3965
    3966            this = self.expression(
    3967                operation,
    3968                comments=comments,
    3969                this=this,
    3970                distinct=distinct,
    3971                by_name=by_name,
    3972                expression=expression,
    3973            )
    3974
    3975        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
    3976            expression = this.expression
    3977
    3978            if expression:
    3979                for arg in self.UNION_MODIFIERS:
    3980                    expr = expression.args.get(arg)
    3981                    if expr:
    3982                        this.set(arg, expr.pop())
    3983
    3984        return this
    3985
    3986    def _parse_expression(self) -> t.Optional[exp.Expression]:
    3987        return self._parse_alias(self._parse_assignment())
    3988
    3989    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    3990        this = self._parse_disjunction()
    3991
    3992        while self._match_set(self.ASSIGNMENT):
    3993            this = self.expression(
    3994                self.ASSIGNMENT[self._prev.token_type],
    3995                this=this,
    3996                comments=self._prev_comments,
    3997                expression=self._parse_assignment(),
    3998            )
    3999
    4000        return this
    4001
    4002    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4003        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4004
    4005    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4006        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4007
    4008    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4009        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4010
    4011    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4012        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4013
    4014    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4015        this = this or self._parse_bitwise()
    4016        negate = self._match(TokenType.NOT)
    4017
    4018        if self._match_set(self.RANGE_PARSERS):
    4019            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4020            if not expression:
    4021                return this
    4022
    4023            this = expression
    4024        elif self._match(TokenType.ISNULL):
    4025            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4026
    4027        # Postgres supports ISNULL and NOTNULL for conditions.
    4028        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4029        if self._match(TokenType.NOTNULL):
    4030            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4031            this = self.expression(exp.Not, this=this)
    4032
    4033        if negate:
    4034            this = self.expression(exp.Not, this=this)
    4035
    4036        if self._match(TokenType.IS):
    4037            this = self._parse_is(this)
    4038
    4039        return this
    4040
    4041    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4042        index = self._index - 1
    4043        negate = self._match(TokenType.NOT)
    4044
    4045        if self._match_text_seq("DISTINCT", "FROM"):
    4046            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4047            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4048
    4049        expression = self._parse_null() or self._parse_boolean()
    4050        if not expression:
    4051            self._retreat(index)
    4052            return None
    4053
    4054        this = self.expression(exp.Is, this=this, expression=expression)
    4055        return self.expression(exp.Not, this=this) if negate else this
    4056
    4057    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4058        unnest = self._parse_unnest(with_alias=False)
    4059        if unnest:
    4060            this = self.expression(exp.In, this=this, unnest=unnest)
    4061        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4062            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4063            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4064
    4065            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4066                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4067            else:
    4068                this = self.expression(exp.In, this=this, expressions=expressions)
    4069
    4070            if matched_l_paren:
    4071                self._match_r_paren(this)
    4072            elif not self._match(TokenType.R_BRACKET, expression=this):
    4073                self.raise_error("Expecting ]")
    4074        else:
    4075            this = self.expression(exp.In, this=this, field=self._parse_field())
    4076
    4077        return this
    4078
    4079    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4080        low = self._parse_bitwise()
    4081        self._match(TokenType.AND)
    4082        high = self._parse_bitwise()
    4083        return self.expression(exp.Between, this=this, low=low, high=high)
    4084
    4085    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4086        if not self._match(TokenType.ESCAPE):
    4087            return this
    4088        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4089
    4090    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4091        index = self._index
    4092
    4093        if not self._match(TokenType.INTERVAL) and match_interval:
    4094            return None
    4095
    4096        if self._match(TokenType.STRING, advance=False):
    4097            this = self._parse_primary()
    4098        else:
    4099            this = self._parse_term()
    4100
    4101        if not this or (
    4102            isinstance(this, exp.Column)
    4103            and not this.table
    4104            and not this.this.quoted
    4105            and this.name.upper() == "IS"
    4106        ):
    4107            self._retreat(index)
    4108            return None
    4109
    4110        unit = self._parse_function() or (
    4111            not self._match(TokenType.ALIAS, advance=False)
    4112            and self._parse_var(any_token=True, upper=True)
    4113        )
    4114
    4115        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4116        # each INTERVAL expression into this canonical form so it's easy to transpile
    4117        if this and this.is_number:
    4118            this = exp.Literal.string(this.name)
    4119        elif this and this.is_string:
    4120            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4121            if len(parts) == 1:
    4122                if unit:
    4123                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4124                    self._retreat(self._index - 1)
    4125
    4126                this = exp.Literal.string(parts[0][0])
    4127                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4128
    4129        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4130            unit = self.expression(
    4131                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4132            )
    4133
    4134        interval = self.expression(exp.Interval, this=this, unit=unit)
    4135
    4136        index = self._index
    4137        self._match(TokenType.PLUS)
    4138
    4139        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4140        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4141            return self.expression(
    4142                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4143            )
    4144
    4145        self._retreat(index)
    4146        return interval
    4147
    4148    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4149        this = self._parse_term()
    4150
    4151        while True:
    4152            if self._match_set(self.BITWISE):
    4153                this = self.expression(
    4154                    self.BITWISE[self._prev.token_type],
    4155                    this=this,
    4156                    expression=self._parse_term(),
    4157                )
    4158            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4159                this = self.expression(
    4160                    exp.DPipe,
    4161                    this=this,
    4162                    expression=self._parse_term(),
    4163                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4164                )
    4165            elif self._match(TokenType.DQMARK):
    4166                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
    4167            elif self._match_pair(TokenType.LT, TokenType.LT):
    4168                this = self.expression(
    4169                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4170                )
    4171            elif self._match_pair(TokenType.GT, TokenType.GT):
    4172                this = self.expression(
    4173                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4174                )
    4175            else:
    4176                break
    4177
    4178        return this
    4179
    4180    def _parse_term(self) -> t.Optional[exp.Expression]:
    4181        return self._parse_tokens(self._parse_factor, self.TERM)
    4182
    4183    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4184        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4185        this = parse_method()
    4186
    4187        while self._match_set(self.FACTOR):
    4188            klass = self.FACTOR[self._prev.token_type]
    4189            comments = self._prev_comments
    4190            expression = parse_method()
    4191
    4192            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4193                self._retreat(self._index - 1)
    4194                return this
    4195
    4196            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4197
    4198            if isinstance(this, exp.Div):
    4199                this.args["typed"] = self.dialect.TYPED_DIVISION
    4200                this.args["safe"] = self.dialect.SAFE_DIVISION
    4201
    4202        return this
    4203
    4204    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    4205        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    4206
    4207    def _parse_unary(self) -> t.Optional[exp.Expression]:
    4208        if self._match_set(self.UNARY_PARSERS):
    4209            return self.UNARY_PARSERS[self._prev.token_type](self)
    4210        return self._parse_at_time_zone(self._parse_type())
    4211
    4212    def _parse_type(
    4213        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    4214    ) -> t.Optional[exp.Expression]:
    4215        interval = parse_interval and self._parse_interval()
    4216        if interval:
    4217            return interval
    4218
    4219        index = self._index
    4220        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    4221
    4222        if data_type:
    4223            index2 = self._index
    4224            this = self._parse_primary()
    4225
    4226            if isinstance(this, exp.Literal):
    4227                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    4228                if parser:
    4229                    return parser(self, this, data_type)
    4230
    4231                return self.expression(exp.Cast, this=this, to=data_type)
    4232
    4233            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    4234            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    4235            #
    4236            # If the index difference here is greater than 1, that means the parser itself must have
    4237            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    4238            #
    4239            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    4240            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    4241            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    4242            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    4243            #
    4244            # In these cases, we don't really want to return the converted type, but instead retreat
    4245            # and try to parse a Column or Identifier in the section below.
    4246            if data_type.expressions and index2 - index > 1:
    4247                self._retreat(index2)
    4248                return self._parse_column_ops(data_type)
    4249
    4250            self._retreat(index)
    4251
    4252        if fallback_to_identifier:
    4253            return self._parse_id_var()
    4254
    4255        this = self._parse_column()
    4256        return this and self._parse_column_ops(this)
    4257
    4258    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    4259        this = self._parse_type()
    4260        if not this:
    4261            return None
    4262
    4263        if isinstance(this, exp.Column) and not this.table:
    4264            this = exp.var(this.name.upper())
    4265
    4266        return self.expression(
    4267            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    4268        )
    4269
    4270    def _parse_types(
    4271        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    4272    ) -> t.Optional[exp.Expression]:
    4273        index = self._index
    4274
    4275        this: t.Optional[exp.Expression] = None
    4276        prefix = self._match_text_seq("SYSUDTLIB", ".")
    4277
    4278        if not self._match_set(self.TYPE_TOKENS):
    4279            identifier = allow_identifiers and self._parse_id_var(
    4280                any_token=False, tokens=(TokenType.VAR,)
    4281            )
    4282            if identifier:
    4283                tokens = self.dialect.tokenize(identifier.name)
    4284
    4285                if len(tokens) != 1:
    4286                    self.raise_error("Unexpected identifier", self._prev)
    4287
    4288                if tokens[0].token_type in self.TYPE_TOKENS:
    4289                    self._prev = tokens[0]
    4290                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    4291                    type_name = identifier.name
    4292
    4293                    while self._match(TokenType.DOT):
    4294                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    4295
    4296                    this = exp.DataType.build(type_name, udt=True)
    4297                else:
    4298                    self._retreat(self._index - 1)
    4299                    return None
    4300            else:
    4301                return None
    4302
    4303        type_token = self._prev.token_type
    4304
    4305        if type_token == TokenType.PSEUDO_TYPE:
    4306            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    4307
    4308        if type_token == TokenType.OBJECT_IDENTIFIER:
    4309            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    4310
    4311        # https://materialize.com/docs/sql/types/map/
    4312        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    4313            key_type = self._parse_types(
    4314                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4315            )
    4316            if not self._match(TokenType.FARROW):
    4317                self._retreat(index)
    4318                return None
    4319
    4320            value_type = self._parse_types(
    4321                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4322            )
    4323            if not self._match(TokenType.R_BRACKET):
    4324                self._retreat(index)
    4325                return None
    4326
    4327            return exp.DataType(
    4328                this=exp.DataType.Type.MAP,
    4329                expressions=[key_type, value_type],
    4330                nested=True,
    4331                prefix=prefix,
    4332            )
    4333
    4334        nested = type_token in self.NESTED_TYPE_TOKENS
    4335        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    4336        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    4337        expressions = None
    4338        maybe_func = False
    4339
    4340        if self._match(TokenType.L_PAREN):
    4341            if is_struct:
    4342                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    4343            elif nested:
    4344                expressions = self._parse_csv(
    4345                    lambda: self._parse_types(
    4346                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4347                    )
    4348                )
    4349            elif type_token in self.ENUM_TYPE_TOKENS:
    4350                expressions = self._parse_csv(self._parse_equality)
    4351            elif is_aggregate:
    4352                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    4353                    any_token=False, tokens=(TokenType.VAR,)
    4354                )
    4355                if not func_or_ident or not self._match(TokenType.COMMA):
    4356                    return None
    4357                expressions = self._parse_csv(
    4358                    lambda: self._parse_types(
    4359                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4360                    )
    4361                )
    4362                expressions.insert(0, func_or_ident)
    4363            else:
    4364                expressions = self._parse_csv(self._parse_type_size)
    4365
    4366            if not expressions or not self._match(TokenType.R_PAREN):
    4367                self._retreat(index)
    4368                return None
    4369
    4370            maybe_func = True
    4371
    4372        values: t.Optional[t.List[exp.Expression]] = None
    4373
    4374        if nested and self._match(TokenType.LT):
    4375            if is_struct:
    4376                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    4377            else:
    4378                expressions = self._parse_csv(
    4379                    lambda: self._parse_types(
    4380                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    4381                    )
    4382                )
    4383
    4384            if not self._match(TokenType.GT):
    4385                self.raise_error("Expecting >")
    4386
    4387            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    4388                values = self._parse_csv(self._parse_assignment)
    4389                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    4390
    4391        if type_token in self.TIMESTAMPS:
    4392            if self._match_text_seq("WITH", "TIME", "ZONE"):
    4393                maybe_func = False
    4394                tz_type = (
    4395                    exp.DataType.Type.TIMETZ
    4396                    if type_token in self.TIMES
    4397                    else exp.DataType.Type.TIMESTAMPTZ
    4398                )
    4399                this = exp.DataType(this=tz_type, expressions=expressions)
    4400            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    4401                maybe_func = False
    4402                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    4403            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    4404                maybe_func = False
    4405        elif type_token == TokenType.INTERVAL:
    4406            unit = self._parse_var(upper=True)
    4407            if unit:
    4408                if self._match_text_seq("TO"):
    4409                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    4410
    4411                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    4412            else:
    4413                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    4414
    4415        if maybe_func and check_func:
    4416            index2 = self._index
    4417            peek = self._parse_string()
    4418
    4419            if not peek:
    4420                self._retreat(index)
    4421                return None
    4422
    4423            self._retreat(index2)
    4424
    4425        if not this:
    4426            if self._match_text_seq("UNSIGNED"):
    4427                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    4428                if not unsigned_type_token:
    4429                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    4430
    4431                type_token = unsigned_type_token or type_token
    4432
    4433            this = exp.DataType(
    4434                this=exp.DataType.Type[type_token.value],
    4435                expressions=expressions,
    4436                nested=nested,
    4437                values=values,
    4438                prefix=prefix,
    4439            )
    4440        elif expressions:
    4441            this.set("expressions", expressions)
    4442
    4443        # https://materialize.com/docs/sql/types/list/#type-name
    4444        while self._match(TokenType.LIST):
    4445            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    4446
    4447        index = self._index
    4448
    4449        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    4450        matched_array = self._match(TokenType.ARRAY)
    4451
    4452        while self._curr:
    4453            matched_l_bracket = self._match(TokenType.L_BRACKET)
    4454            if not matched_l_bracket and not matched_array:
    4455                break
    4456
    4457            matched_array = False
    4458            values = self._parse_csv(self._parse_assignment) or None
    4459            if values and not schema:
    4460                self._retreat(index)
    4461                break
    4462
    4463            this = exp.DataType(
    4464                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    4465            )
    4466            self._match(TokenType.R_BRACKET)
    4467
    4468        if self.TYPE_CONVERTER and isinstance(this.this, exp.DataType.Type):
    4469            converter = self.TYPE_CONVERTER.get(this.this)
    4470            if converter:
    4471                this = converter(t.cast(exp.DataType, this))
    4472
    4473        return this
    4474
    4475    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    4476        index = self._index
    4477        this = (
    4478            self._parse_type(parse_interval=False, fallback_to_identifier=True)
    4479            or self._parse_id_var()
    4480        )
    4481        self._match(TokenType.COLON)
    4482
    4483        if (
    4484            type_required
    4485            and not isinstance(this, exp.DataType)
    4486            and not self._match_set(self.TYPE_TOKENS, advance=False)
    4487        ):
    4488            self._retreat(index)
    4489            return self._parse_types()
    4490
    4491        return self._parse_column_def(this)
    4492
    4493    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4494        if not self._match_text_seq("AT", "TIME", "ZONE"):
    4495            return this
    4496        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    4497
    4498    def _parse_column(self) -> t.Optional[exp.Expression]:
    4499        this = self._parse_column_reference()
    4500        return self._parse_column_ops(this) if this else self._parse_bracket(this)
    4501
    4502    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    4503        this = self._parse_field()
    4504        if (
    4505            not this
    4506            and self._match(TokenType.VALUES, advance=False)
    4507            and self.VALUES_FOLLOWED_BY_PAREN
    4508            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    4509        ):
    4510            this = self._parse_id_var()
    4511
    4512        if isinstance(this, exp.Identifier):
    4513            # We bubble up comments from the Identifier to the Column
    4514            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    4515
    4516        return this
    4517
    4518    def _parse_colon_as_json_extract(
    4519        self, this: t.Optional[exp.Expression]
    4520    ) -> t.Optional[exp.Expression]:
    4521        casts = []
    4522        json_path = []
    4523
    4524        while self._match(TokenType.COLON):
    4525            start_index = self._index
    4526            path = self._parse_column_ops(self._parse_field(any_token=True))
    4527
    4528            # The cast :: operator has a lower precedence than the extraction operator :, so
    4529            # we rearrange the AST appropriately to avoid casting the JSON path
    4530            while isinstance(path, exp.Cast):
    4531                casts.append(path.to)
    4532                path = path.this
    4533
    4534            if casts:
    4535                dcolon_offset = next(
    4536                    i
    4537                    for i, t in enumerate(self._tokens[start_index:])
    4538                    if t.token_type == TokenType.DCOLON
    4539                )
    4540                end_token = self._tokens[start_index + dcolon_offset - 1]
    4541            else:
    4542                end_token = self._prev
    4543
    4544            if path:
    4545                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    4546
    4547        if json_path:
    4548            this = self.expression(
    4549                exp.JSONExtract,
    4550                this=this,
    4551                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
    4552            )
    4553
    4554            while casts:
    4555                this = self.expression(exp.Cast, this=this, to=casts.pop())
    4556
    4557        return this
    4558
    4559    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4560        this = self._parse_bracket(this)
    4561
    4562        while self._match_set(self.COLUMN_OPERATORS):
    4563            op_token = self._prev.token_type
    4564            op = self.COLUMN_OPERATORS.get(op_token)
    4565
    4566            if op_token == TokenType.DCOLON:
    4567                field = self._parse_types()
    4568                if not field:
    4569                    self.raise_error("Expected type")
    4570            elif op and self._curr:
    4571                field = self._parse_column_reference()
    4572            else:
    4573                field = self._parse_field(any_token=True, anonymous_func=True)
    4574
    4575            if isinstance(field, exp.Func) and this:
    4576                # bigquery allows function calls like x.y.count(...)
    4577                # SAFE.SUBSTR(...)
    4578                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    4579                this = exp.replace_tree(
    4580                    this,
    4581                    lambda n: (
    4582                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    4583                        if n.table
    4584                        else n.this
    4585                    )
    4586                    if isinstance(n, exp.Column)
    4587                    else n,
    4588                )
    4589
    4590            if op:
    4591                this = op(self, this, field)
    4592            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    4593                this = self.expression(
    4594                    exp.Column,
    4595                    this=field,
    4596                    table=this.this,
    4597                    db=this.args.get("table"),
    4598                    catalog=this.args.get("db"),
    4599                )
    4600            else:
    4601                this = self.expression(exp.Dot, this=this, expression=field)
    4602
    4603            this = self._parse_bracket(this)
    4604
    4605        return self._parse_colon_as_json_extract(this) if self.COLON_IS_JSON_EXTRACT else this
    4606
    4607    def _parse_primary(self) -> t.Optional[exp.Expression]:
    4608        if self._match_set(self.PRIMARY_PARSERS):
    4609            token_type = self._prev.token_type
    4610            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    4611
    4612            if token_type == TokenType.STRING:
    4613                expressions = [primary]
    4614                while self._match(TokenType.STRING):
    4615                    expressions.append(exp.Literal.string(self._prev.text))
    4616
    4617                if len(expressions) > 1:
    4618                    return self.expression(exp.Concat, expressions=expressions)
    4619
    4620            return primary
    4621
    4622        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    4623            return exp.Literal.number(f"0.{self._prev.text}")
    4624
    4625        if self._match(TokenType.L_PAREN):
    4626            comments = self._prev_comments
    4627            query = self._parse_select()
    4628
    4629            if query:
    4630                expressions = [query]
    4631            else:
    4632                expressions = self._parse_expressions()
    4633
    4634            this = self._parse_query_modifiers(seq_get(expressions, 0))
    4635
    4636            if not this and self._match(TokenType.R_PAREN, advance=False):
    4637                this = self.expression(exp.Tuple)
    4638            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    4639                this = self._parse_subquery(this=this, parse_alias=False)
    4640            elif isinstance(this, exp.Subquery):
    4641                this = self._parse_subquery(
    4642                    this=self._parse_set_operations(this), parse_alias=False
    4643                )
    4644            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    4645                this = self.expression(exp.Tuple, expressions=expressions)
    4646            else:
    4647                this = self.expression(exp.Paren, this=this)
    4648
    4649            if this:
    4650                this.add_comments(comments)
    4651
    4652            self._match_r_paren(expression=this)
    4653            return this
    4654
    4655        return None
    4656
    4657    def _parse_field(
    4658        self,
    4659        any_token: bool = False,
    4660        tokens: t.Optional[t.Collection[TokenType]] = None,
    4661        anonymous_func: bool = False,
    4662    ) -> t.Optional[exp.Expression]:
    4663        if anonymous_func:
    4664            field = (
    4665                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    4666                or self._parse_primary()
    4667            )
    4668        else:
    4669            field = self._parse_primary() or self._parse_function(
    4670                anonymous=anonymous_func, any_token=any_token
    4671            )
    4672        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    4673
    4674    def _parse_function(
    4675        self,
    4676        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4677        anonymous: bool = False,
    4678        optional_parens: bool = True,
    4679        any_token: bool = False,
    4680    ) -> t.Optional[exp.Expression]:
    4681        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    4682        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    4683        fn_syntax = False
    4684        if (
    4685            self._match(TokenType.L_BRACE, advance=False)
    4686            and self._next
    4687            and self._next.text.upper() == "FN"
    4688        ):
    4689            self._advance(2)
    4690            fn_syntax = True
    4691
    4692        func = self._parse_function_call(
    4693            functions=functions,
    4694            anonymous=anonymous,
    4695            optional_parens=optional_parens,
    4696            any_token=any_token,
    4697        )
    4698
    4699        if fn_syntax:
    4700            self._match(TokenType.R_BRACE)
    4701
    4702        return func
    4703
    4704    def _parse_function_call(
    4705        self,
    4706        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    4707        anonymous: bool = False,
    4708        optional_parens: bool = True,
    4709        any_token: bool = False,
    4710    ) -> t.Optional[exp.Expression]:
    4711        if not self._curr:
    4712            return None
    4713
    4714        comments = self._curr.comments
    4715        token_type = self._curr.token_type
    4716        this = self._curr.text
    4717        upper = this.upper()
    4718
    4719        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    4720        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    4721            self._advance()
    4722            return self._parse_window(parser(self))
    4723
    4724        if not self._next or self._next.token_type != TokenType.L_PAREN:
    4725            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    4726                self._advance()
    4727                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    4728
    4729            return None
    4730
    4731        if any_token:
    4732            if token_type in self.RESERVED_TOKENS:
    4733                return None
    4734        elif token_type not in self.FUNC_TOKENS:
    4735            return None
    4736
    4737        self._advance(2)
    4738
    4739        parser = self.FUNCTION_PARSERS.get(upper)
    4740        if parser and not anonymous:
    4741            this = parser(self)
    4742        else:
    4743            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    4744
    4745            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    4746                this = self.expression(subquery_predicate, this=self._parse_select())
    4747                self._match_r_paren()
    4748                return this
    4749
    4750            if functions is None:
    4751                functions = self.FUNCTIONS
    4752
    4753            function = functions.get(upper)
    4754
    4755            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    4756            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    4757
    4758            if alias:
    4759                args = self._kv_to_prop_eq(args)
    4760
    4761            if function and not anonymous:
    4762                if "dialect" in function.__code__.co_varnames:
    4763                    func = function(args, dialect=self.dialect)
    4764                else:
    4765                    func = function(args)
    4766
    4767                func = self.validate_expression(func, args)
    4768                if not self.dialect.NORMALIZE_FUNCTIONS:
    4769                    func.meta["name"] = this
    4770
    4771                this = func
    4772            else:
    4773                if token_type == TokenType.IDENTIFIER:
    4774                    this = exp.Identifier(this=this, quoted=True)
    4775                this = self.expression(exp.Anonymous, this=this, expressions=args)
    4776
    4777        if isinstance(this, exp.Expression):
    4778            this.add_comments(comments)
    4779
    4780        self._match_r_paren(this)
    4781        return self._parse_window(this)
    4782
    4783    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    4784        transformed = []
    4785
    4786        for e in expressions:
    4787            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    4788                if isinstance(e, exp.Alias):
    4789                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    4790
    4791                if not isinstance(e, exp.PropertyEQ):
    4792                    e = self.expression(
    4793                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    4794                    )
    4795
    4796                if isinstance(e.this, exp.Column):
    4797                    e.this.replace(e.this.this)
    4798
    4799            transformed.append(e)
    4800
    4801        return transformed
    4802
    4803    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    4804        return self._parse_column_def(self._parse_id_var())
    4805
    4806    def _parse_user_defined_function(
    4807        self, kind: t.Optional[TokenType] = None
    4808    ) -> t.Optional[exp.Expression]:
    4809        this = self._parse_id_var()
    4810
    4811        while self._match(TokenType.DOT):
    4812            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
    4813
    4814        if not self._match(TokenType.L_PAREN):
    4815            return this
    4816
    4817        expressions = self._parse_csv(self._parse_function_parameter)
    4818        self._match_r_paren()
    4819        return self.expression(
    4820            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    4821        )
    4822
    4823    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    4824        literal = self._parse_primary()
    4825        if literal:
    4826            return self.expression(exp.Introducer, this=token.text, expression=literal)
    4827
    4828        return self.expression(exp.Identifier, this=token.text)
    4829
    4830    def _parse_session_parameter(self) -> exp.SessionParameter:
    4831        kind = None
    4832        this = self._parse_id_var() or self._parse_primary()
    4833
    4834        if this and self._match(TokenType.DOT):
    4835            kind = this.name
    4836            this = self._parse_var() or self._parse_primary()
    4837
    4838        return self.expression(exp.SessionParameter, this=this, kind=kind)
    4839
    4840    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    4841        return self._parse_id_var()
    4842
    4843    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    4844        index = self._index
    4845
    4846        if self._match(TokenType.L_PAREN):
    4847            expressions = t.cast(
    4848                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    4849            )
    4850
    4851            if not self._match(TokenType.R_PAREN):
    4852                self._retreat(index)
    4853        else:
    4854            expressions = [self._parse_lambda_arg()]
    4855
    4856        if self._match_set(self.LAMBDAS):
    4857            return self.LAMBDAS[self._prev.token_type](self, expressions)
    4858
    4859        self._retreat(index)
    4860
    4861        this: t.Optional[exp.Expression]
    4862
    4863        if self._match(TokenType.DISTINCT):
    4864            this = self.expression(
    4865                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    4866            )
    4867        else:
    4868            this = self._parse_select_or_expression(alias=alias)
    4869
    4870        return self._parse_limit(
    4871            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    4872        )
    4873
    4874    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4875        index = self._index
    4876        if not self._match(TokenType.L_PAREN):
    4877            return this
    4878
    4879        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    4880        # expr can be of both types
    4881        if self._match_set(self.SELECT_START_TOKENS):
    4882            self._retreat(index)
    4883            return this
    4884        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    4885        self._match_r_paren()
    4886        return self.expression(exp.Schema, this=this, expressions=args)
    4887
    4888    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    4889        return self._parse_column_def(self._parse_field(any_token=True))
    4890
    4891    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4892        # column defs are not really columns, they're identifiers
    4893        if isinstance(this, exp.Column):
    4894            this = this.this
    4895
    4896        kind = self._parse_types(schema=True)
    4897
    4898        if self._match_text_seq("FOR", "ORDINALITY"):
    4899            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    4900
    4901        constraints: t.List[exp.Expression] = []
    4902
    4903        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    4904            ("ALIAS", "MATERIALIZED")
    4905        ):
    4906            persisted = self._prev.text.upper() == "MATERIALIZED"
    4907            constraints.append(
    4908                self.expression(
    4909                    exp.ComputedColumnConstraint,
    4910                    this=self._parse_assignment(),
    4911                    persisted=persisted or self._match_text_seq("PERSISTED"),
    4912                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    4913                )
    4914            )
    4915        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
    4916            self._match(TokenType.ALIAS)
    4917            constraints.append(
    4918                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
    4919            )
    4920
    4921        while True:
    4922            constraint = self._parse_column_constraint()
    4923            if not constraint:
    4924                break
    4925            constraints.append(constraint)
    4926
    4927        if not kind and not constraints:
    4928            return this
    4929
    4930        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    4931
    4932    def _parse_auto_increment(
    4933        self,
    4934    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    4935        start = None
    4936        increment = None
    4937
    4938        if self._match(TokenType.L_PAREN, advance=False):
    4939            args = self._parse_wrapped_csv(self._parse_bitwise)
    4940            start = seq_get(args, 0)
    4941            increment = seq_get(args, 1)
    4942        elif self._match_text_seq("START"):
    4943            start = self._parse_bitwise()
    4944            self._match_text_seq("INCREMENT")
    4945            increment = self._parse_bitwise()
    4946
    4947        if start and increment:
    4948            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
    4949
    4950        return exp.AutoIncrementColumnConstraint()
    4951
    4952    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    4953        if not self._match_text_seq("REFRESH"):
    4954            self._retreat(self._index - 1)
    4955            return None
    4956        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    4957
    4958    def _parse_compress(self) -> exp.CompressColumnConstraint:
    4959        if self._match(TokenType.L_PAREN, advance=False):
    4960            return self.expression(
    4961                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    4962            )
    4963
    4964        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    4965
    4966    def _parse_generated_as_identity(
    4967        self,
    4968    ) -> (
    4969        exp.GeneratedAsIdentityColumnConstraint
    4970        | exp.ComputedColumnConstraint
    4971        | exp.GeneratedAsRowColumnConstraint
    4972    ):
    4973        if self._match_text_seq("BY", "DEFAULT"):
    4974            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    4975            this = self.expression(
    4976                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    4977            )
    4978        else:
    4979            self._match_text_seq("ALWAYS")
    4980            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    4981
    4982        self._match(TokenType.ALIAS)
    4983
    4984        if self._match_text_seq("ROW"):
    4985            start = self._match_text_seq("START")
    4986            if not start:
    4987                self._match(TokenType.END)
    4988            hidden = self._match_text_seq("HIDDEN")
    4989            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    4990
    4991        identity = self._match_text_seq("IDENTITY")
    4992
    4993        if self._match(TokenType.L_PAREN):
    4994            if self._match(TokenType.START_WITH):
    4995                this.set("start", self._parse_bitwise())
    4996            if self._match_text_seq("INCREMENT", "BY"):
    4997                this.set("increment", self._parse_bitwise())
    4998            if self._match_text_seq("MINVALUE"):
    4999                this.set("minvalue", self._parse_bitwise())
    5000            if self._match_text_seq("MAXVALUE"):
    5001                this.set("maxvalue", self._parse_bitwise())
    5002
    5003            if self._match_text_seq("CYCLE"):
    5004                this.set("cycle", True)
    5005            elif self._match_text_seq("NO", "CYCLE"):
    5006                this.set("cycle", False)
    5007
    5008            if not identity:
    5009                this.set("expression", self._parse_range())
    5010            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5011                args = self._parse_csv(self._parse_bitwise)
    5012                this.set("start", seq_get(args, 0))
    5013                this.set("increment", seq_get(args, 1))
    5014
    5015            self._match_r_paren()
    5016
    5017        return this
    5018
    5019    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5020        self._match_text_seq("LENGTH")
    5021        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5022
    5023    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5024        if self._match_text_seq("NULL"):
    5025            return self.expression(exp.NotNullColumnConstraint)
    5026        if self._match_text_seq("CASESPECIFIC"):
    5027            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5028        if self._match_text_seq("FOR", "REPLICATION"):
    5029            return self.expression(exp.NotForReplicationColumnConstraint)
    5030        return None
    5031
    5032    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5033        if self._match(TokenType.CONSTRAINT):
    5034            this = self._parse_id_var()
    5035        else:
    5036            this = None
    5037
    5038        if self._match_texts(self.CONSTRAINT_PARSERS):
    5039            return self.expression(
    5040                exp.ColumnConstraint,
    5041                this=this,
    5042                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5043            )
    5044
    5045        return this
    5046
    5047    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5048        if not self._match(TokenType.CONSTRAINT):
    5049            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5050
    5051        return self.expression(
    5052            exp.Constraint,
    5053            this=self._parse_id_var(),
    5054            expressions=self._parse_unnamed_constraints(),
    5055        )
    5056
    5057    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5058        constraints = []
    5059        while True:
    5060            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5061            if not constraint:
    5062                break
    5063            constraints.append(constraint)
    5064
    5065        return constraints
    5066
    5067    def _parse_unnamed_constraint(
    5068        self, constraints: t.Optional[t.Collection[str]] = None
    5069    ) -> t.Optional[exp.Expression]:
    5070        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    5071            constraints or self.CONSTRAINT_PARSERS
    5072        ):
    5073            return None
    5074
    5075        constraint = self._prev.text.upper()
    5076        if constraint not in self.CONSTRAINT_PARSERS:
    5077            self.raise_error(f"No parser found for schema constraint {constraint}.")
    5078
    5079        return self.CONSTRAINT_PARSERS[constraint](self)
    5080
    5081    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    5082        self._match_text_seq("KEY")
    5083        return self.expression(
    5084            exp.UniqueColumnConstraint,
    5085            this=self._parse_schema(self._parse_id_var(any_token=False)),
    5086            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    5087            on_conflict=self._parse_on_conflict(),
    5088        )
    5089
    5090    def _parse_key_constraint_options(self) -> t.List[str]:
    5091        options = []
    5092        while True:
    5093            if not self._curr:
    5094                break
    5095
    5096            if self._match(TokenType.ON):
    5097                action = None
    5098                on = self._advance_any() and self._prev.text
    5099
    5100                if self._match_text_seq("NO", "ACTION"):
    5101                    action = "NO ACTION"
    5102                elif self._match_text_seq("CASCADE"):
    5103                    action = "CASCADE"
    5104                elif self._match_text_seq("RESTRICT"):
    5105                    action = "RESTRICT"
    5106                elif self._match_pair(TokenType.SET, TokenType.NULL):
    5107                    action = "SET NULL"
    5108                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    5109                    action = "SET DEFAULT"
    5110                else:
    5111                    self.raise_error("Invalid key constraint")
    5112
    5113                options.append(f"ON {on} {action}")
    5114            elif self._match_text_seq("NOT", "ENFORCED"):
    5115                options.append("NOT ENFORCED")
    5116            elif self._match_text_seq("DEFERRABLE"):
    5117                options.append("DEFERRABLE")
    5118            elif self._match_text_seq("INITIALLY", "DEFERRED"):
    5119                options.append("INITIALLY DEFERRED")
    5120            elif self._match_text_seq("NORELY"):
    5121                options.append("NORELY")
    5122            elif self._match_text_seq("MATCH", "FULL"):
    5123                options.append("MATCH FULL")
    5124            else:
    5125                break
    5126
    5127        return options
    5128
    5129    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    5130        if match and not self._match(TokenType.REFERENCES):
    5131            return None
    5132
    5133        expressions = None
    5134        this = self._parse_table(schema=True)
    5135        options = self._parse_key_constraint_options()
    5136        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    5137
    5138    def _parse_foreign_key(self) -> exp.ForeignKey:
    5139        expressions = self._parse_wrapped_id_vars()
    5140        reference = self._parse_references()
    5141        options = {}
    5142
    5143        while self._match(TokenType.ON):
    5144            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    5145                self.raise_error("Expected DELETE or UPDATE")
    5146
    5147            kind = self._prev.text.lower()
    5148
    5149            if self._match_text_seq("NO", "ACTION"):
    5150                action = "NO ACTION"
    5151            elif self._match(TokenType.SET):
    5152                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    5153                action = "SET " + self._prev.text.upper()
    5154            else:
    5155                self._advance()
    5156                action = self._prev.text.upper()
    5157
    5158            options[kind] = action
    5159
    5160        return self.expression(
    5161            exp.ForeignKey,
    5162            expressions=expressions,
    5163            reference=reference,
    5164            **options,  # type: ignore
    5165        )
    5166
    5167    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    5168        return self._parse_field()
    5169
    5170    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    5171        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    5172            self._retreat(self._index - 1)
    5173            return None
    5174
    5175        id_vars = self._parse_wrapped_id_vars()
    5176        return self.expression(
    5177            exp.PeriodForSystemTimeConstraint,
    5178            this=seq_get(id_vars, 0),
    5179            expression=seq_get(id_vars, 1),
    5180        )
    5181
    5182    def _parse_primary_key(
    5183        self, wrapped_optional: bool = False, in_props: bool = False
    5184    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    5185        desc = (
    5186            self._match_set((TokenType.ASC, TokenType.DESC))
    5187            and self._prev.token_type == TokenType.DESC
    5188        )
    5189
    5190        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    5191            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
    5192
    5193        expressions = self._parse_wrapped_csv(
    5194            self._parse_primary_key_part, optional=wrapped_optional
    5195        )
    5196        options = self._parse_key_constraint_options()
    5197        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    5198
    5199    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    5200        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    5201
    5202    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5203        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    5204            return this
    5205
    5206        bracket_kind = self._prev.token_type
    5207        expressions = self._parse_csv(
    5208            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    5209        )
    5210
    5211        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    5212            self.raise_error("Expected ]")
    5213        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    5214            self.raise_error("Expected }")
    5215
    5216        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    5217        if bracket_kind == TokenType.L_BRACE:
    5218            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    5219        elif not this:
    5220            this = self.expression(exp.Array, expressions=expressions)
    5221        else:
    5222            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    5223            if constructor_type:
    5224                return self.expression(constructor_type, expressions=expressions)
    5225
    5226            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
    5227            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    5228
    5229        self._add_comments(this)
    5230        return self._parse_bracket(this)
    5231
    5232    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5233        if self._match(TokenType.COLON):
    5234            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    5235        return this
    5236
    5237    def _parse_case(self) -> t.Optional[exp.Expression]:
    5238        ifs = []
    5239        default = None
    5240
    5241        comments = self._prev_comments
    5242        expression = self._parse_assignment()
    5243
    5244        while self._match(TokenType.WHEN):
    5245            this = self._parse_assignment()
    5246            self._match(TokenType.THEN)
    5247            then = self._parse_assignment()
    5248            ifs.append(self.expression(exp.If, this=this, true=then))
    5249
    5250        if self._match(TokenType.ELSE):
    5251            default = self._parse_assignment()
    5252
    5253        if not self._match(TokenType.END):
    5254            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    5255                default = exp.column("interval")
    5256            else:
    5257                self.raise_error("Expected END after CASE", self._prev)
    5258
    5259        return self.expression(
    5260            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    5261        )
    5262
    5263    def _parse_if(self) -> t.Optional[exp.Expression]:
    5264        if self._match(TokenType.L_PAREN):
    5265            args = self._parse_csv(self._parse_assignment)
    5266            this = self.validate_expression(exp.If.from_arg_list(args), args)
    5267            self._match_r_paren()
    5268        else:
    5269            index = self._index - 1
    5270
    5271            if self.NO_PAREN_IF_COMMANDS and index == 0:
    5272                return self._parse_as_command(self._prev)
    5273
    5274            condition = self._parse_assignment()
    5275
    5276            if not condition:
    5277                self._retreat(index)
    5278                return None
    5279
    5280            self._match(TokenType.THEN)
    5281            true = self._parse_assignment()
    5282            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    5283            self._match(TokenType.END)
    5284            this = self.expression(exp.If, this=condition, true=true, false=false)
    5285
    5286        return this
    5287
    5288    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    5289        if not self._match_text_seq("VALUE", "FOR"):
    5290            self._retreat(self._index - 1)
    5291            return None
    5292
    5293        return self.expression(
    5294            exp.NextValueFor,
    5295            this=self._parse_column(),
    5296            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    5297        )
    5298
    5299    def _parse_extract(self) -> exp.Extract:
    5300        this = self._parse_function() or self._parse_var() or self._parse_type()
    5301
    5302        if self._match(TokenType.FROM):
    5303            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    5304
    5305        if not self._match(TokenType.COMMA):
    5306            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    5307
    5308        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    5309
    5310    def _parse_gap_fill(self) -> exp.GapFill:
    5311        self._match(TokenType.TABLE)
    5312        this = self._parse_table()
    5313
    5314        self._match(TokenType.COMMA)
    5315        args = [this, *self._parse_csv(self._parse_lambda)]
    5316
    5317        gap_fill = exp.GapFill.from_arg_list(args)
    5318        return self.validate_expression(gap_fill, args)
    5319
    5320    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    5321        this = self._parse_assignment()
    5322
    5323        if not self._match(TokenType.ALIAS):
    5324            if self._match(TokenType.COMMA):
    5325                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    5326
    5327            self.raise_error("Expected AS after CAST")
    5328
    5329        fmt = None
    5330        to = self._parse_types()
    5331
    5332        if self._match(TokenType.FORMAT):
    5333            fmt_string = self._parse_string()
    5334            fmt = self._parse_at_time_zone(fmt_string)
    5335
    5336            if not to:
    5337                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    5338            if to.this in exp.DataType.TEMPORAL_TYPES:
    5339                this = self.expression(
    5340                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    5341                    this=this,
    5342                    format=exp.Literal.string(
    5343                        format_time(
    5344                            fmt_string.this if fmt_string else "",
    5345                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    5346                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    5347                        )
    5348                    ),
    5349                )
    5350
    5351                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    5352                    this.set("zone", fmt.args["zone"])
    5353                return this
    5354        elif not to:
    5355            self.raise_error("Expected TYPE after CAST")
    5356        elif isinstance(to, exp.Identifier):
    5357            to = exp.DataType.build(to.name, udt=True)
    5358        elif to.this == exp.DataType.Type.CHAR:
    5359            if self._match(TokenType.CHARACTER_SET):
    5360                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    5361
    5362        return self.expression(
    5363            exp.Cast if strict else exp.TryCast,
    5364            this=this,
    5365            to=to,
    5366            format=fmt,
    5367            safe=safe,
    5368            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    5369        )
    5370
    5371    def _parse_string_agg(self) -> exp.Expression:
    5372        if self._match(TokenType.DISTINCT):
    5373            args: t.List[t.Optional[exp.Expression]] = [
    5374                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    5375            ]
    5376            if self._match(TokenType.COMMA):
    5377                args.extend(self._parse_csv(self._parse_assignment))
    5378        else:
    5379            args = self._parse_csv(self._parse_assignment)  # type: ignore
    5380
    5381        index = self._index
    5382        if not self._match(TokenType.R_PAREN) and args:
    5383            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    5384            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    5385            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
    5386            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    5387
    5388        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    5389        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    5390        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    5391        if not self._match_text_seq("WITHIN", "GROUP"):
    5392            self._retreat(index)
    5393            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    5394
    5395        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
    5396        order = self._parse_order(this=seq_get(args, 0))
    5397        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
    5398
    5399    def _parse_convert(
    5400        self, strict: bool, safe: t.Optional[bool] = None
    5401    ) -> t.Optional[exp.Expression]:
    5402        this = self._parse_bitwise()
    5403
    5404        if self._match(TokenType.USING):
    5405            to: t.Optional[exp.Expression] = self.expression(
    5406                exp.CharacterSet, this=self._parse_var()
    5407            )
    5408        elif self._match(TokenType.COMMA):
    5409            to = self._parse_types()
    5410        else:
    5411            to = None
    5412
    5413        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    5414
    5415    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    5416        """
    5417        There are generally two variants of the DECODE function:
    5418
    5419        - DECODE(bin, charset)
    5420        - DECODE(expression, search, result [, search, result] ... [, default])
    5421
    5422        The second variant will always be parsed into a CASE expression. Note that NULL
    5423        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    5424        instead of relying on pattern matching.
    5425        """
    5426        args = self._parse_csv(self._parse_assignment)
    5427
    5428        if len(args) < 3:
    5429            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    5430
    5431        expression, *expressions = args
    5432        if not expression:
    5433            return None
    5434
    5435        ifs = []
    5436        for search, result in zip(expressions[::2], expressions[1::2]):
    5437            if not search or not result:
    5438                return None
    5439
    5440            if isinstance(search, exp.Literal):
    5441                ifs.append(
    5442                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    5443                )
    5444            elif isinstance(search, exp.Null):
    5445                ifs.append(
    5446                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    5447                )
    5448            else:
    5449                cond = exp.or_(
    5450                    exp.EQ(this=expression.copy(), expression=search),
    5451                    exp.and_(
    5452                        exp.Is(this=expression.copy(), expression=exp.Null()),
    5453                        exp.Is(this=search.copy(), expression=exp.Null()),
    5454                        copy=False,
    5455                    ),
    5456                    copy=False,
    5457                )
    5458                ifs.append(exp.If(this=cond, true=result))
    5459
    5460        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    5461
    5462    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    5463        self._match_text_seq("KEY")
    5464        key = self._parse_column()
    5465        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    5466        self._match_text_seq("VALUE")
    5467        value = self._parse_bitwise()
    5468
    5469        if not key and not value:
    5470            return None
    5471        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    5472
    5473    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5474        if not this or not self._match_text_seq("FORMAT", "JSON"):
    5475            return this
    5476
    5477        return self.expression(exp.FormatJson, this=this)
    5478
    5479    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
    5480        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
    5481        for value in values:
    5482            if self._match_text_seq(value, "ON", on):
    5483                return f"{value} ON {on}"
    5484
    5485        return None
    5486
    5487    @t.overload
    5488    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    5489
    5490    @t.overload
    5491    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    5492
    5493    def _parse_json_object(self, agg=False):
    5494        star = self._parse_star()
    5495        expressions = (
    5496            [star]
    5497            if star
    5498            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    5499        )
    5500        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    5501
    5502        unique_keys = None
    5503        if self._match_text_seq("WITH", "UNIQUE"):
    5504            unique_keys = True
    5505        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    5506            unique_keys = False
    5507
    5508        self._match_text_seq("KEYS")
    5509
    5510        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    5511            self._parse_type()
    5512        )
    5513        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    5514
    5515        return self.expression(
    5516            exp.JSONObjectAgg if agg else exp.JSONObject,
    5517            expressions=expressions,
    5518            null_handling=null_handling,
    5519            unique_keys=unique_keys,
    5520            return_type=return_type,
    5521            encoding=encoding,
    5522        )
    5523
    5524    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    5525    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    5526        if not self._match_text_seq("NESTED"):
    5527            this = self._parse_id_var()
    5528            kind = self._parse_types(allow_identifiers=False)
    5529            nested = None
    5530        else:
    5531            this = None
    5532            kind = None
    5533            nested = True
    5534
    5535        path = self._match_text_seq("PATH") and self._parse_string()
    5536        nested_schema = nested and self._parse_json_schema()
    5537
    5538        return self.expression(
    5539            exp.JSONColumnDef,
    5540            this=this,
    5541            kind=kind,
    5542            path=path,
    5543            nested_schema=nested_schema,
    5544        )
    5545
    5546    def _parse_json_schema(self) -> exp.JSONSchema:
    5547        self._match_text_seq("COLUMNS")
    5548        return self.expression(
    5549            exp.JSONSchema,
    5550            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    5551        )
    5552
    5553    def _parse_json_table(self) -> exp.JSONTable:
    5554        this = self._parse_format_json(self._parse_bitwise())
    5555        path = self._match(TokenType.COMMA) and self._parse_string()
    5556        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    5557        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    5558        schema = self._parse_json_schema()
    5559
    5560        return exp.JSONTable(
    5561            this=this,
    5562            schema=schema,
    5563            path=path,
    5564            error_handling=error_handling,
    5565            empty_handling=empty_handling,
    5566        )
    5567
    5568    def _parse_match_against(self) -> exp.MatchAgainst:
    5569        expressions = self._parse_csv(self._parse_column)
    5570
    5571        self._match_text_seq(")", "AGAINST", "(")
    5572
    5573        this = self._parse_string()
    5574
    5575        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    5576            modifier = "IN NATURAL LANGUAGE MODE"
    5577            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5578                modifier = f"{modifier} WITH QUERY EXPANSION"
    5579        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    5580            modifier = "IN BOOLEAN MODE"
    5581        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    5582            modifier = "WITH QUERY EXPANSION"
    5583        else:
    5584            modifier = None
    5585
    5586        return self.expression(
    5587            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    5588        )
    5589
    5590    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    5591    def _parse_open_json(self) -> exp.OpenJSON:
    5592        this = self._parse_bitwise()
    5593        path = self._match(TokenType.COMMA) and self._parse_string()
    5594
    5595        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    5596            this = self._parse_field(any_token=True)
    5597            kind = self._parse_types()
    5598            path = self._parse_string()
    5599            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    5600
    5601            return self.expression(
    5602                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    5603            )
    5604
    5605        expressions = None
    5606        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    5607            self._match_l_paren()
    5608            expressions = self._parse_csv(_parse_open_json_column_def)
    5609
    5610        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    5611
    5612    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    5613        args = self._parse_csv(self._parse_bitwise)
    5614
    5615        if self._match(TokenType.IN):
    5616            return self.expression(
    5617                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    5618            )
    5619
    5620        if haystack_first:
    5621            haystack = seq_get(args, 0)
    5622            needle = seq_get(args, 1)
    5623        else:
    5624            needle = seq_get(args, 0)
    5625            haystack = seq_get(args, 1)
    5626
    5627        return self.expression(
    5628            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    5629        )
    5630
    5631    def _parse_predict(self) -> exp.Predict:
    5632        self._match_text_seq("MODEL")
    5633        this = self._parse_table()
    5634
    5635        self._match(TokenType.COMMA)
    5636        self._match_text_seq("TABLE")
    5637
    5638        return self.expression(
    5639            exp.Predict,
    5640            this=this,
    5641            expression=self._parse_table(),
    5642            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    5643        )
    5644
    5645    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    5646        args = self._parse_csv(self._parse_table)
    5647        return exp.JoinHint(this=func_name.upper(), expressions=args)
    5648
    5649    def _parse_substring(self) -> exp.Substring:
    5650        # Postgres supports the form: substring(string [from int] [for int])
    5651        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    5652
    5653        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    5654
    5655        if self._match(TokenType.FROM):
    5656            args.append(self._parse_bitwise())
    5657        if self._match(TokenType.FOR):
    5658            if len(args) == 1:
    5659                args.append(exp.Literal.number(1))
    5660            args.append(self._parse_bitwise())
    5661
    5662        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    5663
    5664    def _parse_trim(self) -> exp.Trim:
    5665        # https://www.w3resource.com/sql/character-functions/trim.php
    5666        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    5667
    5668        position = None
    5669        collation = None
    5670        expression = None
    5671
    5672        if self._match_texts(self.TRIM_TYPES):
    5673            position = self._prev.text.upper()
    5674
    5675        this = self._parse_bitwise()
    5676        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    5677            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    5678            expression = self._parse_bitwise()
    5679
    5680            if invert_order:
    5681                this, expression = expression, this
    5682
    5683        if self._match(TokenType.COLLATE):
    5684            collation = self._parse_bitwise()
    5685
    5686        return self.expression(
    5687            exp.Trim, this=this, position=position, expression=expression, collation=collation
    5688        )
    5689
    5690    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    5691        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    5692
    5693    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    5694        return self._parse_window(self._parse_id_var(), alias=True)
    5695
    5696    def _parse_respect_or_ignore_nulls(
    5697        self, this: t.Optional[exp.Expression]
    5698    ) -> t.Optional[exp.Expression]:
    5699        if self._match_text_seq("IGNORE", "NULLS"):
    5700            return self.expression(exp.IgnoreNulls, this=this)
    5701        if self._match_text_seq("RESPECT", "NULLS"):
    5702            return self.expression(exp.RespectNulls, this=this)
    5703        return this
    5704
    5705    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5706        if self._match(TokenType.HAVING):
    5707            self._match_texts(("MAX", "MIN"))
    5708            max = self._prev.text.upper() != "MIN"
    5709            return self.expression(
    5710                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    5711            )
    5712
    5713        return this
    5714
    5715    def _parse_window(
    5716        self, this: t.Optional[exp.Expression], alias: bool = False
    5717    ) -> t.Optional[exp.Expression]:
    5718        func = this
    5719        comments = func.comments if isinstance(func, exp.Expression) else None
    5720
    5721        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    5722            self._match(TokenType.WHERE)
    5723            this = self.expression(
    5724                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    5725            )
    5726            self._match_r_paren()
    5727
    5728        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    5729        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    5730        if self._match_text_seq("WITHIN", "GROUP"):
    5731            order = self._parse_wrapped(self._parse_order)
    5732            this = self.expression(exp.WithinGroup, this=this, expression=order)
    5733
    5734        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    5735        # Some dialects choose to implement and some do not.
    5736        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    5737
    5738        # There is some code above in _parse_lambda that handles
    5739        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    5740
    5741        # The below changes handle
    5742        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    5743
    5744        # Oracle allows both formats
    5745        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    5746        #   and Snowflake chose to do the same for familiarity
    5747        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    5748        if isinstance(this, exp.AggFunc):
    5749            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    5750
    5751            if ignore_respect and ignore_respect is not this:
    5752                ignore_respect.replace(ignore_respect.this)
    5753                this = self.expression(ignore_respect.__class__, this=this)
    5754
    5755        this = self._parse_respect_or_ignore_nulls(this)
    5756
    5757        # bigquery select from window x AS (partition by ...)
    5758        if alias:
    5759            over = None
    5760            self._match(TokenType.ALIAS)
    5761        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    5762            return this
    5763        else:
    5764            over = self._prev.text.upper()
    5765
    5766        if comments and isinstance(func, exp.Expression):
    5767            func.pop_comments()
    5768
    5769        if not self._match(TokenType.L_PAREN):
    5770            return self.expression(
    5771                exp.Window,
    5772                comments=comments,
    5773                this=this,
    5774                alias=self._parse_id_var(False),
    5775                over=over,
    5776            )
    5777
    5778        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    5779
    5780        first = self._match(TokenType.FIRST)
    5781        if self._match_text_seq("LAST"):
    5782            first = False
    5783
    5784        partition, order = self._parse_partition_and_order()
    5785        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    5786
    5787        if kind:
    5788            self._match(TokenType.BETWEEN)
    5789            start = self._parse_window_spec()
    5790            self._match(TokenType.AND)
    5791            end = self._parse_window_spec()
    5792
    5793            spec = self.expression(
    5794                exp.WindowSpec,
    5795                kind=kind,
    5796                start=start["value"],
    5797                start_side=start["side"],
    5798                end=end["value"],
    5799                end_side=end["side"],
    5800            )
    5801        else:
    5802            spec = None
    5803
    5804        self._match_r_paren()
    5805
    5806        window = self.expression(
    5807            exp.Window,
    5808            comments=comments,
    5809            this=this,
    5810            partition_by=partition,
    5811            order=order,
    5812            spec=spec,
    5813            alias=window_alias,
    5814            over=over,
    5815            first=first,
    5816        )
    5817
    5818        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    5819        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    5820            return self._parse_window(window, alias=alias)
    5821
    5822        return window
    5823
    5824    def _parse_partition_and_order(
    5825        self,
    5826    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    5827        return self._parse_partition_by(), self._parse_order()
    5828
    5829    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    5830        self._match(TokenType.BETWEEN)
    5831
    5832        return {
    5833            "value": (
    5834                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    5835                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    5836                or self._parse_bitwise()
    5837            ),
    5838            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    5839        }
    5840
    5841    def _parse_alias(
    5842        self, this: t.Optional[exp.Expression], explicit: bool = False
    5843    ) -> t.Optional[exp.Expression]:
    5844        any_token = self._match(TokenType.ALIAS)
    5845        comments = self._prev_comments or []
    5846
    5847        if explicit and not any_token:
    5848            return this
    5849
    5850        if self._match(TokenType.L_PAREN):
    5851            aliases = self.expression(
    5852                exp.Aliases,
    5853                comments=comments,
    5854                this=this,
    5855                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    5856            )
    5857            self._match_r_paren(aliases)
    5858            return aliases
    5859
    5860        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    5861            self.STRING_ALIASES and self._parse_string_as_identifier()
    5862        )
    5863
    5864        if alias:
    5865            comments.extend(alias.pop_comments())
    5866            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    5867            column = this.this
    5868
    5869            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    5870            if not this.comments and column and column.comments:
    5871                this.comments = column.pop_comments()
    5872
    5873        return this
    5874
    5875    def _parse_id_var(
    5876        self,
    5877        any_token: bool = True,
    5878        tokens: t.Optional[t.Collection[TokenType]] = None,
    5879    ) -> t.Optional[exp.Expression]:
    5880        expression = self._parse_identifier()
    5881        if not expression and (
    5882            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    5883        ):
    5884            quoted = self._prev.token_type == TokenType.STRING
    5885            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    5886
    5887        return expression
    5888
    5889    def _parse_string(self) -> t.Optional[exp.Expression]:
    5890        if self._match_set(self.STRING_PARSERS):
    5891            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    5892        return self._parse_placeholder()
    5893
    5894    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    5895        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    5896
    5897    def _parse_number(self) -> t.Optional[exp.Expression]:
    5898        if self._match_set(self.NUMERIC_PARSERS):
    5899            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    5900        return self._parse_placeholder()
    5901
    5902    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    5903        if self._match(TokenType.IDENTIFIER):
    5904            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    5905        return self._parse_placeholder()
    5906
    5907    def _parse_var(
    5908        self,
    5909        any_token: bool = False,
    5910        tokens: t.Optional[t.Collection[TokenType]] = None,
    5911        upper: bool = False,
    5912    ) -> t.Optional[exp.Expression]:
    5913        if (
    5914            (any_token and self._advance_any())
    5915            or self._match(TokenType.VAR)
    5916            or (self._match_set(tokens) if tokens else False)
    5917        ):
    5918            return self.expression(
    5919                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    5920            )
    5921        return self._parse_placeholder()
    5922
    5923    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    5924        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    5925            self._advance()
    5926            return self._prev
    5927        return None
    5928
    5929    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
    5930        return self._parse_var() or self._parse_string()
    5931
    5932    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    5933        return self._parse_primary() or self._parse_var(any_token=True)
    5934
    5935    def _parse_null(self) -> t.Optional[exp.Expression]:
    5936        if self._match_set(self.NULL_TOKENS):
    5937            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    5938        return self._parse_placeholder()
    5939
    5940    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    5941        if self._match(TokenType.TRUE):
    5942            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    5943        if self._match(TokenType.FALSE):
    5944            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    5945        return self._parse_placeholder()
    5946
    5947    def _parse_star(self) -> t.Optional[exp.Expression]:
    5948        if self._match(TokenType.STAR):
    5949            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    5950        return self._parse_placeholder()
    5951
    5952    def _parse_parameter(self) -> exp.Parameter:
    5953        this = self._parse_identifier() or self._parse_primary_or_var()
    5954        return self.expression(exp.Parameter, this=this)
    5955
    5956    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    5957        if self._match_set(self.PLACEHOLDER_PARSERS):
    5958            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    5959            if placeholder:
    5960                return placeholder
    5961            self._advance(-1)
    5962        return None
    5963
    5964    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    5965        if not self._match_texts(keywords):
    5966            return None
    5967        if self._match(TokenType.L_PAREN, advance=False):
    5968            return self._parse_wrapped_csv(self._parse_expression)
    5969
    5970        expression = self._parse_expression()
    5971        return [expression] if expression else None
    5972
    5973    def _parse_csv(
    5974        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    5975    ) -> t.List[exp.Expression]:
    5976        parse_result = parse_method()
    5977        items = [parse_result] if parse_result is not None else []
    5978
    5979        while self._match(sep):
    5980            self._add_comments(parse_result)
    5981            parse_result = parse_method()
    5982            if parse_result is not None:
    5983                items.append(parse_result)
    5984
    5985        return items
    5986
    5987    def _parse_tokens(
    5988        self, parse_method: t.Callable, expressions: t.Dict
    5989    ) -> t.Optional[exp.Expression]:
    5990        this = parse_method()
    5991
    5992        while self._match_set(expressions):
    5993            this = self.expression(
    5994                expressions[self._prev.token_type],
    5995                this=this,
    5996                comments=self._prev_comments,
    5997                expression=parse_method(),
    5998            )
    5999
    6000        return this
    6001
    6002    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    6003        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    6004
    6005    def _parse_wrapped_csv(
    6006        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    6007    ) -> t.List[exp.Expression]:
    6008        return self._parse_wrapped(
    6009            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    6010        )
    6011
    6012    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    6013        wrapped = self._match(TokenType.L_PAREN)
    6014        if not wrapped and not optional:
    6015            self.raise_error("Expecting (")
    6016        parse_result = parse_method()
    6017        if wrapped:
    6018            self._match_r_paren()
    6019        return parse_result
    6020
    6021    def _parse_expressions(self) -> t.List[exp.Expression]:
    6022        return self._parse_csv(self._parse_expression)
    6023
    6024    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    6025        return self._parse_select() or self._parse_set_operations(
    6026            self._parse_expression() if alias else self._parse_assignment()
    6027        )
    6028
    6029    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    6030        return self._parse_query_modifiers(
    6031            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    6032        )
    6033
    6034    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    6035        this = None
    6036        if self._match_texts(self.TRANSACTION_KIND):
    6037            this = self._prev.text
    6038
    6039        self._match_texts(("TRANSACTION", "WORK"))
    6040
    6041        modes = []
    6042        while True:
    6043            mode = []
    6044            while self._match(TokenType.VAR):
    6045                mode.append(self._prev.text)
    6046
    6047            if mode:
    6048                modes.append(" ".join(mode))
    6049            if not self._match(TokenType.COMMA):
    6050                break
    6051
    6052        return self.expression(exp.Transaction, this=this, modes=modes)
    6053
    6054    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    6055        chain = None
    6056        savepoint = None
    6057        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    6058
    6059        self._match_texts(("TRANSACTION", "WORK"))
    6060
    6061        if self._match_text_seq("TO"):
    6062            self._match_text_seq("SAVEPOINT")
    6063            savepoint = self._parse_id_var()
    6064
    6065        if self._match(TokenType.AND):
    6066            chain = not self._match_text_seq("NO")
    6067            self._match_text_seq("CHAIN")
    6068
    6069        if is_rollback:
    6070            return self.expression(exp.Rollback, savepoint=savepoint)
    6071
    6072        return self.expression(exp.Commit, chain=chain)
    6073
    6074    def _parse_refresh(self) -> exp.Refresh:
    6075        self._match(TokenType.TABLE)
    6076        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    6077
    6078    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    6079        if not self._match_text_seq("ADD"):
    6080            return None
    6081
    6082        self._match(TokenType.COLUMN)
    6083        exists_column = self._parse_exists(not_=True)
    6084        expression = self._parse_field_def()
    6085
    6086        if expression:
    6087            expression.set("exists", exists_column)
    6088
    6089            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    6090            if self._match_texts(("FIRST", "AFTER")):
    6091                position = self._prev.text
    6092                column_position = self.expression(
    6093                    exp.ColumnPosition, this=self._parse_column(), position=position
    6094                )
    6095                expression.set("position", column_position)
    6096
    6097        return expression
    6098
    6099    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    6100        drop = self._match(TokenType.DROP) and self._parse_drop()
    6101        if drop and not isinstance(drop, exp.Command):
    6102            drop.set("kind", drop.args.get("kind", "COLUMN"))
    6103        return drop
    6104
    6105    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    6106    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    6107        return self.expression(
    6108            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    6109        )
    6110
    6111    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    6112        index = self._index - 1
    6113
    6114        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    6115            return self._parse_csv(
    6116                lambda: self.expression(
    6117                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    6118                )
    6119            )
    6120
    6121        self._retreat(index)
    6122        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    6123            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    6124        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    6125
    6126    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    6127        if self._match_texts(self.ALTER_ALTER_PARSERS):
    6128            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    6129
    6130        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    6131        # keyword after ALTER we default to parsing this statement
    6132        self._match(TokenType.COLUMN)
    6133        column = self._parse_field(any_token=True)
    6134
    6135        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    6136            return self.expression(exp.AlterColumn, this=column, drop=True)
    6137        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    6138            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    6139        if self._match(TokenType.COMMENT):
    6140            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    6141        if self._match_text_seq("DROP", "NOT", "NULL"):
    6142            return self.expression(
    6143                exp.AlterColumn,
    6144                this=column,
    6145                drop=True,
    6146                allow_null=True,
    6147            )
    6148        if self._match_text_seq("SET", "NOT", "NULL"):
    6149            return self.expression(
    6150                exp.AlterColumn,
    6151                this=column,
    6152                allow_null=False,
    6153            )
    6154        self._match_text_seq("SET", "DATA")
    6155        self._match_text_seq("TYPE")
    6156        return self.expression(
    6157            exp.AlterColumn,
    6158            this=column,
    6159            dtype=self._parse_types(),
    6160            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    6161            using=self._match(TokenType.USING) and self._parse_assignment(),
    6162        )
    6163
    6164    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    6165        if self._match_texts(("ALL", "EVEN", "AUTO")):
    6166            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    6167
    6168        self._match_text_seq("KEY", "DISTKEY")
    6169        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    6170
    6171    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    6172        if compound:
    6173            self._match_text_seq("SORTKEY")
    6174
    6175        if self._match(TokenType.L_PAREN, advance=False):
    6176            return self.expression(
    6177                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    6178            )
    6179
    6180        self._match_texts(("AUTO", "NONE"))
    6181        return self.expression(
    6182            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    6183        )
    6184
    6185    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    6186        index = self._index - 1
    6187
    6188        partition_exists = self._parse_exists()
    6189        if self._match(TokenType.PARTITION, advance=False):
    6190            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    6191
    6192        self._retreat(index)
    6193        return self._parse_csv(self._parse_drop_column)
    6194
    6195    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
    6196        if self._match(TokenType.COLUMN):
    6197            exists = self._parse_exists()
    6198            old_column = self._parse_column()
    6199            to = self._match_text_seq("TO")
    6200            new_column = self._parse_column()
    6201
    6202            if old_column is None or to is None or new_column is None:
    6203                return None
    6204
    6205            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    6206
    6207        self._match_text_seq("TO")
    6208        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
    6209
    6210    def _parse_alter_table_set(self) -> exp.AlterSet:
    6211        alter_set = self.expression(exp.AlterSet)
    6212
    6213        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    6214            "TABLE", "PROPERTIES"
    6215        ):
    6216            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    6217        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    6218            alter_set.set("expressions", [self._parse_assignment()])
    6219        elif self._match_texts(("LOGGED", "UNLOGGED")):
    6220            alter_set.set("option", exp.var(self._prev.text.upper()))
    6221        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    6222            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    6223        elif self._match_text_seq("LOCATION"):
    6224            alter_set.set("location", self._parse_field())
    6225        elif self._match_text_seq("ACCESS", "METHOD"):
    6226            alter_set.set("access_method", self._parse_field())
    6227        elif self._match_text_seq("TABLESPACE"):
    6228            alter_set.set("tablespace", self._parse_field())
    6229        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    6230            alter_set.set("file_format", [self._parse_field()])
    6231        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    6232            alter_set.set("file_format", self._parse_wrapped_options())
    6233        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    6234            alter_set.set("copy_options", self._parse_wrapped_options())
    6235        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    6236            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    6237        else:
    6238            if self._match_text_seq("SERDE"):
    6239                alter_set.set("serde", self._parse_field())
    6240
    6241            alter_set.set("expressions", [self._parse_properties()])
    6242
    6243        return alter_set
    6244
    6245    def _parse_alter(self) -> exp.AlterTable | exp.Command:
    6246        start = self._prev
    6247
    6248        if not self._match(TokenType.TABLE):
    6249            return self._parse_as_command(start)
    6250
    6251        exists = self._parse_exists()
    6252        only = self._match_text_seq("ONLY")
    6253        this = self._parse_table(schema=True)
    6254        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6255
    6256        if self._next:
    6257            self._advance()
    6258
    6259        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    6260        if parser:
    6261            actions = ensure_list(parser(self))
    6262            options = self._parse_csv(self._parse_property)
    6263
    6264            if not self._curr and actions:
    6265                return self.expression(
    6266                    exp.AlterTable,
    6267                    this=this,
    6268                    exists=exists,
    6269                    actions=actions,
    6270                    only=only,
    6271                    options=options,
    6272                    cluster=cluster,
    6273                )
    6274
    6275        return self._parse_as_command(start)
    6276
    6277    def _parse_merge(self) -> exp.Merge:
    6278        self._match(TokenType.INTO)
    6279        target = self._parse_table()
    6280
    6281        if target and self._match(TokenType.ALIAS, advance=False):
    6282            target.set("alias", self._parse_table_alias())
    6283
    6284        self._match(TokenType.USING)
    6285        using = self._parse_table()
    6286
    6287        self._match(TokenType.ON)
    6288        on = self._parse_assignment()
    6289
    6290        return self.expression(
    6291            exp.Merge,
    6292            this=target,
    6293            using=using,
    6294            on=on,
    6295            expressions=self._parse_when_matched(),
    6296        )
    6297
    6298    def _parse_when_matched(self) -> t.List[exp.When]:
    6299        whens = []
    6300
    6301        while self._match(TokenType.WHEN):
    6302            matched = not self._match(TokenType.NOT)
    6303            self._match_text_seq("MATCHED")
    6304            source = (
    6305                False
    6306                if self._match_text_seq("BY", "TARGET")
    6307                else self._match_text_seq("BY", "SOURCE")
    6308            )
    6309            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    6310
    6311            self._match(TokenType.THEN)
    6312
    6313            if self._match(TokenType.INSERT):
    6314                _this = self._parse_star()
    6315                if _this:
    6316                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
    6317                else:
    6318                    then = self.expression(
    6319                        exp.Insert,
    6320                        this=self._parse_value(),
    6321                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    6322                    )
    6323            elif self._match(TokenType.UPDATE):
    6324                expressions = self._parse_star()
    6325                if expressions:
    6326                    then = self.expression(exp.Update, expressions=expressions)
    6327                else:
    6328                    then = self.expression(
    6329                        exp.Update,
    6330                        expressions=self._match(TokenType.SET)
    6331                        and self._parse_csv(self._parse_equality),
    6332                    )
    6333            elif self._match(TokenType.DELETE):
    6334                then = self.expression(exp.Var, this=self._prev.text)
    6335            else:
    6336                then = None
    6337
    6338            whens.append(
    6339                self.expression(
    6340                    exp.When,
    6341                    matched=matched,
    6342                    source=source,
    6343                    condition=condition,
    6344                    then=then,
    6345                )
    6346            )
    6347        return whens
    6348
    6349    def _parse_show(self) -> t.Optional[exp.Expression]:
    6350        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    6351        if parser:
    6352            return parser(self)
    6353        return self._parse_as_command(self._prev)
    6354
    6355    def _parse_set_item_assignment(
    6356        self, kind: t.Optional[str] = None
    6357    ) -> t.Optional[exp.Expression]:
    6358        index = self._index
    6359
    6360        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    6361            return self._parse_set_transaction(global_=kind == "GLOBAL")
    6362
    6363        left = self._parse_primary() or self._parse_column()
    6364        assignment_delimiter = self._match_texts(("=", "TO"))
    6365
    6366        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    6367            self._retreat(index)
    6368            return None
    6369
    6370        right = self._parse_statement() or self._parse_id_var()
    6371        if isinstance(right, (exp.Column, exp.Identifier)):
    6372            right = exp.var(right.name)
    6373
    6374        this = self.expression(exp.EQ, this=left, expression=right)
    6375        return self.expression(exp.SetItem, this=this, kind=kind)
    6376
    6377    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    6378        self._match_text_seq("TRANSACTION")
    6379        characteristics = self._parse_csv(
    6380            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    6381        )
    6382        return self.expression(
    6383            exp.SetItem,
    6384            expressions=characteristics,
    6385            kind="TRANSACTION",
    6386            **{"global": global_},  # type: ignore
    6387        )
    6388
    6389    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    6390        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    6391        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    6392
    6393    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    6394        index = self._index
    6395        set_ = self.expression(
    6396            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    6397        )
    6398
    6399        if self._curr:
    6400            self._retreat(index)
    6401            return self._parse_as_command(self._prev)
    6402
    6403        return set_
    6404
    6405    def _parse_var_from_options(
    6406        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    6407    ) -> t.Optional[exp.Var]:
    6408        start = self._curr
    6409        if not start:
    6410            return None
    6411
    6412        option = start.text.upper()
    6413        continuations = options.get(option)
    6414
    6415        index = self._index
    6416        self._advance()
    6417        for keywords in continuations or []:
    6418            if isinstance(keywords, str):
    6419                keywords = (keywords,)
    6420
    6421            if self._match_text_seq(*keywords):
    6422                option = f"{option} {' '.join(keywords)}"
    6423                break
    6424        else:
    6425            if continuations or continuations is None:
    6426                if raise_unmatched:
    6427                    self.raise_error(f"Unknown option {option}")
    6428
    6429                self._retreat(index)
    6430                return None
    6431
    6432        return exp.var(option)
    6433
    6434    def _parse_as_command(self, start: Token) -> exp.Command:
    6435        while self._curr:
    6436            self._advance()
    6437        text = self._find_sql(start, self._prev)
    6438        size = len(start.text)
    6439        self._warn_unsupported()
    6440        return exp.Command(this=text[:size], expression=text[size:])
    6441
    6442    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    6443        settings = []
    6444
    6445        self._match_l_paren()
    6446        kind = self._parse_id_var()
    6447
    6448        if self._match(TokenType.L_PAREN):
    6449            while True:
    6450                key = self._parse_id_var()
    6451                value = self._parse_primary()
    6452
    6453                if not key and value is None:
    6454                    break
    6455                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    6456            self._match(TokenType.R_PAREN)
    6457
    6458        self._match_r_paren()
    6459
    6460        return self.expression(
    6461            exp.DictProperty,
    6462            this=this,
    6463            kind=kind.this if kind else None,
    6464            settings=settings,
    6465        )
    6466
    6467    def _parse_dict_range(self, this: str) -> exp.DictRange:
    6468        self._match_l_paren()
    6469        has_min = self._match_text_seq("MIN")
    6470        if has_min:
    6471            min = self._parse_var() or self._parse_primary()
    6472            self._match_text_seq("MAX")
    6473            max = self._parse_var() or self._parse_primary()
    6474        else:
    6475            max = self._parse_var() or self._parse_primary()
    6476            min = exp.Literal.number(0)
    6477        self._match_r_paren()
    6478        return self.expression(exp.DictRange, this=this, min=min, max=max)
    6479
    6480    def _parse_comprehension(
    6481        self, this: t.Optional[exp.Expression]
    6482    ) -> t.Optional[exp.Comprehension]:
    6483        index = self._index
    6484        expression = self._parse_column()
    6485        if not self._match(TokenType.IN):
    6486            self._retreat(index - 1)
    6487            return None
    6488        iterator = self._parse_column()
    6489        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    6490        return self.expression(
    6491            exp.Comprehension,
    6492            this=this,
    6493            expression=expression,
    6494            iterator=iterator,
    6495            condition=condition,
    6496        )
    6497
    6498    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    6499        if self._match(TokenType.HEREDOC_STRING):
    6500            return self.expression(exp.Heredoc, this=self._prev.text)
    6501
    6502        if not self._match_text_seq("$"):
    6503            return None
    6504
    6505        tags = ["$"]
    6506        tag_text = None
    6507
    6508        if self._is_connected():
    6509            self._advance()
    6510            tags.append(self._prev.text.upper())
    6511        else:
    6512            self.raise_error("No closing $ found")
    6513
    6514        if tags[-1] != "$":
    6515            if self._is_connected() and self._match_text_seq("$"):
    6516                tag_text = tags[-1]
    6517                tags.append("$")
    6518            else:
    6519                self.raise_error("No closing $ found")
    6520
    6521        heredoc_start = self._curr
    6522
    6523        while self._curr:
    6524            if self._match_text_seq(*tags, advance=False):
    6525                this = self._find_sql(heredoc_start, self._prev)
    6526                self._advance(len(tags))
    6527                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    6528
    6529            self._advance()
    6530
    6531        self.raise_error(f"No closing {''.join(tags)} found")
    6532        return None
    6533
    6534    def _find_parser(
    6535        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    6536    ) -> t.Optional[t.Callable]:
    6537        if not self._curr:
    6538            return None
    6539
    6540        index = self._index
    6541        this = []
    6542        while True:
    6543            # The current token might be multiple words
    6544            curr = self._curr.text.upper()
    6545            key = curr.split(" ")
    6546            this.append(curr)
    6547
    6548            self._advance()
    6549            result, trie = in_trie(trie, key)
    6550            if result == TrieResult.FAILED:
    6551                break
    6552
    6553            if result == TrieResult.EXISTS:
    6554                subparser = parsers[" ".join(this)]
    6555                return subparser
    6556
    6557        self._retreat(index)
    6558        return None
    6559
    6560    def _match(self, token_type, advance=True, expression=None):
    6561        if not self._curr:
    6562            return None
    6563
    6564        if self._curr.token_type == token_type:
    6565            if advance:
    6566                self._advance()
    6567            self._add_comments(expression)
    6568            return True
    6569
    6570        return None
    6571
    6572    def _match_set(self, types, advance=True):
    6573        if not self._curr:
    6574            return None
    6575
    6576        if self._curr.token_type in types:
    6577            if advance:
    6578                self._advance()
    6579            return True
    6580
    6581        return None
    6582
    6583    def _match_pair(self, token_type_a, token_type_b, advance=True):
    6584        if not self._curr or not self._next:
    6585            return None
    6586
    6587        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    6588            if advance:
    6589                self._advance(2)
    6590            return True
    6591
    6592        return None
    6593
    6594    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6595        if not self._match(TokenType.L_PAREN, expression=expression):
    6596            self.raise_error("Expecting (")
    6597
    6598    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    6599        if not self._match(TokenType.R_PAREN, expression=expression):
    6600            self.raise_error("Expecting )")
    6601
    6602    def _match_texts(self, texts, advance=True):
    6603        if self._curr and self._curr.text.upper() in texts:
    6604            if advance:
    6605                self._advance()
    6606            return True
    6607        return None
    6608
    6609    def _match_text_seq(self, *texts, advance=True):
    6610        index = self._index
    6611        for text in texts:
    6612            if self._curr and self._curr.text.upper() == text:
    6613                self._advance()
    6614            else:
    6615                self._retreat(index)
    6616                return None
    6617
    6618        if not advance:
    6619            self._retreat(index)
    6620
    6621        return True
    6622
    6623    def _replace_lambda(
    6624        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    6625    ) -> t.Optional[exp.Expression]:
    6626        if not node:
    6627            return node
    6628
    6629        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    6630
    6631        for column in node.find_all(exp.Column):
    6632            typ = lambda_types.get(column.parts[0].name)
    6633            if typ is not None:
    6634                dot_or_id = column.to_dot() if column.table else column.this
    6635
    6636                if typ:
    6637                    dot_or_id = self.expression(
    6638                        exp.Cast,
    6639                        this=dot_or_id,
    6640                        to=typ,
    6641                    )
    6642
    6643                parent = column.parent
    6644
    6645                while isinstance(parent, exp.Dot):
    6646                    if not isinstance(parent.parent, exp.Dot):
    6647                        parent.replace(dot_or_id)
    6648                        break
    6649                    parent = parent.parent
    6650                else:
    6651                    if column is node:
    6652                        node = dot_or_id
    6653                    else:
    6654                        column.replace(dot_or_id)
    6655        return node
    6656
    6657    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    6658        start = self._prev
    6659
    6660        # Not to be confused with TRUNCATE(number, decimals) function call
    6661        if self._match(TokenType.L_PAREN):
    6662            self._retreat(self._index - 2)
    6663            return self._parse_function()
    6664
    6665        # Clickhouse supports TRUNCATE DATABASE as well
    6666        is_database = self._match(TokenType.DATABASE)
    6667
    6668        self._match(TokenType.TABLE)
    6669
    6670        exists = self._parse_exists(not_=False)
    6671
    6672        expressions = self._parse_csv(
    6673            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    6674        )
    6675
    6676        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    6677
    6678        if self._match_text_seq("RESTART", "IDENTITY"):
    6679            identity = "RESTART"
    6680        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    6681            identity = "CONTINUE"
    6682        else:
    6683            identity = None
    6684
    6685        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    6686            option = self._prev.text
    6687        else:
    6688            option = None
    6689
    6690        partition = self._parse_partition()
    6691
    6692        # Fallback case
    6693        if self._curr:
    6694            return self._parse_as_command(start)
    6695
    6696        return self.expression(
    6697            exp.TruncateTable,
    6698            expressions=expressions,
    6699            is_database=is_database,
    6700            exists=exists,
    6701            cluster=cluster,
    6702            identity=identity,
    6703            option=option,
    6704            partition=partition,
    6705        )
    6706
    6707    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    6708        this = self._parse_ordered(self._parse_opclass)
    6709
    6710        if not self._match(TokenType.WITH):
    6711            return this
    6712
    6713        op = self._parse_var(any_token=True)
    6714
    6715        return self.expression(exp.WithOperator, this=this, op=op)
    6716
    6717    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    6718        self._match(TokenType.EQ)
    6719        self._match(TokenType.L_PAREN)
    6720
    6721        opts: t.List[t.Optional[exp.Expression]] = []
    6722        while self._curr and not self._match(TokenType.R_PAREN):
    6723            if self._match_text_seq("FORMAT_NAME", "="):
    6724                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
    6725                # so we parse it separately to use _parse_field()
    6726                prop = self.expression(
    6727                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
    6728                )
    6729                opts.append(prop)
    6730            else:
    6731                opts.append(self._parse_property())
    6732
    6733            self._match(TokenType.COMMA)
    6734
    6735        return opts
    6736
    6737    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    6738        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    6739
    6740        options = []
    6741        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    6742            option = self._parse_var(any_token=True)
    6743            prev = self._prev.text.upper()
    6744
    6745            # Different dialects might separate options and values by white space, "=" and "AS"
    6746            self._match(TokenType.EQ)
    6747            self._match(TokenType.ALIAS)
    6748
    6749            param = self.expression(exp.CopyParameter, this=option)
    6750
    6751            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    6752                TokenType.L_PAREN, advance=False
    6753            ):
    6754                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    6755                param.set("expressions", self._parse_wrapped_options())
    6756            elif prev == "FILE_FORMAT":
    6757                # T-SQL's external file format case
    6758                param.set("expression", self._parse_field())
    6759            else:
    6760                param.set("expression", self._parse_unquoted_field())
    6761
    6762            options.append(param)
    6763            self._match(sep)
    6764
    6765        return options
    6766
    6767    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    6768        expr = self.expression(exp.Credentials)
    6769
    6770        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    6771            expr.set("storage", self._parse_field())
    6772        if self._match_text_seq("CREDENTIALS"):
    6773            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    6774            creds = (
    6775                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    6776            )
    6777            expr.set("credentials", creds)
    6778        if self._match_text_seq("ENCRYPTION"):
    6779            expr.set("encryption", self._parse_wrapped_options())
    6780        if self._match_text_seq("IAM_ROLE"):
    6781            expr.set("iam_role", self._parse_field())
    6782        if self._match_text_seq("REGION"):
    6783            expr.set("region", self._parse_field())
    6784
    6785        return expr
    6786
    6787    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    6788        return self._parse_field()
    6789
    6790    def _parse_copy(self) -> exp.Copy | exp.Command:
    6791        start = self._prev
    6792
    6793        self._match(TokenType.INTO)
    6794
    6795        this = (
    6796            self._parse_select(nested=True, parse_subquery_alias=False)
    6797            if self._match(TokenType.L_PAREN, advance=False)
    6798            else self._parse_table(schema=True)
    6799        )
    6800
    6801        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    6802
    6803        files = self._parse_csv(self._parse_file_location)
    6804        credentials = self._parse_credentials()
    6805
    6806        self._match_text_seq("WITH")
    6807
    6808        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    6809
    6810        # Fallback case
    6811        if self._curr:
    6812            return self._parse_as_command(start)
    6813
    6814        return self.expression(
    6815            exp.Copy,
    6816            this=this,
    6817            kind=kind,
    6818            credentials=credentials,
    6819            files=files,
    6820            params=params,
    6821        )

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: 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, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) View Source

    1224    def __init__(
    1225        self,
    1226        error_level: t.Optional[ErrorLevel] = None,
    1227        error_message_context: int = 100,
    1228        max_errors: int = 3,
    1229        dialect: DialectType = None,
    1230    ):
    1231        from sqlglot.dialects import Dialect
    1232
    1233        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1234        self.error_message_context = error_message_context
    1235        self.max_errors = max_errors
    1236        self.dialect = Dialect.get_or_raise(dialect)
    1237        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, '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'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONSTRUCT_COMPACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConstructCompact'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_HAS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_CONTAINS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'ARRAY_HAS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, '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_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <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_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, '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'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, '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'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, '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'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, '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'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, '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'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, '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': <function build_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'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, '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'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, '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': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, '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'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, '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_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, '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_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, '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_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, '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>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, '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': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function build_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>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.LIST: 'LIST'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.NULLABLE: 'NULLABLE'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.MONEY: 'MONEY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSON: 'JSON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.TILDA: 'TILDA'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.GT: 'GT'>, <TokenType.COLON: 'COLON'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SLASH: 'SLASH'>, <TokenType.EQ: 'EQ'>, <TokenType.NOT: 'NOT'>, <TokenType.LT: 'LT'>, <TokenType.STAR: 'STAR'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.CARET: 'CARET'>, <TokenType.DOT: 'DOT'>, <TokenType.DASH: 'DASH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.AMP: 'AMP'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.MOD: 'MOD'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.HASH: 'HASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.PLUS: 'PLUS'>}
DB_CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>}
CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TAG: 'TAG'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
ID_VAR_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
INTERVAL_VARS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
TABLE_ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
UPDATE_ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INSERT: 'INSERT'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.XOR: 'XOR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.GLOB: 'GLOB'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.LEFT: 'LEFT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SOME: 'SOME'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ROW: 'ROW'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.JSON: 'JSON'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
CONJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>}
ASSIGNMENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>}
DISJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<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'>}
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'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <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.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <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>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <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>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <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>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <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>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <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>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <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>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PERIOD', 'PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE', 'EXCLUDE', 'CHECK', 'LIKE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTER: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
INSERT_ALTERNATIVES = {'REPLACE', 'ROLLBACK', 'FAIL', 'IGNORE', 'ABORT'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_KIND = {'OFFSET', 'TIMESTAMP', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'DESC', 'NULLS', 'WITH'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>}
VIEW_ATTRIBUTES = {'VIEW_METADATA', 'ENCRYPTION', 'SCHEMABINDING'}
WINDOW_ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UINT: 'UINT'>, <TokenType.USE: 'USE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NAME: 'NAME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ASC: 'ASC'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.FULL: 'FULL'>, <TokenType.KILL: 'KILL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CASE: 'CASE'>, <TokenType.XML: 'XML'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ALL: 'ALL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIME: 'TIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.SET: 'SET'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.INT128: 'INT128'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.LOAD: 'LOAD'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INT: 'INT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.BIT: 'BIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SOME: 'SOME'>, <TokenType.CACHE: 'CACHE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ROW: 'ROW'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UUID: 'UUID'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TOP: 'TOP'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VAR: 'VAR'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COPY: 'COPY'>, <TokenType.JSON: 'JSON'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.INT256: 'INT256'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LIST: 'LIST'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>, <TokenType.FILTER: 'FILTER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.DIV: 'DIV'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INET: 'INET'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.NULL: 'NULL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DESC: 'DESC'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>}
SELECT_START_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
COPY_INTO_VARLEN_OPTIONS = {'COPY_OPTIONS', 'CREDENTIAL', 'FORMAT_OPTIONS', 'FILE_FORMAT'}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'order', 'limit', 'offset'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_JSON_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self): View Source

    1239    def reset(self):
    1240        self.sql = ""
    1241        self.errors = []
    1242        self._tokens = []
    1243        self._index = 0
    1244        self._curr = None
    1245        self._next = None
    1246        self._prev = None
    1247        self._prev_comments = None

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

    1249    def parse(
    1250        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1251    ) -> t.List[t.Optional[exp.Expression]]:
    1252        """
    1253        Parses a list of tokens and returns a list of syntax trees, one tree
    1254        per parsed SQL statement.
    1255
    1256        Args:
    1257            raw_tokens: The list of tokens.
    1258            sql: The original SQL string, used to produce helpful debug messages.
    1259
    1260        Returns:
    1261            The list of the produced syntax trees.
    1262        """
    1263        return self._parse(
    1264            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1265        )

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

    1267    def parse_into(
    1268        self,
    1269        expression_types: exp.IntoType,
    1270        raw_tokens: t.List[Token],
    1271        sql: t.Optional[str] = None,
    1272    ) -> t.List[t.Optional[exp.Expression]]:
    1273        """
    1274        Parses a list of tokens into a given Expression type. If a collection of Expression
    1275        types is given instead, this method will try to parse the token list into each one
    1276        of them, stopping at the first for which the parsing succeeds.
    1277
    1278        Args:
    1279            expression_types: The expression type(s) to try and parse the token list into.
    1280            raw_tokens: The list of tokens.
    1281            sql: The original SQL string, used to produce helpful debug messages.
    1282
    1283        Returns:
    1284            The target Expression.
    1285        """
    1286        errors = []
    1287        for expression_type in ensure_list(expression_types):
    1288            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1289            if not parser:
    1290                raise TypeError(f"No parser registered for {expression_type}")
    1291
    1292            try:
    1293                return self._parse(parser, raw_tokens, sql)
    1294            except ParseError as e:
    1295                e.errors[0]["into_expression"] = expression_type
    1296                errors.append(e)
    1297
    1298        raise ParseError(
    1299            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1300            errors=merge_errors(errors),
    1301        ) 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

    1341    def check_errors(self) -> None:
    1342        """Logs or raises any found errors, depending on the chosen error level setting."""
    1343        if self.error_level == ErrorLevel.WARN:
    1344            for error in self.errors:
    1345                logger.error(str(error))
    1346        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1347            raise ParseError(
    1348                concat_messages(self.errors, self.max_errors),
    1349                errors=merge_errors(self.errors),
    1350            )

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

    1352    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1353        """
    1354        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1355        error level setting.
    1356        """
    1357        token = token or self._curr or self._prev or Token.string("")
    1358        start = token.start
    1359        end = token.end + 1
    1360        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1361        highlight = self.sql[start:end]
    1362        end_context = self.sql[end : end + self.error_message_context]
    1363
    1364        error = ParseError.new(
    1365            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1366            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1367            description=message,
    1368            line=token.line,
    1369            col=token.col,
    1370            start_context=start_context,
    1371            highlight=highlight,
    1372            end_context=end_context,
    1373        )
    1374
    1375        if self.error_level == ErrorLevel.IMMEDIATE:
    1376            raise error
    1377
    1378        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

    1380    def expression(
    1381        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1382    ) -> E:
    1383        """
    1384        Creates a new, validated Expression.
    1385
    1386        Args:
    1387            exp_class: The expression class to instantiate.
    1388            comments: An optional list of comments to attach to the expression.
    1389            kwargs: The arguments to set for the expression along with their respective values.
    1390
    1391        Returns:
    1392            The target expression.
    1393        """
    1394        instance = exp_class(**kwargs)
    1395        instance.add_comments(comments) if comments else self._add_comments(instance)
    1396        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

    1403    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1404        """
    1405        Validates an Expression, making sure that all its mandatory arguments are set.
    1406
    1407        Args:
    1408            expression: The expression to validate.
    1409            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1410
    1411        Returns:
    1412            The validated expression.
    1413        """
    1414        if self.error_level != ErrorLevel.IGNORE:
    1415            for error_message in expression.error_messages(args):
    1416                self.raise_error(error_message)
    1417
    1418        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