sqlglot.dialects.bigquery API documentation

Edit on GitHub

# sqlglot.dialects.bigquery

View Source

       1from __future__ import annotations
       2
       3import logging
       4import re
       5import typing as t
       6
       7from sqlglot import exp, generator, parser, tokens, transforms
       8from sqlglot.dialects.dialect import (
       9    Dialect,
      10    NormalizationStrategy,
      11    annotate_with_type_lambda,
      12    arg_max_or_min_no_count,
      13    binary_from_function,
      14    date_add_interval_sql,
      15    datestrtodate_sql,
      16    build_formatted_time,
      17    filter_array_using_unnest,
      18    if_sql,
      19    inline_array_unless_query,
      20    max_or_greatest,
      21    min_or_least,
      22    no_ilike_sql,
      23    build_date_delta_with_interval,
      24    regexp_replace_sql,
      25    rename_func,
      26    sha256_sql,
      27    timestrtotime_sql,
      28    ts_or_ds_add_cast,
      29    unit_to_var,
      30    strposition_sql,
      31    groupconcat_sql,
      32)
      33from sqlglot.helper import seq_get, split_num_words
      34from sqlglot.tokens import TokenType
      35from sqlglot.generator import unsupported_args
      36
      37if t.TYPE_CHECKING:
      38    from sqlglot._typing import E, Lit
      39
      40    from sqlglot.optimizer.annotate_types import TypeAnnotator
      41
      42logger = logging.getLogger("sqlglot")
      43
      44
      45JSON_EXTRACT_TYPE = t.Union[exp.JSONExtract, exp.JSONExtractScalar, exp.JSONExtractArray]
      46
      47DQUOTES_ESCAPING_JSON_FUNCTIONS = ("JSON_QUERY", "JSON_VALUE", "JSON_QUERY_ARRAY")
      48
      49
      50def _derived_table_values_to_unnest(self: BigQuery.Generator, expression: exp.Values) -> str:
      51    if not expression.find_ancestor(exp.From, exp.Join):
      52        return self.values_sql(expression)
      53
      54    structs = []
      55    alias = expression.args.get("alias")
      56    for tup in expression.find_all(exp.Tuple):
      57        field_aliases = (
      58            alias.columns
      59            if alias and alias.columns
      60            else (f"_c{i}" for i in range(len(tup.expressions)))
      61        )
      62        expressions = [
      63            exp.PropertyEQ(this=exp.to_identifier(name), expression=fld)
      64            for name, fld in zip(field_aliases, tup.expressions)
      65        ]
      66        structs.append(exp.Struct(expressions=expressions))
      67
      68    # Due to `UNNEST_COLUMN_ONLY`, it is expected that the table alias be contained in the columns expression
      69    alias_name_only = exp.TableAlias(columns=[alias.this]) if alias else None
      70    return self.unnest_sql(
      71        exp.Unnest(expressions=[exp.array(*structs, copy=False)], alias=alias_name_only)
      72    )
      73
      74
      75def _returnsproperty_sql(self: BigQuery.Generator, expression: exp.ReturnsProperty) -> str:
      76    this = expression.this
      77    if isinstance(this, exp.Schema):
      78        this = f"{self.sql(this, 'this')} <{self.expressions(this)}>"
      79    else:
      80        this = self.sql(this)
      81    return f"RETURNS {this}"
      82
      83
      84def _create_sql(self: BigQuery.Generator, expression: exp.Create) -> str:
      85    returns = expression.find(exp.ReturnsProperty)
      86    if expression.kind == "FUNCTION" and returns and returns.args.get("is_table"):
      87        expression.set("kind", "TABLE FUNCTION")
      88
      89        if isinstance(expression.expression, (exp.Subquery, exp.Literal)):
      90            expression.set("expression", expression.expression.this)
      91
      92    return self.create_sql(expression)
      93
      94
      95# https://issuetracker.google.com/issues/162294746
      96# workaround for bigquery bug when grouping by an expression and then ordering
      97# WITH x AS (SELECT 1 y)
      98# SELECT y + 1 z
      99# FROM x
     100# GROUP BY x + 1
     101# ORDER by z
     102def _alias_ordered_group(expression: exp.Expression) -> exp.Expression:
     103    if isinstance(expression, exp.Select):
     104        group = expression.args.get("group")
     105        order = expression.args.get("order")
     106
     107        if group and order:
     108            aliases = {
     109                select.this: select.args["alias"]
     110                for select in expression.selects
     111                if isinstance(select, exp.Alias)
     112            }
     113
     114            for grouped in group.expressions:
     115                if grouped.is_int:
     116                    continue
     117                alias = aliases.get(grouped)
     118                if alias:
     119                    grouped.replace(exp.column(alias))
     120
     121    return expression
     122
     123
     124def _pushdown_cte_column_names(expression: exp.Expression) -> exp.Expression:
     125    """BigQuery doesn't allow column names when defining a CTE, so we try to push them down."""
     126    if isinstance(expression, exp.CTE) and expression.alias_column_names:
     127        cte_query = expression.this
     128
     129        if cte_query.is_star:
     130            logger.warning(
     131                "Can't push down CTE column names for star queries. Run the query through"
     132                " the optimizer or use 'qualify' to expand the star projections first."
     133            )
     134            return expression
     135
     136        column_names = expression.alias_column_names
     137        expression.args["alias"].set("columns", None)
     138
     139        for name, select in zip(column_names, cte_query.selects):
     140            to_replace = select
     141
     142            if isinstance(select, exp.Alias):
     143                select = select.this
     144
     145            # Inner aliases are shadowed by the CTE column names
     146            to_replace.replace(exp.alias_(select, name))
     147
     148    return expression
     149
     150
     151def _build_parse_timestamp(args: t.List) -> exp.StrToTime:
     152    this = build_formatted_time(exp.StrToTime, "bigquery")([seq_get(args, 1), seq_get(args, 0)])
     153    this.set("zone", seq_get(args, 2))
     154    return this
     155
     156
     157def _build_timestamp(args: t.List) -> exp.Timestamp:
     158    timestamp = exp.Timestamp.from_arg_list(args)
     159    timestamp.set("with_tz", True)
     160    return timestamp
     161
     162
     163def _build_date(args: t.List) -> exp.Date | exp.DateFromParts:
     164    expr_type = exp.DateFromParts if len(args) == 3 else exp.Date
     165    return expr_type.from_arg_list(args)
     166
     167
     168def _build_to_hex(args: t.List) -> exp.Hex | exp.MD5:
     169    # TO_HEX(MD5(..)) is common in BigQuery, so it's parsed into MD5 to simplify its transpilation
     170    arg = seq_get(args, 0)
     171    return exp.MD5(this=arg.this) if isinstance(arg, exp.MD5Digest) else exp.LowerHex(this=arg)
     172
     173
     174def _array_contains_sql(self: BigQuery.Generator, expression: exp.ArrayContains) -> str:
     175    return self.sql(
     176        exp.Exists(
     177            this=exp.select("1")
     178            .from_(exp.Unnest(expressions=[expression.left]).as_("_unnest", table=["_col"]))
     179            .where(exp.column("_col").eq(expression.right))
     180        )
     181    )
     182
     183
     184def _ts_or_ds_add_sql(self: BigQuery.Generator, expression: exp.TsOrDsAdd) -> str:
     185    return date_add_interval_sql("DATE", "ADD")(self, ts_or_ds_add_cast(expression))
     186
     187
     188def _ts_or_ds_diff_sql(self: BigQuery.Generator, expression: exp.TsOrDsDiff) -> str:
     189    expression.this.replace(exp.cast(expression.this, exp.DataType.Type.TIMESTAMP))
     190    expression.expression.replace(exp.cast(expression.expression, exp.DataType.Type.TIMESTAMP))
     191    unit = unit_to_var(expression)
     192    return self.func("DATE_DIFF", expression.this, expression.expression, unit)
     193
     194
     195def _unix_to_time_sql(self: BigQuery.Generator, expression: exp.UnixToTime) -> str:
     196    scale = expression.args.get("scale")
     197    timestamp = expression.this
     198
     199    if scale in (None, exp.UnixToTime.SECONDS):
     200        return self.func("TIMESTAMP_SECONDS", timestamp)
     201    if scale == exp.UnixToTime.MILLIS:
     202        return self.func("TIMESTAMP_MILLIS", timestamp)
     203    if scale == exp.UnixToTime.MICROS:
     204        return self.func("TIMESTAMP_MICROS", timestamp)
     205
     206    unix_seconds = exp.cast(
     207        exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), exp.DataType.Type.BIGINT
     208    )
     209    return self.func("TIMESTAMP_SECONDS", unix_seconds)
     210
     211
     212def _build_time(args: t.List) -> exp.Func:
     213    if len(args) == 1:
     214        return exp.TsOrDsToTime(this=args[0])
     215    if len(args) == 2:
     216        return exp.Time.from_arg_list(args)
     217    return exp.TimeFromParts.from_arg_list(args)
     218
     219
     220def _build_datetime(args: t.List) -> exp.Func:
     221    if len(args) == 1:
     222        return exp.TsOrDsToDatetime.from_arg_list(args)
     223    if len(args) == 2:
     224        return exp.Datetime.from_arg_list(args)
     225    return exp.TimestampFromParts.from_arg_list(args)
     226
     227
     228def _build_regexp_extract(
     229    expr_type: t.Type[E], default_group: t.Optional[exp.Expression] = None
     230) -> t.Callable[[t.List], E]:
     231    def _builder(args: t.List) -> E:
     232        try:
     233            group = re.compile(args[1].name).groups == 1
     234        except re.error:
     235            group = False
     236
     237        # Default group is used for the transpilation of REGEXP_EXTRACT_ALL
     238        return expr_type(
     239            this=seq_get(args, 0),
     240            expression=seq_get(args, 1),
     241            position=seq_get(args, 2),
     242            occurrence=seq_get(args, 3),
     243            group=exp.Literal.number(1) if group else default_group,
     244        )
     245
     246    return _builder
     247
     248
     249def _build_extract_json_with_default_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
     250    def _builder(args: t.List, dialect: Dialect) -> E:
     251        if len(args) == 1:
     252            # The default value for the JSONPath is '$' i.e all of the data
     253            args.append(exp.Literal.string("$"))
     254        return parser.build_extract_json_with_path(expr_type)(args, dialect)
     255
     256    return _builder
     257
     258
     259def _str_to_datetime_sql(
     260    self: BigQuery.Generator, expression: exp.StrToDate | exp.StrToTime
     261) -> str:
     262    this = self.sql(expression, "this")
     263    dtype = "DATE" if isinstance(expression, exp.StrToDate) else "TIMESTAMP"
     264
     265    if expression.args.get("safe"):
     266        fmt = self.format_time(
     267            expression,
     268            self.dialect.INVERSE_FORMAT_MAPPING,
     269            self.dialect.INVERSE_FORMAT_TRIE,
     270        )
     271        return f"SAFE_CAST({this} AS {dtype} FORMAT {fmt})"
     272
     273    fmt = self.format_time(expression)
     274    return self.func(f"PARSE_{dtype}", fmt, this, expression.args.get("zone"))
     275
     276
     277def _annotate_math_functions(self: TypeAnnotator, expression: E) -> E:
     278    """
     279    Many BigQuery math functions such as CEIL, FLOOR etc follow this return type convention:
     280    +---------+---------+---------+------------+---------+
     281    |  INPUT  | INT64   | NUMERIC | BIGNUMERIC | FLOAT64 |
     282    +---------+---------+---------+------------+---------+
     283    |  OUTPUT | FLOAT64 | NUMERIC | BIGNUMERIC | FLOAT64 |
     284    +---------+---------+---------+------------+---------+
     285    """
     286    self._annotate_args(expression)
     287
     288    this: exp.Expression = expression.this
     289
     290    self._set_type(
     291        expression,
     292        exp.DataType.Type.DOUBLE if this.is_type(*exp.DataType.INTEGER_TYPES) else this.type,
     293    )
     294    return expression
     295
     296
     297@unsupported_args("ins_cost", "del_cost", "sub_cost")
     298def _levenshtein_sql(self: BigQuery.Generator, expression: exp.Levenshtein) -> str:
     299    max_dist = expression.args.get("max_dist")
     300    if max_dist:
     301        max_dist = exp.Kwarg(this=exp.var("max_distance"), expression=max_dist)
     302
     303    return self.func("EDIT_DISTANCE", expression.this, expression.expression, max_dist)
     304
     305
     306def _build_levenshtein(args: t.List) -> exp.Levenshtein:
     307    max_dist = seq_get(args, 2)
     308    return exp.Levenshtein(
     309        this=seq_get(args, 0),
     310        expression=seq_get(args, 1),
     311        max_dist=max_dist.expression if max_dist else None,
     312    )
     313
     314
     315def _build_format_time(expr_type: t.Type[exp.Expression]) -> t.Callable[[t.List], exp.TimeToStr]:
     316    def _builder(args: t.List) -> exp.TimeToStr:
     317        return exp.TimeToStr(
     318            this=expr_type(this=seq_get(args, 1)),
     319            format=seq_get(args, 0),
     320            zone=seq_get(args, 2),
     321        )
     322
     323    return _builder
     324
     325
     326def _build_contains_substring(args: t.List) -> exp.Contains | exp.Anonymous:
     327    if len(args) == 3:
     328        return exp.Anonymous(this="CONTAINS_SUBSTR", expressions=args)
     329
     330    # Lowercase the operands in case of transpilation, as exp.Contains
     331    # is case-sensitive on other dialects
     332    this = exp.Lower(this=seq_get(args, 0))
     333    expr = exp.Lower(this=seq_get(args, 1))
     334
     335    return exp.Contains(this=this, expression=expr)
     336
     337
     338def _json_extract_sql(self: BigQuery.Generator, expression: JSON_EXTRACT_TYPE) -> str:
     339    name = (expression._meta and expression.meta.get("name")) or expression.sql_name()
     340    upper = name.upper()
     341
     342    dquote_escaping = upper in DQUOTES_ESCAPING_JSON_FUNCTIONS
     343
     344    if dquote_escaping:
     345        self._quote_json_path_key_using_brackets = False
     346
     347    sql = rename_func(upper)(self, expression)
     348
     349    if dquote_escaping:
     350        self._quote_json_path_key_using_brackets = True
     351
     352    return sql
     353
     354
     355class BigQuery(Dialect):
     356    WEEK_OFFSET = -1
     357    UNNEST_COLUMN_ONLY = True
     358    SUPPORTS_USER_DEFINED_TYPES = False
     359    SUPPORTS_SEMI_ANTI_JOIN = False
     360    LOG_BASE_FIRST = False
     361    HEX_LOWERCASE = True
     362    FORCE_EARLY_ALIAS_REF_EXPANSION = True
     363    PRESERVE_ORIGINAL_NAMES = True
     364    HEX_STRING_IS_INTEGER_TYPE = True
     365
     366    # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
     367    NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
     368
     369    # bigquery udfs are case sensitive
     370    NORMALIZE_FUNCTIONS = False
     371
     372    # https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_elements_date_time
     373    TIME_MAPPING = {
     374        "%D": "%m/%d/%y",
     375        "%E6S": "%S.%f",
     376        "%e": "%-d",
     377    }
     378
     379    FORMAT_MAPPING = {
     380        "DD": "%d",
     381        "MM": "%m",
     382        "MON": "%b",
     383        "MONTH": "%B",
     384        "YYYY": "%Y",
     385        "YY": "%y",
     386        "HH": "%I",
     387        "HH12": "%I",
     388        "HH24": "%H",
     389        "MI": "%M",
     390        "SS": "%S",
     391        "SSSSS": "%f",
     392        "TZH": "%z",
     393    }
     394
     395    # The _PARTITIONTIME and _PARTITIONDATE pseudo-columns are not returned by a SELECT * statement
     396    # https://cloud.google.com/bigquery/docs/querying-partitioned-tables#query_an_ingestion-time_partitioned_table
     397    PSEUDOCOLUMNS = {"_PARTITIONTIME", "_PARTITIONDATE"}
     398
     399    # All set operations require either a DISTINCT or ALL specifier
     400    SET_OP_DISTINCT_BY_DEFAULT = dict.fromkeys((exp.Except, exp.Intersect, exp.Union), None)
     401
     402    # BigQuery maps Type.TIMESTAMP to DATETIME, so we need to amend the inferred types
     403    TYPE_TO_EXPRESSIONS = {
     404        **Dialect.TYPE_TO_EXPRESSIONS,
     405        exp.DataType.Type.TIMESTAMPTZ: Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.TIMESTAMP],
     406    }
     407    TYPE_TO_EXPRESSIONS.pop(exp.DataType.Type.TIMESTAMP)
     408
     409    ANNOTATORS = {
     410        **Dialect.ANNOTATORS,
     411        **{
     412            expr_type: annotate_with_type_lambda(data_type)
     413            for data_type, expressions in TYPE_TO_EXPRESSIONS.items()
     414            for expr_type in expressions
     415        },
     416        **{
     417            expr_type: lambda self, e: _annotate_math_functions(self, e)
     418            for expr_type in (exp.Floor, exp.Ceil, exp.Log, exp.Ln, exp.Sqrt, exp.Exp, exp.Round)
     419        },
     420        **{
     421            expr_type: lambda self, e: self._annotate_by_args(e, "this")
     422            for expr_type in (
     423                exp.Left,
     424                exp.Right,
     425                exp.Lower,
     426                exp.Upper,
     427                exp.Pad,
     428                exp.Trim,
     429                exp.RegexpExtract,
     430                exp.RegexpReplace,
     431                exp.Repeat,
     432                exp.Substring,
     433            )
     434        },
     435        exp.Concat: lambda self, e: self._annotate_by_args(e, "expressions"),
     436        exp.Sign: lambda self, e: self._annotate_by_args(e, "this"),
     437        exp.Split: lambda self, e: self._annotate_by_args(e, "this", array=True),
     438    }
     439
     440    def normalize_identifier(self, expression: E) -> E:
     441        if (
     442            isinstance(expression, exp.Identifier)
     443            and self.normalization_strategy is not NormalizationStrategy.CASE_SENSITIVE
     444        ):
     445            parent = expression.parent
     446            while isinstance(parent, exp.Dot):
     447                parent = parent.parent
     448
     449            # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive
     450            # by default. The following check uses a heuristic to detect tables based on whether
     451            # they are qualified. This should generally be correct, because tables in BigQuery
     452            # must be qualified with at least a dataset, unless @@dataset_id is set.
     453            case_sensitive = (
     454                isinstance(parent, exp.UserDefinedFunction)
     455                or (
     456                    isinstance(parent, exp.Table)
     457                    and parent.db
     458                    and (parent.meta.get("quoted_table") or not parent.meta.get("maybe_column"))
     459                )
     460                or expression.meta.get("is_table")
     461            )
     462            if not case_sensitive:
     463                expression.set("this", expression.this.lower())
     464
     465        return expression
     466
     467    class Tokenizer(tokens.Tokenizer):
     468        QUOTES = ["'", '"', '"""', "'''"]
     469        COMMENTS = ["--", "#", ("/*", "*/")]
     470        IDENTIFIERS = ["`"]
     471        STRING_ESCAPES = ["\\"]
     472
     473        HEX_STRINGS = [("0x", ""), ("0X", "")]
     474
     475        BYTE_STRINGS = [
     476            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
     477        ]
     478
     479        RAW_STRINGS = [
     480            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
     481        ]
     482
     483        KEYWORDS = {
     484            **tokens.Tokenizer.KEYWORDS,
     485            "ANY TYPE": TokenType.VARIANT,
     486            "BEGIN": TokenType.COMMAND,
     487            "BEGIN TRANSACTION": TokenType.BEGIN,
     488            "BYTEINT": TokenType.INT,
     489            "BYTES": TokenType.BINARY,
     490            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
     491            "DATETIME": TokenType.TIMESTAMP,
     492            "DECLARE": TokenType.COMMAND,
     493            "ELSEIF": TokenType.COMMAND,
     494            "EXCEPTION": TokenType.COMMAND,
     495            "EXPORT": TokenType.EXPORT,
     496            "FLOAT64": TokenType.DOUBLE,
     497            "FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
     498            "MODEL": TokenType.MODEL,
     499            "NOT DETERMINISTIC": TokenType.VOLATILE,
     500            "RECORD": TokenType.STRUCT,
     501            "TIMESTAMP": TokenType.TIMESTAMPTZ,
     502        }
     503        KEYWORDS.pop("DIV")
     504        KEYWORDS.pop("VALUES")
     505        KEYWORDS.pop("/*+")
     506
     507    class Parser(parser.Parser):
     508        PREFIXED_PIVOT_COLUMNS = True
     509        LOG_DEFAULTS_TO_LN = True
     510        SUPPORTS_IMPLICIT_UNNEST = True
     511
     512        FUNCTIONS = {
     513            **parser.Parser.FUNCTIONS,
     514            "CONTAINS_SUBSTR": _build_contains_substring,
     515            "DATE": _build_date,
     516            "DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
     517            "DATE_SUB": build_date_delta_with_interval(exp.DateSub),
     518            "DATE_TRUNC": lambda args: exp.DateTrunc(
     519                unit=exp.Literal.string(str(seq_get(args, 1))),
     520                this=seq_get(args, 0),
     521                zone=seq_get(args, 2),
     522            ),
     523            "DATETIME": _build_datetime,
     524            "DATETIME_ADD": build_date_delta_with_interval(exp.DatetimeAdd),
     525            "DATETIME_SUB": build_date_delta_with_interval(exp.DatetimeSub),
     526            "DIV": binary_from_function(exp.IntDiv),
     527            "EDIT_DISTANCE": _build_levenshtein,
     528            "FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
     529            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
     530            "JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
     531            "JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
     532            "JSON_QUERY": parser.build_extract_json_with_path(exp.JSONExtract),
     533            "JSON_QUERY_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
     534            "JSON_VALUE": _build_extract_json_with_default_path(exp.JSONExtractScalar),
     535            "JSON_VALUE_ARRAY": _build_extract_json_with_default_path(exp.JSONValueArray),
     536            "LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
     537            "MD5": exp.MD5Digest.from_arg_list,
     538            "TO_HEX": _build_to_hex,
     539            "PARSE_DATE": lambda args: build_formatted_time(exp.StrToDate, "bigquery")(
     540                [seq_get(args, 1), seq_get(args, 0)]
     541            ),
     542            "PARSE_TIMESTAMP": _build_parse_timestamp,
     543            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
     544            "REGEXP_EXTRACT": _build_regexp_extract(exp.RegexpExtract),
     545            "REGEXP_SUBSTR": _build_regexp_extract(exp.RegexpExtract),
     546            "REGEXP_EXTRACT_ALL": _build_regexp_extract(
     547                exp.RegexpExtractAll, default_group=exp.Literal.number(0)
     548            ),
     549            "SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
     550            "SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
     551            "SPLIT": lambda args: exp.Split(
     552                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
     553                this=seq_get(args, 0),
     554                expression=seq_get(args, 1) or exp.Literal.string(","),
     555            ),
     556            "STRPOS": exp.StrPosition.from_arg_list,
     557            "TIME": _build_time,
     558            "TIME_ADD": build_date_delta_with_interval(exp.TimeAdd),
     559            "TIME_SUB": build_date_delta_with_interval(exp.TimeSub),
     560            "TIMESTAMP": _build_timestamp,
     561            "TIMESTAMP_ADD": build_date_delta_with_interval(exp.TimestampAdd),
     562            "TIMESTAMP_SUB": build_date_delta_with_interval(exp.TimestampSub),
     563            "TIMESTAMP_MICROS": lambda args: exp.UnixToTime(
     564                this=seq_get(args, 0), scale=exp.UnixToTime.MICROS
     565            ),
     566            "TIMESTAMP_MILLIS": lambda args: exp.UnixToTime(
     567                this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS
     568            ),
     569            "TIMESTAMP_SECONDS": lambda args: exp.UnixToTime(this=seq_get(args, 0)),
     570            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
     571            "FORMAT_DATETIME": _build_format_time(exp.TsOrDsToDatetime),
     572            "FORMAT_TIMESTAMP": _build_format_time(exp.TsOrDsToTimestamp),
     573        }
     574
     575        FUNCTION_PARSERS = {
     576            **parser.Parser.FUNCTION_PARSERS,
     577            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
     578            "MAKE_INTERVAL": lambda self: self._parse_make_interval(),
     579            "FEATURES_AT_TIME": lambda self: self._parse_features_at_time(),
     580        }
     581        FUNCTION_PARSERS.pop("TRIM")
     582
     583        NO_PAREN_FUNCTIONS = {
     584            **parser.Parser.NO_PAREN_FUNCTIONS,
     585            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
     586        }
     587
     588        NESTED_TYPE_TOKENS = {
     589            *parser.Parser.NESTED_TYPE_TOKENS,
     590            TokenType.TABLE,
     591        }
     592
     593        PROPERTY_PARSERS = {
     594            **parser.Parser.PROPERTY_PARSERS,
     595            "NOT DETERMINISTIC": lambda self: self.expression(
     596                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
     597            ),
     598            "OPTIONS": lambda self: self._parse_with_property(),
     599        }
     600
     601        CONSTRAINT_PARSERS = {
     602            **parser.Parser.CONSTRAINT_PARSERS,
     603            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
     604        }
     605
     606        RANGE_PARSERS = parser.Parser.RANGE_PARSERS.copy()
     607        RANGE_PARSERS.pop(TokenType.OVERLAPS)
     608
     609        NULL_TOKENS = {TokenType.NULL, TokenType.UNKNOWN}
     610
     611        DASHED_TABLE_PART_FOLLOW_TOKENS = {TokenType.DOT, TokenType.L_PAREN, TokenType.R_PAREN}
     612
     613        STATEMENT_PARSERS = {
     614            **parser.Parser.STATEMENT_PARSERS,
     615            TokenType.ELSE: lambda self: self._parse_as_command(self._prev),
     616            TokenType.END: lambda self: self._parse_as_command(self._prev),
     617            TokenType.FOR: lambda self: self._parse_for_in(),
     618            TokenType.EXPORT: lambda self: self._parse_export_data(),
     619        }
     620
     621        BRACKET_OFFSETS = {
     622            "OFFSET": (0, False),
     623            "ORDINAL": (1, False),
     624            "SAFE_OFFSET": (0, True),
     625            "SAFE_ORDINAL": (1, True),
     626        }
     627
     628        def _parse_for_in(self) -> exp.ForIn:
     629            this = self._parse_range()
     630            self._match_text_seq("DO")
     631            return self.expression(exp.ForIn, this=this, expression=self._parse_statement())
     632
     633        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
     634            this = super()._parse_table_part(schema=schema) or self._parse_number()
     635
     636            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
     637            if isinstance(this, exp.Identifier):
     638                table_name = this.name
     639                while self._match(TokenType.DASH, advance=False) and self._next:
     640                    start = self._curr
     641                    while self._is_connected() and not self._match_set(
     642                        self.DASHED_TABLE_PART_FOLLOW_TOKENS, advance=False
     643                    ):
     644                        self._advance()
     645
     646                    table_name += self._find_sql(start, self._prev)
     647
     648                this = exp.Identifier(
     649                    this=table_name, quoted=this.args.get("quoted")
     650                ).update_positions(this)
     651            elif isinstance(this, exp.Literal):
     652                table_name = this.name
     653
     654                if self._is_connected() and self._parse_var(any_token=True):
     655                    table_name += self._prev.text
     656
     657                this = exp.Identifier(this=table_name, quoted=True).update_positions(this)
     658
     659            return this
     660
     661        def _parse_table_parts(
     662            self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
     663        ) -> exp.Table:
     664            table = super()._parse_table_parts(
     665                schema=schema, is_db_reference=is_db_reference, wildcard=True
     666            )
     667
     668            # proj-1.db.tbl -- `1.` is tokenized as a float so we need to unravel it here
     669            if not table.catalog:
     670                if table.db:
     671                    previous_db = table.args["db"]
     672                    parts = table.db.split(".")
     673                    if len(parts) == 2 and not table.args["db"].quoted:
     674                        table.set(
     675                            "catalog", exp.Identifier(this=parts[0]).update_positions(previous_db)
     676                        )
     677                        table.set("db", exp.Identifier(this=parts[1]).update_positions(previous_db))
     678                else:
     679                    previous_this = table.this
     680                    parts = table.name.split(".")
     681                    if len(parts) == 2 and not table.this.quoted:
     682                        table.set(
     683                            "db", exp.Identifier(this=parts[0]).update_positions(previous_this)
     684                        )
     685                        table.set(
     686                            "this", exp.Identifier(this=parts[1]).update_positions(previous_this)
     687                        )
     688
     689            if isinstance(table.this, exp.Identifier) and any("." in p.name for p in table.parts):
     690                alias = table.this
     691                catalog, db, this, *rest = (
     692                    exp.to_identifier(p, quoted=True)
     693                    for p in split_num_words(".".join(p.name for p in table.parts), ".", 3)
     694                )
     695
     696                for part in (catalog, db, this):
     697                    if part:
     698                        part.update_positions(table.this)
     699
     700                if rest and this:
     701                    this = exp.Dot.build([this, *rest])  # type: ignore
     702
     703                table = exp.Table(
     704                    this=this, db=db, catalog=catalog, pivots=table.args.get("pivots")
     705                )
     706                table.meta["quoted_table"] = True
     707            else:
     708                alias = None
     709
     710            # The `INFORMATION_SCHEMA` views in BigQuery need to be qualified by a region or
     711            # dataset, so if the project identifier is omitted we need to fix the ast so that
     712            # the `INFORMATION_SCHEMA.X` bit is represented as a single (quoted) Identifier.
     713            # Otherwise, we wouldn't correctly qualify a `Table` node that references these
     714            # views, because it would seem like the "catalog" part is set, when it'd actually
     715            # be the region/dataset. Merging the two identifiers into a single one is done to
     716            # avoid producing a 4-part Table reference, which would cause issues in the schema
     717            # module, when there are 3-part table names mixed with information schema views.
     718            #
     719            # See: https://cloud.google.com/bigquery/docs/information-schema-intro#syntax
     720            table_parts = table.parts
     721            if len(table_parts) > 1 and table_parts[-2].name.upper() == "INFORMATION_SCHEMA":
     722                # We need to alias the table here to avoid breaking existing qualified columns.
     723                # This is expected to be safe, because if there's an actual alias coming up in
     724                # the token stream, it will overwrite this one. If there isn't one, we are only
     725                # exposing the name that can be used to reference the view explicitly (a no-op).
     726                exp.alias_(
     727                    table,
     728                    t.cast(exp.Identifier, alias or table_parts[-1]),
     729                    table=True,
     730                    copy=False,
     731                )
     732
     733                info_schema_view = f"{table_parts[-2].name}.{table_parts[-1].name}"
     734                new_this = exp.Identifier(this=info_schema_view, quoted=True).update_positions(
     735                    line=table_parts[-2].meta.get("line"),
     736                    col=table_parts[-1].meta.get("col"),
     737                    start=table_parts[-2].meta.get("start"),
     738                    end=table_parts[-1].meta.get("end"),
     739                )
     740                table.set("this", new_this)
     741                table.set("db", seq_get(table_parts, -3))
     742                table.set("catalog", seq_get(table_parts, -4))
     743
     744            return table
     745
     746        def _parse_column(self) -> t.Optional[exp.Expression]:
     747            column = super()._parse_column()
     748            if isinstance(column, exp.Column):
     749                parts = column.parts
     750                if any("." in p.name for p in parts):
     751                    catalog, db, table, this, *rest = (
     752                        exp.to_identifier(p, quoted=True)
     753                        for p in split_num_words(".".join(p.name for p in parts), ".", 4)
     754                    )
     755
     756                    if rest and this:
     757                        this = exp.Dot.build([this, *rest])  # type: ignore
     758
     759                    column = exp.Column(this=this, table=table, db=db, catalog=catalog)
     760                    column.meta["quoted_column"] = True
     761
     762            return column
     763
     764        @t.overload
     765        def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
     766
     767        @t.overload
     768        def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
     769
     770        def _parse_json_object(self, agg=False):
     771            json_object = super()._parse_json_object()
     772            array_kv_pair = seq_get(json_object.expressions, 0)
     773
     774            # Converts BQ's "signature 2" of JSON_OBJECT into SQLGlot's canonical representation
     775            # https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_object_signature2
     776            if (
     777                array_kv_pair
     778                and isinstance(array_kv_pair.this, exp.Array)
     779                and isinstance(array_kv_pair.expression, exp.Array)
     780            ):
     781                keys = array_kv_pair.this.expressions
     782                values = array_kv_pair.expression.expressions
     783
     784                json_object.set(
     785                    "expressions",
     786                    [exp.JSONKeyValue(this=k, expression=v) for k, v in zip(keys, values)],
     787                )
     788
     789            return json_object
     790
     791        def _parse_bracket(
     792            self, this: t.Optional[exp.Expression] = None
     793        ) -> t.Optional[exp.Expression]:
     794            bracket = super()._parse_bracket(this)
     795
     796            if this is bracket:
     797                return bracket
     798
     799            if isinstance(bracket, exp.Bracket):
     800                for expression in bracket.expressions:
     801                    name = expression.name.upper()
     802
     803                    if name not in self.BRACKET_OFFSETS:
     804                        break
     805
     806                    offset, safe = self.BRACKET_OFFSETS[name]
     807                    bracket.set("offset", offset)
     808                    bracket.set("safe", safe)
     809                    expression.replace(expression.expressions[0])
     810
     811            return bracket
     812
     813        def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
     814            unnest = super()._parse_unnest(with_alias=with_alias)
     815
     816            if not unnest:
     817                return None
     818
     819            unnest_expr = seq_get(unnest.expressions, 0)
     820            if unnest_expr:
     821                from sqlglot.optimizer.annotate_types import annotate_types
     822
     823                unnest_expr = annotate_types(unnest_expr, dialect=self.dialect)
     824
     825                # Unnesting a nested array (i.e array of structs) explodes the top-level struct fields,
     826                # in contrast to other dialects such as DuckDB which flattens only the array by default
     827                if unnest_expr.is_type(exp.DataType.Type.ARRAY) and any(
     828                    array_elem.is_type(exp.DataType.Type.STRUCT)
     829                    for array_elem in unnest_expr._type.expressions
     830                ):
     831                    unnest.set("explode_array", True)
     832
     833            return unnest
     834
     835        def _parse_make_interval(self) -> exp.MakeInterval:
     836            expr = exp.MakeInterval()
     837
     838            for arg_key in expr.arg_types:
     839                value = self._parse_lambda()
     840
     841                if not value:
     842                    break
     843
     844                # Non-named arguments are filled sequentially, (optionally) followed by named arguments
     845                # that can appear in any order e.g MAKE_INTERVAL(1, minute => 5, day => 2)
     846                if isinstance(value, exp.Kwarg):
     847                    arg_key = value.this.name
     848
     849                expr.set(arg_key, value)
     850
     851                self._match(TokenType.COMMA)
     852
     853            return expr
     854
     855        def _parse_features_at_time(self) -> exp.FeaturesAtTime:
     856            expr = self.expression(
     857                exp.FeaturesAtTime,
     858                this=(self._match(TokenType.TABLE) and self._parse_table())
     859                or self._parse_select(nested=True),
     860            )
     861
     862            while self._match(TokenType.COMMA):
     863                arg = self._parse_lambda()
     864
     865                # Get the LHS of the Kwarg and set the arg to that value, e.g
     866                # "num_rows => 1" sets the expr's `num_rows` arg
     867                if arg:
     868                    expr.set(arg.this.name, arg)
     869
     870            return expr
     871
     872        def _parse_export_data(self) -> exp.Export:
     873            self._match_text_seq("DATA")
     874
     875            return self.expression(
     876                exp.Export,
     877                connection=self._match_text_seq("WITH", "CONNECTION") and self._parse_table_parts(),
     878                options=self._parse_properties(),
     879                this=self._match_text_seq("AS") and self._parse_select(),
     880            )
     881
     882    class Generator(generator.Generator):
     883        INTERVAL_ALLOWS_PLURAL_FORM = False
     884        JOIN_HINTS = False
     885        QUERY_HINTS = False
     886        TABLE_HINTS = False
     887        LIMIT_FETCH = "LIMIT"
     888        RENAME_TABLE_WITH_DB = False
     889        NVL2_SUPPORTED = False
     890        UNNEST_WITH_ORDINALITY = False
     891        COLLATE_IS_FUNC = True
     892        LIMIT_ONLY_LITERALS = True
     893        SUPPORTS_TABLE_ALIAS_COLUMNS = False
     894        UNPIVOT_ALIASES_ARE_IDENTIFIERS = False
     895        JSON_KEY_VALUE_PAIR_SEP = ","
     896        NULL_ORDERING_SUPPORTED = False
     897        IGNORE_NULLS_IN_FUNC = True
     898        JSON_PATH_SINGLE_QUOTE_ESCAPE = True
     899        CAN_IMPLEMENT_ARRAY_ANY = True
     900        SUPPORTS_TO_NUMBER = False
     901        NAMED_PLACEHOLDER_TOKEN = "@"
     902        HEX_FUNC = "TO_HEX"
     903        WITH_PROPERTIES_PREFIX = "OPTIONS"
     904        SUPPORTS_EXPLODING_PROJECTIONS = False
     905        EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
     906        SUPPORTS_UNIX_SECONDS = True
     907
     908        TRANSFORMS = {
     909            **generator.Generator.TRANSFORMS,
     910            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
     911            exp.ArgMax: arg_max_or_min_no_count("MAX_BY"),
     912            exp.ArgMin: arg_max_or_min_no_count("MIN_BY"),
     913            exp.Array: inline_array_unless_query,
     914            exp.ArrayContains: _array_contains_sql,
     915            exp.ArrayFilter: filter_array_using_unnest,
     916            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
     917            exp.CollateProperty: lambda self, e: (
     918                f"DEFAULT COLLATE {self.sql(e, 'this')}"
     919                if e.args.get("default")
     920                else f"COLLATE {self.sql(e, 'this')}"
     921            ),
     922            exp.Commit: lambda *_: "COMMIT TRANSACTION",
     923            exp.CountIf: rename_func("COUNTIF"),
     924            exp.Create: _create_sql,
     925            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
     926            exp.DateAdd: date_add_interval_sql("DATE", "ADD"),
     927            exp.DateDiff: lambda self, e: self.func(
     928                "DATE_DIFF", e.this, e.expression, unit_to_var(e)
     929            ),
     930            exp.DateFromParts: rename_func("DATE"),
     931            exp.DateStrToDate: datestrtodate_sql,
     932            exp.DateSub: date_add_interval_sql("DATE", "SUB"),
     933            exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
     934            exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
     935            exp.DateTrunc: lambda self, e: self.func(
     936                "DATE_TRUNC", e.this, e.text("unit"), e.args.get("zone")
     937            ),
     938            exp.FromTimeZone: lambda self, e: self.func(
     939                "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
     940            ),
     941            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
     942            exp.GroupConcat: lambda self, e: groupconcat_sql(
     943                self, e, func_name="STRING_AGG", within_group=False
     944            ),
     945            exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))),
     946            exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
     947            exp.If: if_sql(false_value="NULL"),
     948            exp.ILike: no_ilike_sql,
     949            exp.IntDiv: rename_func("DIV"),
     950            exp.Int64: rename_func("INT64"),
     951            exp.JSONExtract: _json_extract_sql,
     952            exp.JSONExtractArray: _json_extract_sql,
     953            exp.JSONExtractScalar: _json_extract_sql,
     954            exp.JSONFormat: rename_func("TO_JSON_STRING"),
     955            exp.Levenshtein: _levenshtein_sql,
     956            exp.Max: max_or_greatest,
     957            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
     958            exp.MD5Digest: rename_func("MD5"),
     959            exp.Min: min_or_least,
     960            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
     961            exp.RegexpExtract: lambda self, e: self.func(
     962                "REGEXP_EXTRACT",
     963                e.this,
     964                e.expression,
     965                e.args.get("position"),
     966                e.args.get("occurrence"),
     967            ),
     968            exp.RegexpExtractAll: lambda self, e: self.func(
     969                "REGEXP_EXTRACT_ALL", e.this, e.expression
     970            ),
     971            exp.RegexpReplace: regexp_replace_sql,
     972            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
     973            exp.ReturnsProperty: _returnsproperty_sql,
     974            exp.Rollback: lambda *_: "ROLLBACK TRANSACTION",
     975            exp.Select: transforms.preprocess(
     976                [
     977                    transforms.explode_projection_to_unnest(),
     978                    transforms.unqualify_unnest,
     979                    transforms.eliminate_distinct_on,
     980                    _alias_ordered_group,
     981                    transforms.eliminate_semi_and_anti_joins,
     982                ]
     983            ),
     984            exp.SHA: rename_func("SHA1"),
     985            exp.SHA2: sha256_sql,
     986            exp.StabilityProperty: lambda self, e: (
     987                "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
     988            ),
     989            exp.String: rename_func("STRING"),
     990            exp.StrPosition: lambda self, e: (
     991                strposition_sql(
     992                    self, e, func_name="INSTR", supports_position=True, supports_occurrence=True
     993                )
     994            ),
     995            exp.StrToDate: _str_to_datetime_sql,
     996            exp.StrToTime: _str_to_datetime_sql,
     997            exp.TimeAdd: date_add_interval_sql("TIME", "ADD"),
     998            exp.TimeFromParts: rename_func("TIME"),
     999            exp.TimestampFromParts: rename_func("DATETIME"),
    1000            exp.TimeSub: date_add_interval_sql("TIME", "SUB"),
    1001            exp.TimestampAdd: date_add_interval_sql("TIMESTAMP", "ADD"),
    1002            exp.TimestampDiff: rename_func("TIMESTAMP_DIFF"),
    1003            exp.TimestampSub: date_add_interval_sql("TIMESTAMP", "SUB"),
    1004            exp.TimeStrToTime: timestrtotime_sql,
    1005            exp.Transaction: lambda *_: "BEGIN TRANSACTION",
    1006            exp.TsOrDsAdd: _ts_or_ds_add_sql,
    1007            exp.TsOrDsDiff: _ts_or_ds_diff_sql,
    1008            exp.TsOrDsToTime: rename_func("TIME"),
    1009            exp.TsOrDsToDatetime: rename_func("DATETIME"),
    1010            exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"),
    1011            exp.Unhex: rename_func("FROM_HEX"),
    1012            exp.UnixDate: rename_func("UNIX_DATE"),
    1013            exp.UnixToTime: _unix_to_time_sql,
    1014            exp.Uuid: lambda *_: "GENERATE_UUID()",
    1015            exp.Values: _derived_table_values_to_unnest,
    1016            exp.VariancePop: rename_func("VAR_POP"),
    1017            exp.SafeDivide: rename_func("SAFE_DIVIDE"),
    1018        }
    1019
    1020        SUPPORTED_JSON_PATH_PARTS = {
    1021            exp.JSONPathKey,
    1022            exp.JSONPathRoot,
    1023            exp.JSONPathSubscript,
    1024        }
    1025
    1026        TYPE_MAPPING = {
    1027            **generator.Generator.TYPE_MAPPING,
    1028            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
    1029            exp.DataType.Type.BIGINT: "INT64",
    1030            exp.DataType.Type.BINARY: "BYTES",
    1031            exp.DataType.Type.BLOB: "BYTES",
    1032            exp.DataType.Type.BOOLEAN: "BOOL",
    1033            exp.DataType.Type.CHAR: "STRING",
    1034            exp.DataType.Type.DECIMAL: "NUMERIC",
    1035            exp.DataType.Type.DOUBLE: "FLOAT64",
    1036            exp.DataType.Type.FLOAT: "FLOAT64",
    1037            exp.DataType.Type.INT: "INT64",
    1038            exp.DataType.Type.NCHAR: "STRING",
    1039            exp.DataType.Type.NVARCHAR: "STRING",
    1040            exp.DataType.Type.SMALLINT: "INT64",
    1041            exp.DataType.Type.TEXT: "STRING",
    1042            exp.DataType.Type.TIMESTAMP: "DATETIME",
    1043            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
    1044            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
    1045            exp.DataType.Type.TINYINT: "INT64",
    1046            exp.DataType.Type.ROWVERSION: "BYTES",
    1047            exp.DataType.Type.UUID: "STRING",
    1048            exp.DataType.Type.VARBINARY: "BYTES",
    1049            exp.DataType.Type.VARCHAR: "STRING",
    1050            exp.DataType.Type.VARIANT: "ANY TYPE",
    1051        }
    1052
    1053        PROPERTIES_LOCATION = {
    1054            **generator.Generator.PROPERTIES_LOCATION,
    1055            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
    1056            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
    1057        }
    1058
    1059        # WINDOW comes after QUALIFY
    1060        # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#window_clause
    1061        AFTER_HAVING_MODIFIER_TRANSFORMS = {
    1062            "qualify": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["qualify"],
    1063            "windows": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["windows"],
    1064        }
    1065
    1066        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
    1067        RESERVED_KEYWORDS = {
    1068            "all",
    1069            "and",
    1070            "any",
    1071            "array",
    1072            "as",
    1073            "asc",
    1074            "assert_rows_modified",
    1075            "at",
    1076            "between",
    1077            "by",
    1078            "case",
    1079            "cast",
    1080            "collate",
    1081            "contains",
    1082            "create",
    1083            "cross",
    1084            "cube",
    1085            "current",
    1086            "default",
    1087            "define",
    1088            "desc",
    1089            "distinct",
    1090            "else",
    1091            "end",
    1092            "enum",
    1093            "escape",
    1094            "except",
    1095            "exclude",
    1096            "exists",
    1097            "extract",
    1098            "false",
    1099            "fetch",
    1100            "following",
    1101            "for",
    1102            "from",
    1103            "full",
    1104            "group",
    1105            "grouping",
    1106            "groups",
    1107            "hash",
    1108            "having",
    1109            "if",
    1110            "ignore",
    1111            "in",
    1112            "inner",
    1113            "intersect",
    1114            "interval",
    1115            "into",
    1116            "is",
    1117            "join",
    1118            "lateral",
    1119            "left",
    1120            "like",
    1121            "limit",
    1122            "lookup",
    1123            "merge",
    1124            "natural",
    1125            "new",
    1126            "no",
    1127            "not",
    1128            "null",
    1129            "nulls",
    1130            "of",
    1131            "on",
    1132            "or",
    1133            "order",
    1134            "outer",
    1135            "over",
    1136            "partition",
    1137            "preceding",
    1138            "proto",
    1139            "qualify",
    1140            "range",
    1141            "recursive",
    1142            "respect",
    1143            "right",
    1144            "rollup",
    1145            "rows",
    1146            "select",
    1147            "set",
    1148            "some",
    1149            "struct",
    1150            "tablesample",
    1151            "then",
    1152            "to",
    1153            "treat",
    1154            "true",
    1155            "unbounded",
    1156            "union",
    1157            "unnest",
    1158            "using",
    1159            "when",
    1160            "where",
    1161            "window",
    1162            "with",
    1163            "within",
    1164        }
    1165
    1166        def mod_sql(self, expression: exp.Mod) -> str:
    1167            this = expression.this
    1168            expr = expression.expression
    1169            return self.func(
    1170                "MOD",
    1171                this.unnest() if isinstance(this, exp.Paren) else this,
    1172                expr.unnest() if isinstance(expr, exp.Paren) else expr,
    1173            )
    1174
    1175        def column_parts(self, expression: exp.Column) -> str:
    1176            if expression.meta.get("quoted_column"):
    1177                # If a column reference is of the form `dataset.table`.name, we need
    1178                # to preserve the quoted table path, otherwise the reference breaks
    1179                table_parts = ".".join(p.name for p in expression.parts[:-1])
    1180                table_path = self.sql(exp.Identifier(this=table_parts, quoted=True))
    1181                return f"{table_path}.{self.sql(expression, 'this')}"
    1182
    1183            return super().column_parts(expression)
    1184
    1185        def table_parts(self, expression: exp.Table) -> str:
    1186            # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so
    1187            # we need to make sure the correct quoting is used in each case.
    1188            #
    1189            # For example, if there is a CTE x that clashes with a schema name, then the former will
    1190            # return the table y in that schema, whereas the latter will return the CTE's y column:
    1191            #
    1192            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y`   -> cross join
    1193            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest
    1194            if expression.meta.get("quoted_table"):
    1195                table_parts = ".".join(p.name for p in expression.parts)
    1196                return self.sql(exp.Identifier(this=table_parts, quoted=True))
    1197
    1198            return super().table_parts(expression)
    1199
    1200        def timetostr_sql(self, expression: exp.TimeToStr) -> str:
    1201            this = expression.this
    1202            if isinstance(this, exp.TsOrDsToDatetime):
    1203                func_name = "FORMAT_DATETIME"
    1204            elif isinstance(this, exp.TsOrDsToTimestamp):
    1205                func_name = "FORMAT_TIMESTAMP"
    1206            else:
    1207                func_name = "FORMAT_DATE"
    1208
    1209            time_expr = (
    1210                this
    1211                if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
    1212                else expression
    1213            )
    1214            return self.func(
    1215                func_name, self.format_time(expression), time_expr.this, expression.args.get("zone")
    1216            )
    1217
    1218        def eq_sql(self, expression: exp.EQ) -> str:
    1219            # Operands of = cannot be NULL in BigQuery
    1220            if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null):
    1221                if not isinstance(expression.parent, exp.Update):
    1222                    return "NULL"
    1223
    1224            return self.binary(expression, "=")
    1225
    1226        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
    1227            parent = expression.parent
    1228
    1229            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
    1230            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
    1231            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
    1232                return self.func(
    1233                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
    1234                )
    1235
    1236            return super().attimezone_sql(expression)
    1237
    1238        def trycast_sql(self, expression: exp.TryCast) -> str:
    1239            return self.cast_sql(expression, safe_prefix="SAFE_")
    1240
    1241        def bracket_sql(self, expression: exp.Bracket) -> str:
    1242            this = expression.this
    1243            expressions = expression.expressions
    1244
    1245            if len(expressions) == 1 and this and this.is_type(exp.DataType.Type.STRUCT):
    1246                arg = expressions[0]
    1247                if arg.type is None:
    1248                    from sqlglot.optimizer.annotate_types import annotate_types
    1249
    1250                    arg = annotate_types(arg, dialect=self.dialect)
    1251
    1252                if arg.type and arg.type.this in exp.DataType.TEXT_TYPES:
    1253                    # BQ doesn't support bracket syntax with string values for structs
    1254                    return f"{self.sql(this)}.{arg.name}"
    1255
    1256            expressions_sql = self.expressions(expression, flat=True)
    1257            offset = expression.args.get("offset")
    1258
    1259            if offset == 0:
    1260                expressions_sql = f"OFFSET({expressions_sql})"
    1261            elif offset == 1:
    1262                expressions_sql = f"ORDINAL({expressions_sql})"
    1263            elif offset is not None:
    1264                self.unsupported(f"Unsupported array offset: {offset}")
    1265
    1266            if expression.args.get("safe"):
    1267                expressions_sql = f"SAFE_{expressions_sql}"
    1268
    1269            return f"{self.sql(this)}[{expressions_sql}]"
    1270
    1271        def in_unnest_op(self, expression: exp.Unnest) -> str:
    1272            return self.sql(expression)
    1273
    1274        def version_sql(self, expression: exp.Version) -> str:
    1275            if expression.name == "TIMESTAMP":
    1276                expression.set("this", "SYSTEM_TIME")
    1277            return super().version_sql(expression)
    1278
    1279        def contains_sql(self, expression: exp.Contains) -> str:
    1280            this = expression.this
    1281            expr = expression.expression
    1282
    1283            if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
    1284                this = this.this
    1285                expr = expr.this
    1286
    1287            return self.func("CONTAINS_SUBSTR", this, expr)
    1288
    1289        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
    1290            this = expression.this
    1291
    1292            # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3]
    1293            # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions,
    1294            # because they aren't literals and so the above syntax is invalid BigQuery.
    1295            if isinstance(this, exp.Array):
    1296                elem = seq_get(this.expressions, 0)
    1297                if not (elem and elem.find(exp.Query)):
    1298                    return f"{self.sql(expression, 'to')}{self.sql(this)}"
    1299
    1300            return super().cast_sql(expression, safe_prefix=safe_prefix)

logger = <Logger sqlglot (WARNING)>
JSON_EXTRACT_TYPE = typing.Union[sqlglot.expressions.JSONExtract, sqlglot.expressions.JSONExtractScalar, sqlglot.expressions.JSONExtractArray]
DQUOTES_ESCAPING_JSON_FUNCTIONS = ('JSON_QUERY', 'JSON_VALUE', 'JSON_QUERY_ARRAY')
class BigQuery(sqlglot.dialects.dialect.Dialect): View Source

     356class BigQuery(Dialect):
     357    WEEK_OFFSET = -1
     358    UNNEST_COLUMN_ONLY = True
     359    SUPPORTS_USER_DEFINED_TYPES = False
     360    SUPPORTS_SEMI_ANTI_JOIN = False
     361    LOG_BASE_FIRST = False
     362    HEX_LOWERCASE = True
     363    FORCE_EARLY_ALIAS_REF_EXPANSION = True
     364    PRESERVE_ORIGINAL_NAMES = True
     365    HEX_STRING_IS_INTEGER_TYPE = True
     366
     367    # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
     368    NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
     369
     370    # bigquery udfs are case sensitive
     371    NORMALIZE_FUNCTIONS = False
     372
     373    # https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_elements_date_time
     374    TIME_MAPPING = {
     375        "%D": "%m/%d/%y",
     376        "%E6S": "%S.%f",
     377        "%e": "%-d",
     378    }
     379
     380    FORMAT_MAPPING = {
     381        "DD": "%d",
     382        "MM": "%m",
     383        "MON": "%b",
     384        "MONTH": "%B",
     385        "YYYY": "%Y",
     386        "YY": "%y",
     387        "HH": "%I",
     388        "HH12": "%I",
     389        "HH24": "%H",
     390        "MI": "%M",
     391        "SS": "%S",
     392        "SSSSS": "%f",
     393        "TZH": "%z",
     394    }
     395
     396    # The _PARTITIONTIME and _PARTITIONDATE pseudo-columns are not returned by a SELECT * statement
     397    # https://cloud.google.com/bigquery/docs/querying-partitioned-tables#query_an_ingestion-time_partitioned_table
     398    PSEUDOCOLUMNS = {"_PARTITIONTIME", "_PARTITIONDATE"}
     399
     400    # All set operations require either a DISTINCT or ALL specifier
     401    SET_OP_DISTINCT_BY_DEFAULT = dict.fromkeys((exp.Except, exp.Intersect, exp.Union), None)
     402
     403    # BigQuery maps Type.TIMESTAMP to DATETIME, so we need to amend the inferred types
     404    TYPE_TO_EXPRESSIONS = {
     405        **Dialect.TYPE_TO_EXPRESSIONS,
     406        exp.DataType.Type.TIMESTAMPTZ: Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.TIMESTAMP],
     407    }
     408    TYPE_TO_EXPRESSIONS.pop(exp.DataType.Type.TIMESTAMP)
     409
     410    ANNOTATORS = {
     411        **Dialect.ANNOTATORS,
     412        **{
     413            expr_type: annotate_with_type_lambda(data_type)
     414            for data_type, expressions in TYPE_TO_EXPRESSIONS.items()
     415            for expr_type in expressions
     416        },
     417        **{
     418            expr_type: lambda self, e: _annotate_math_functions(self, e)
     419            for expr_type in (exp.Floor, exp.Ceil, exp.Log, exp.Ln, exp.Sqrt, exp.Exp, exp.Round)
     420        },
     421        **{
     422            expr_type: lambda self, e: self._annotate_by_args(e, "this")
     423            for expr_type in (
     424                exp.Left,
     425                exp.Right,
     426                exp.Lower,
     427                exp.Upper,
     428                exp.Pad,
     429                exp.Trim,
     430                exp.RegexpExtract,
     431                exp.RegexpReplace,
     432                exp.Repeat,
     433                exp.Substring,
     434            )
     435        },
     436        exp.Concat: lambda self, e: self._annotate_by_args(e, "expressions"),
     437        exp.Sign: lambda self, e: self._annotate_by_args(e, "this"),
     438        exp.Split: lambda self, e: self._annotate_by_args(e, "this", array=True),
     439    }
     440
     441    def normalize_identifier(self, expression: E) -> E:
     442        if (
     443            isinstance(expression, exp.Identifier)
     444            and self.normalization_strategy is not NormalizationStrategy.CASE_SENSITIVE
     445        ):
     446            parent = expression.parent
     447            while isinstance(parent, exp.Dot):
     448                parent = parent.parent
     449
     450            # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive
     451            # by default. The following check uses a heuristic to detect tables based on whether
     452            # they are qualified. This should generally be correct, because tables in BigQuery
     453            # must be qualified with at least a dataset, unless @@dataset_id is set.
     454            case_sensitive = (
     455                isinstance(parent, exp.UserDefinedFunction)
     456                or (
     457                    isinstance(parent, exp.Table)
     458                    and parent.db
     459                    and (parent.meta.get("quoted_table") or not parent.meta.get("maybe_column"))
     460                )
     461                or expression.meta.get("is_table")
     462            )
     463            if not case_sensitive:
     464                expression.set("this", expression.this.lower())
     465
     466        return expression
     467
     468    class Tokenizer(tokens.Tokenizer):
     469        QUOTES = ["'", '"', '"""', "'''"]
     470        COMMENTS = ["--", "#", ("/*", "*/")]
     471        IDENTIFIERS = ["`"]
     472        STRING_ESCAPES = ["\\"]
     473
     474        HEX_STRINGS = [("0x", ""), ("0X", "")]
     475
     476        BYTE_STRINGS = [
     477            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
     478        ]
     479
     480        RAW_STRINGS = [
     481            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
     482        ]
     483
     484        KEYWORDS = {
     485            **tokens.Tokenizer.KEYWORDS,
     486            "ANY TYPE": TokenType.VARIANT,
     487            "BEGIN": TokenType.COMMAND,
     488            "BEGIN TRANSACTION": TokenType.BEGIN,
     489            "BYTEINT": TokenType.INT,
     490            "BYTES": TokenType.BINARY,
     491            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
     492            "DATETIME": TokenType.TIMESTAMP,
     493            "DECLARE": TokenType.COMMAND,
     494            "ELSEIF": TokenType.COMMAND,
     495            "EXCEPTION": TokenType.COMMAND,
     496            "EXPORT": TokenType.EXPORT,
     497            "FLOAT64": TokenType.DOUBLE,
     498            "FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
     499            "MODEL": TokenType.MODEL,
     500            "NOT DETERMINISTIC": TokenType.VOLATILE,
     501            "RECORD": TokenType.STRUCT,
     502            "TIMESTAMP": TokenType.TIMESTAMPTZ,
     503        }
     504        KEYWORDS.pop("DIV")
     505        KEYWORDS.pop("VALUES")
     506        KEYWORDS.pop("/*+")
     507
     508    class Parser(parser.Parser):
     509        PREFIXED_PIVOT_COLUMNS = True
     510        LOG_DEFAULTS_TO_LN = True
     511        SUPPORTS_IMPLICIT_UNNEST = True
     512
     513        FUNCTIONS = {
     514            **parser.Parser.FUNCTIONS,
     515            "CONTAINS_SUBSTR": _build_contains_substring,
     516            "DATE": _build_date,
     517            "DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
     518            "DATE_SUB": build_date_delta_with_interval(exp.DateSub),
     519            "DATE_TRUNC": lambda args: exp.DateTrunc(
     520                unit=exp.Literal.string(str(seq_get(args, 1))),
     521                this=seq_get(args, 0),
     522                zone=seq_get(args, 2),
     523            ),
     524            "DATETIME": _build_datetime,
     525            "DATETIME_ADD": build_date_delta_with_interval(exp.DatetimeAdd),
     526            "DATETIME_SUB": build_date_delta_with_interval(exp.DatetimeSub),
     527            "DIV": binary_from_function(exp.IntDiv),
     528            "EDIT_DISTANCE": _build_levenshtein,
     529            "FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
     530            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
     531            "JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
     532            "JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
     533            "JSON_QUERY": parser.build_extract_json_with_path(exp.JSONExtract),
     534            "JSON_QUERY_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
     535            "JSON_VALUE": _build_extract_json_with_default_path(exp.JSONExtractScalar),
     536            "JSON_VALUE_ARRAY": _build_extract_json_with_default_path(exp.JSONValueArray),
     537            "LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
     538            "MD5": exp.MD5Digest.from_arg_list,
     539            "TO_HEX": _build_to_hex,
     540            "PARSE_DATE": lambda args: build_formatted_time(exp.StrToDate, "bigquery")(
     541                [seq_get(args, 1), seq_get(args, 0)]
     542            ),
     543            "PARSE_TIMESTAMP": _build_parse_timestamp,
     544            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
     545            "REGEXP_EXTRACT": _build_regexp_extract(exp.RegexpExtract),
     546            "REGEXP_SUBSTR": _build_regexp_extract(exp.RegexpExtract),
     547            "REGEXP_EXTRACT_ALL": _build_regexp_extract(
     548                exp.RegexpExtractAll, default_group=exp.Literal.number(0)
     549            ),
     550            "SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
     551            "SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
     552            "SPLIT": lambda args: exp.Split(
     553                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
     554                this=seq_get(args, 0),
     555                expression=seq_get(args, 1) or exp.Literal.string(","),
     556            ),
     557            "STRPOS": exp.StrPosition.from_arg_list,
     558            "TIME": _build_time,
     559            "TIME_ADD": build_date_delta_with_interval(exp.TimeAdd),
     560            "TIME_SUB": build_date_delta_with_interval(exp.TimeSub),
     561            "TIMESTAMP": _build_timestamp,
     562            "TIMESTAMP_ADD": build_date_delta_with_interval(exp.TimestampAdd),
     563            "TIMESTAMP_SUB": build_date_delta_with_interval(exp.TimestampSub),
     564            "TIMESTAMP_MICROS": lambda args: exp.UnixToTime(
     565                this=seq_get(args, 0), scale=exp.UnixToTime.MICROS
     566            ),
     567            "TIMESTAMP_MILLIS": lambda args: exp.UnixToTime(
     568                this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS
     569            ),
     570            "TIMESTAMP_SECONDS": lambda args: exp.UnixToTime(this=seq_get(args, 0)),
     571            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
     572            "FORMAT_DATETIME": _build_format_time(exp.TsOrDsToDatetime),
     573            "FORMAT_TIMESTAMP": _build_format_time(exp.TsOrDsToTimestamp),
     574        }
     575
     576        FUNCTION_PARSERS = {
     577            **parser.Parser.FUNCTION_PARSERS,
     578            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
     579            "MAKE_INTERVAL": lambda self: self._parse_make_interval(),
     580            "FEATURES_AT_TIME": lambda self: self._parse_features_at_time(),
     581        }
     582        FUNCTION_PARSERS.pop("TRIM")
     583
     584        NO_PAREN_FUNCTIONS = {
     585            **parser.Parser.NO_PAREN_FUNCTIONS,
     586            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
     587        }
     588
     589        NESTED_TYPE_TOKENS = {
     590            *parser.Parser.NESTED_TYPE_TOKENS,
     591            TokenType.TABLE,
     592        }
     593
     594        PROPERTY_PARSERS = {
     595            **parser.Parser.PROPERTY_PARSERS,
     596            "NOT DETERMINISTIC": lambda self: self.expression(
     597                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
     598            ),
     599            "OPTIONS": lambda self: self._parse_with_property(),
     600        }
     601
     602        CONSTRAINT_PARSERS = {
     603            **parser.Parser.CONSTRAINT_PARSERS,
     604            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
     605        }
     606
     607        RANGE_PARSERS = parser.Parser.RANGE_PARSERS.copy()
     608        RANGE_PARSERS.pop(TokenType.OVERLAPS)
     609
     610        NULL_TOKENS = {TokenType.NULL, TokenType.UNKNOWN}
     611
     612        DASHED_TABLE_PART_FOLLOW_TOKENS = {TokenType.DOT, TokenType.L_PAREN, TokenType.R_PAREN}
     613
     614        STATEMENT_PARSERS = {
     615            **parser.Parser.STATEMENT_PARSERS,
     616            TokenType.ELSE: lambda self: self._parse_as_command(self._prev),
     617            TokenType.END: lambda self: self._parse_as_command(self._prev),
     618            TokenType.FOR: lambda self: self._parse_for_in(),
     619            TokenType.EXPORT: lambda self: self._parse_export_data(),
     620        }
     621
     622        BRACKET_OFFSETS = {
     623            "OFFSET": (0, False),
     624            "ORDINAL": (1, False),
     625            "SAFE_OFFSET": (0, True),
     626            "SAFE_ORDINAL": (1, True),
     627        }
     628
     629        def _parse_for_in(self) -> exp.ForIn:
     630            this = self._parse_range()
     631            self._match_text_seq("DO")
     632            return self.expression(exp.ForIn, this=this, expression=self._parse_statement())
     633
     634        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
     635            this = super()._parse_table_part(schema=schema) or self._parse_number()
     636
     637            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
     638            if isinstance(this, exp.Identifier):
     639                table_name = this.name
     640                while self._match(TokenType.DASH, advance=False) and self._next:
     641                    start = self._curr
     642                    while self._is_connected() and not self._match_set(
     643                        self.DASHED_TABLE_PART_FOLLOW_TOKENS, advance=False
     644                    ):
     645                        self._advance()
     646
     647                    table_name += self._find_sql(start, self._prev)
     648
     649                this = exp.Identifier(
     650                    this=table_name, quoted=this.args.get("quoted")
     651                ).update_positions(this)
     652            elif isinstance(this, exp.Literal):
     653                table_name = this.name
     654
     655                if self._is_connected() and self._parse_var(any_token=True):
     656                    table_name += self._prev.text
     657
     658                this = exp.Identifier(this=table_name, quoted=True).update_positions(this)
     659
     660            return this
     661
     662        def _parse_table_parts(
     663            self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
     664        ) -> exp.Table:
     665            table = super()._parse_table_parts(
     666                schema=schema, is_db_reference=is_db_reference, wildcard=True
     667            )
     668
     669            # proj-1.db.tbl -- `1.` is tokenized as a float so we need to unravel it here
     670            if not table.catalog:
     671                if table.db:
     672                    previous_db = table.args["db"]
     673                    parts = table.db.split(".")
     674                    if len(parts) == 2 and not table.args["db"].quoted:
     675                        table.set(
     676                            "catalog", exp.Identifier(this=parts[0]).update_positions(previous_db)
     677                        )
     678                        table.set("db", exp.Identifier(this=parts[1]).update_positions(previous_db))
     679                else:
     680                    previous_this = table.this
     681                    parts = table.name.split(".")
     682                    if len(parts) == 2 and not table.this.quoted:
     683                        table.set(
     684                            "db", exp.Identifier(this=parts[0]).update_positions(previous_this)
     685                        )
     686                        table.set(
     687                            "this", exp.Identifier(this=parts[1]).update_positions(previous_this)
     688                        )
     689
     690            if isinstance(table.this, exp.Identifier) and any("." in p.name for p in table.parts):
     691                alias = table.this
     692                catalog, db, this, *rest = (
     693                    exp.to_identifier(p, quoted=True)
     694                    for p in split_num_words(".".join(p.name for p in table.parts), ".", 3)
     695                )
     696
     697                for part in (catalog, db, this):
     698                    if part:
     699                        part.update_positions(table.this)
     700
     701                if rest and this:
     702                    this = exp.Dot.build([this, *rest])  # type: ignore
     703
     704                table = exp.Table(
     705                    this=this, db=db, catalog=catalog, pivots=table.args.get("pivots")
     706                )
     707                table.meta["quoted_table"] = True
     708            else:
     709                alias = None
     710
     711            # The `INFORMATION_SCHEMA` views in BigQuery need to be qualified by a region or
     712            # dataset, so if the project identifier is omitted we need to fix the ast so that
     713            # the `INFORMATION_SCHEMA.X` bit is represented as a single (quoted) Identifier.
     714            # Otherwise, we wouldn't correctly qualify a `Table` node that references these
     715            # views, because it would seem like the "catalog" part is set, when it'd actually
     716            # be the region/dataset. Merging the two identifiers into a single one is done to
     717            # avoid producing a 4-part Table reference, which would cause issues in the schema
     718            # module, when there are 3-part table names mixed with information schema views.
     719            #
     720            # See: https://cloud.google.com/bigquery/docs/information-schema-intro#syntax
     721            table_parts = table.parts
     722            if len(table_parts) > 1 and table_parts[-2].name.upper() == "INFORMATION_SCHEMA":
     723                # We need to alias the table here to avoid breaking existing qualified columns.
     724                # This is expected to be safe, because if there's an actual alias coming up in
     725                # the token stream, it will overwrite this one. If there isn't one, we are only
     726                # exposing the name that can be used to reference the view explicitly (a no-op).
     727                exp.alias_(
     728                    table,
     729                    t.cast(exp.Identifier, alias or table_parts[-1]),
     730                    table=True,
     731                    copy=False,
     732                )
     733
     734                info_schema_view = f"{table_parts[-2].name}.{table_parts[-1].name}"
     735                new_this = exp.Identifier(this=info_schema_view, quoted=True).update_positions(
     736                    line=table_parts[-2].meta.get("line"),
     737                    col=table_parts[-1].meta.get("col"),
     738                    start=table_parts[-2].meta.get("start"),
     739                    end=table_parts[-1].meta.get("end"),
     740                )
     741                table.set("this", new_this)
     742                table.set("db", seq_get(table_parts, -3))
     743                table.set("catalog", seq_get(table_parts, -4))
     744
     745            return table
     746
     747        def _parse_column(self) -> t.Optional[exp.Expression]:
     748            column = super()._parse_column()
     749            if isinstance(column, exp.Column):
     750                parts = column.parts
     751                if any("." in p.name for p in parts):
     752                    catalog, db, table, this, *rest = (
     753                        exp.to_identifier(p, quoted=True)
     754                        for p in split_num_words(".".join(p.name for p in parts), ".", 4)
     755                    )
     756
     757                    if rest and this:
     758                        this = exp.Dot.build([this, *rest])  # type: ignore
     759
     760                    column = exp.Column(this=this, table=table, db=db, catalog=catalog)
     761                    column.meta["quoted_column"] = True
     762
     763            return column
     764
     765        @t.overload
     766        def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
     767
     768        @t.overload
     769        def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
     770
     771        def _parse_json_object(self, agg=False):
     772            json_object = super()._parse_json_object()
     773            array_kv_pair = seq_get(json_object.expressions, 0)
     774
     775            # Converts BQ's "signature 2" of JSON_OBJECT into SQLGlot's canonical representation
     776            # https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_object_signature2
     777            if (
     778                array_kv_pair
     779                and isinstance(array_kv_pair.this, exp.Array)
     780                and isinstance(array_kv_pair.expression, exp.Array)
     781            ):
     782                keys = array_kv_pair.this.expressions
     783                values = array_kv_pair.expression.expressions
     784
     785                json_object.set(
     786                    "expressions",
     787                    [exp.JSONKeyValue(this=k, expression=v) for k, v in zip(keys, values)],
     788                )
     789
     790            return json_object
     791
     792        def _parse_bracket(
     793            self, this: t.Optional[exp.Expression] = None
     794        ) -> t.Optional[exp.Expression]:
     795            bracket = super()._parse_bracket(this)
     796
     797            if this is bracket:
     798                return bracket
     799
     800            if isinstance(bracket, exp.Bracket):
     801                for expression in bracket.expressions:
     802                    name = expression.name.upper()
     803
     804                    if name not in self.BRACKET_OFFSETS:
     805                        break
     806
     807                    offset, safe = self.BRACKET_OFFSETS[name]
     808                    bracket.set("offset", offset)
     809                    bracket.set("safe", safe)
     810                    expression.replace(expression.expressions[0])
     811
     812            return bracket
     813
     814        def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
     815            unnest = super()._parse_unnest(with_alias=with_alias)
     816
     817            if not unnest:
     818                return None
     819
     820            unnest_expr = seq_get(unnest.expressions, 0)
     821            if unnest_expr:
     822                from sqlglot.optimizer.annotate_types import annotate_types
     823
     824                unnest_expr = annotate_types(unnest_expr, dialect=self.dialect)
     825
     826                # Unnesting a nested array (i.e array of structs) explodes the top-level struct fields,
     827                # in contrast to other dialects such as DuckDB which flattens only the array by default
     828                if unnest_expr.is_type(exp.DataType.Type.ARRAY) and any(
     829                    array_elem.is_type(exp.DataType.Type.STRUCT)
     830                    for array_elem in unnest_expr._type.expressions
     831                ):
     832                    unnest.set("explode_array", True)
     833
     834            return unnest
     835
     836        def _parse_make_interval(self) -> exp.MakeInterval:
     837            expr = exp.MakeInterval()
     838
     839            for arg_key in expr.arg_types:
     840                value = self._parse_lambda()
     841
     842                if not value:
     843                    break
     844
     845                # Non-named arguments are filled sequentially, (optionally) followed by named arguments
     846                # that can appear in any order e.g MAKE_INTERVAL(1, minute => 5, day => 2)
     847                if isinstance(value, exp.Kwarg):
     848                    arg_key = value.this.name
     849
     850                expr.set(arg_key, value)
     851
     852                self._match(TokenType.COMMA)
     853
     854            return expr
     855
     856        def _parse_features_at_time(self) -> exp.FeaturesAtTime:
     857            expr = self.expression(
     858                exp.FeaturesAtTime,
     859                this=(self._match(TokenType.TABLE) and self._parse_table())
     860                or self._parse_select(nested=True),
     861            )
     862
     863            while self._match(TokenType.COMMA):
     864                arg = self._parse_lambda()
     865
     866                # Get the LHS of the Kwarg and set the arg to that value, e.g
     867                # "num_rows => 1" sets the expr's `num_rows` arg
     868                if arg:
     869                    expr.set(arg.this.name, arg)
     870
     871            return expr
     872
     873        def _parse_export_data(self) -> exp.Export:
     874            self._match_text_seq("DATA")
     875
     876            return self.expression(
     877                exp.Export,
     878                connection=self._match_text_seq("WITH", "CONNECTION") and self._parse_table_parts(),
     879                options=self._parse_properties(),
     880                this=self._match_text_seq("AS") and self._parse_select(),
     881            )
     882
     883    class Generator(generator.Generator):
     884        INTERVAL_ALLOWS_PLURAL_FORM = False
     885        JOIN_HINTS = False
     886        QUERY_HINTS = False
     887        TABLE_HINTS = False
     888        LIMIT_FETCH = "LIMIT"
     889        RENAME_TABLE_WITH_DB = False
     890        NVL2_SUPPORTED = False
     891        UNNEST_WITH_ORDINALITY = False
     892        COLLATE_IS_FUNC = True
     893        LIMIT_ONLY_LITERALS = True
     894        SUPPORTS_TABLE_ALIAS_COLUMNS = False
     895        UNPIVOT_ALIASES_ARE_IDENTIFIERS = False
     896        JSON_KEY_VALUE_PAIR_SEP = ","
     897        NULL_ORDERING_SUPPORTED = False
     898        IGNORE_NULLS_IN_FUNC = True
     899        JSON_PATH_SINGLE_QUOTE_ESCAPE = True
     900        CAN_IMPLEMENT_ARRAY_ANY = True
     901        SUPPORTS_TO_NUMBER = False
     902        NAMED_PLACEHOLDER_TOKEN = "@"
     903        HEX_FUNC = "TO_HEX"
     904        WITH_PROPERTIES_PREFIX = "OPTIONS"
     905        SUPPORTS_EXPLODING_PROJECTIONS = False
     906        EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
     907        SUPPORTS_UNIX_SECONDS = True
     908
     909        TRANSFORMS = {
     910            **generator.Generator.TRANSFORMS,
     911            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
     912            exp.ArgMax: arg_max_or_min_no_count("MAX_BY"),
     913            exp.ArgMin: arg_max_or_min_no_count("MIN_BY"),
     914            exp.Array: inline_array_unless_query,
     915            exp.ArrayContains: _array_contains_sql,
     916            exp.ArrayFilter: filter_array_using_unnest,
     917            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
     918            exp.CollateProperty: lambda self, e: (
     919                f"DEFAULT COLLATE {self.sql(e, 'this')}"
     920                if e.args.get("default")
     921                else f"COLLATE {self.sql(e, 'this')}"
     922            ),
     923            exp.Commit: lambda *_: "COMMIT TRANSACTION",
     924            exp.CountIf: rename_func("COUNTIF"),
     925            exp.Create: _create_sql,
     926            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
     927            exp.DateAdd: date_add_interval_sql("DATE", "ADD"),
     928            exp.DateDiff: lambda self, e: self.func(
     929                "DATE_DIFF", e.this, e.expression, unit_to_var(e)
     930            ),
     931            exp.DateFromParts: rename_func("DATE"),
     932            exp.DateStrToDate: datestrtodate_sql,
     933            exp.DateSub: date_add_interval_sql("DATE", "SUB"),
     934            exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
     935            exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
     936            exp.DateTrunc: lambda self, e: self.func(
     937                "DATE_TRUNC", e.this, e.text("unit"), e.args.get("zone")
     938            ),
     939            exp.FromTimeZone: lambda self, e: self.func(
     940                "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
     941            ),
     942            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
     943            exp.GroupConcat: lambda self, e: groupconcat_sql(
     944                self, e, func_name="STRING_AGG", within_group=False
     945            ),
     946            exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))),
     947            exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
     948            exp.If: if_sql(false_value="NULL"),
     949            exp.ILike: no_ilike_sql,
     950            exp.IntDiv: rename_func("DIV"),
     951            exp.Int64: rename_func("INT64"),
     952            exp.JSONExtract: _json_extract_sql,
     953            exp.JSONExtractArray: _json_extract_sql,
     954            exp.JSONExtractScalar: _json_extract_sql,
     955            exp.JSONFormat: rename_func("TO_JSON_STRING"),
     956            exp.Levenshtein: _levenshtein_sql,
     957            exp.Max: max_or_greatest,
     958            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
     959            exp.MD5Digest: rename_func("MD5"),
     960            exp.Min: min_or_least,
     961            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
     962            exp.RegexpExtract: lambda self, e: self.func(
     963                "REGEXP_EXTRACT",
     964                e.this,
     965                e.expression,
     966                e.args.get("position"),
     967                e.args.get("occurrence"),
     968            ),
     969            exp.RegexpExtractAll: lambda self, e: self.func(
     970                "REGEXP_EXTRACT_ALL", e.this, e.expression
     971            ),
     972            exp.RegexpReplace: regexp_replace_sql,
     973            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
     974            exp.ReturnsProperty: _returnsproperty_sql,
     975            exp.Rollback: lambda *_: "ROLLBACK TRANSACTION",
     976            exp.Select: transforms.preprocess(
     977                [
     978                    transforms.explode_projection_to_unnest(),
     979                    transforms.unqualify_unnest,
     980                    transforms.eliminate_distinct_on,
     981                    _alias_ordered_group,
     982                    transforms.eliminate_semi_and_anti_joins,
     983                ]
     984            ),
     985            exp.SHA: rename_func("SHA1"),
     986            exp.SHA2: sha256_sql,
     987            exp.StabilityProperty: lambda self, e: (
     988                "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
     989            ),
     990            exp.String: rename_func("STRING"),
     991            exp.StrPosition: lambda self, e: (
     992                strposition_sql(
     993                    self, e, func_name="INSTR", supports_position=True, supports_occurrence=True
     994                )
     995            ),
     996            exp.StrToDate: _str_to_datetime_sql,
     997            exp.StrToTime: _str_to_datetime_sql,
     998            exp.TimeAdd: date_add_interval_sql("TIME", "ADD"),
     999            exp.TimeFromParts: rename_func("TIME"),
    1000            exp.TimestampFromParts: rename_func("DATETIME"),
    1001            exp.TimeSub: date_add_interval_sql("TIME", "SUB"),
    1002            exp.TimestampAdd: date_add_interval_sql("TIMESTAMP", "ADD"),
    1003            exp.TimestampDiff: rename_func("TIMESTAMP_DIFF"),
    1004            exp.TimestampSub: date_add_interval_sql("TIMESTAMP", "SUB"),
    1005            exp.TimeStrToTime: timestrtotime_sql,
    1006            exp.Transaction: lambda *_: "BEGIN TRANSACTION",
    1007            exp.TsOrDsAdd: _ts_or_ds_add_sql,
    1008            exp.TsOrDsDiff: _ts_or_ds_diff_sql,
    1009            exp.TsOrDsToTime: rename_func("TIME"),
    1010            exp.TsOrDsToDatetime: rename_func("DATETIME"),
    1011            exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"),
    1012            exp.Unhex: rename_func("FROM_HEX"),
    1013            exp.UnixDate: rename_func("UNIX_DATE"),
    1014            exp.UnixToTime: _unix_to_time_sql,
    1015            exp.Uuid: lambda *_: "GENERATE_UUID()",
    1016            exp.Values: _derived_table_values_to_unnest,
    1017            exp.VariancePop: rename_func("VAR_POP"),
    1018            exp.SafeDivide: rename_func("SAFE_DIVIDE"),
    1019        }
    1020
    1021        SUPPORTED_JSON_PATH_PARTS = {
    1022            exp.JSONPathKey,
    1023            exp.JSONPathRoot,
    1024            exp.JSONPathSubscript,
    1025        }
    1026
    1027        TYPE_MAPPING = {
    1028            **generator.Generator.TYPE_MAPPING,
    1029            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
    1030            exp.DataType.Type.BIGINT: "INT64",
    1031            exp.DataType.Type.BINARY: "BYTES",
    1032            exp.DataType.Type.BLOB: "BYTES",
    1033            exp.DataType.Type.BOOLEAN: "BOOL",
    1034            exp.DataType.Type.CHAR: "STRING",
    1035            exp.DataType.Type.DECIMAL: "NUMERIC",
    1036            exp.DataType.Type.DOUBLE: "FLOAT64",
    1037            exp.DataType.Type.FLOAT: "FLOAT64",
    1038            exp.DataType.Type.INT: "INT64",
    1039            exp.DataType.Type.NCHAR: "STRING",
    1040            exp.DataType.Type.NVARCHAR: "STRING",
    1041            exp.DataType.Type.SMALLINT: "INT64",
    1042            exp.DataType.Type.TEXT: "STRING",
    1043            exp.DataType.Type.TIMESTAMP: "DATETIME",
    1044            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
    1045            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
    1046            exp.DataType.Type.TINYINT: "INT64",
    1047            exp.DataType.Type.ROWVERSION: "BYTES",
    1048            exp.DataType.Type.UUID: "STRING",
    1049            exp.DataType.Type.VARBINARY: "BYTES",
    1050            exp.DataType.Type.VARCHAR: "STRING",
    1051            exp.DataType.Type.VARIANT: "ANY TYPE",
    1052        }
    1053
    1054        PROPERTIES_LOCATION = {
    1055            **generator.Generator.PROPERTIES_LOCATION,
    1056            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
    1057            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
    1058        }
    1059
    1060        # WINDOW comes after QUALIFY
    1061        # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#window_clause
    1062        AFTER_HAVING_MODIFIER_TRANSFORMS = {
    1063            "qualify": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["qualify"],
    1064            "windows": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["windows"],
    1065        }
    1066
    1067        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
    1068        RESERVED_KEYWORDS = {
    1069            "all",
    1070            "and",
    1071            "any",
    1072            "array",
    1073            "as",
    1074            "asc",
    1075            "assert_rows_modified",
    1076            "at",
    1077            "between",
    1078            "by",
    1079            "case",
    1080            "cast",
    1081            "collate",
    1082            "contains",
    1083            "create",
    1084            "cross",
    1085            "cube",
    1086            "current",
    1087            "default",
    1088            "define",
    1089            "desc",
    1090            "distinct",
    1091            "else",
    1092            "end",
    1093            "enum",
    1094            "escape",
    1095            "except",
    1096            "exclude",
    1097            "exists",
    1098            "extract",
    1099            "false",
    1100            "fetch",
    1101            "following",
    1102            "for",
    1103            "from",
    1104            "full",
    1105            "group",
    1106            "grouping",
    1107            "groups",
    1108            "hash",
    1109            "having",
    1110            "if",
    1111            "ignore",
    1112            "in",
    1113            "inner",
    1114            "intersect",
    1115            "interval",
    1116            "into",
    1117            "is",
    1118            "join",
    1119            "lateral",
    1120            "left",
    1121            "like",
    1122            "limit",
    1123            "lookup",
    1124            "merge",
    1125            "natural",
    1126            "new",
    1127            "no",
    1128            "not",
    1129            "null",
    1130            "nulls",
    1131            "of",
    1132            "on",
    1133            "or",
    1134            "order",
    1135            "outer",
    1136            "over",
    1137            "partition",
    1138            "preceding",
    1139            "proto",
    1140            "qualify",
    1141            "range",
    1142            "recursive",
    1143            "respect",
    1144            "right",
    1145            "rollup",
    1146            "rows",
    1147            "select",
    1148            "set",
    1149            "some",
    1150            "struct",
    1151            "tablesample",
    1152            "then",
    1153            "to",
    1154            "treat",
    1155            "true",
    1156            "unbounded",
    1157            "union",
    1158            "unnest",
    1159            "using",
    1160            "when",
    1161            "where",
    1162            "window",
    1163            "with",
    1164            "within",
    1165        }
    1166
    1167        def mod_sql(self, expression: exp.Mod) -> str:
    1168            this = expression.this
    1169            expr = expression.expression
    1170            return self.func(
    1171                "MOD",
    1172                this.unnest() if isinstance(this, exp.Paren) else this,
    1173                expr.unnest() if isinstance(expr, exp.Paren) else expr,
    1174            )
    1175
    1176        def column_parts(self, expression: exp.Column) -> str:
    1177            if expression.meta.get("quoted_column"):
    1178                # If a column reference is of the form `dataset.table`.name, we need
    1179                # to preserve the quoted table path, otherwise the reference breaks
    1180                table_parts = ".".join(p.name for p in expression.parts[:-1])
    1181                table_path = self.sql(exp.Identifier(this=table_parts, quoted=True))
    1182                return f"{table_path}.{self.sql(expression, 'this')}"
    1183
    1184            return super().column_parts(expression)
    1185
    1186        def table_parts(self, expression: exp.Table) -> str:
    1187            # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so
    1188            # we need to make sure the correct quoting is used in each case.
    1189            #
    1190            # For example, if there is a CTE x that clashes with a schema name, then the former will
    1191            # return the table y in that schema, whereas the latter will return the CTE's y column:
    1192            #
    1193            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y`   -> cross join
    1194            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest
    1195            if expression.meta.get("quoted_table"):
    1196                table_parts = ".".join(p.name for p in expression.parts)
    1197                return self.sql(exp.Identifier(this=table_parts, quoted=True))
    1198
    1199            return super().table_parts(expression)
    1200
    1201        def timetostr_sql(self, expression: exp.TimeToStr) -> str:
    1202            this = expression.this
    1203            if isinstance(this, exp.TsOrDsToDatetime):
    1204                func_name = "FORMAT_DATETIME"
    1205            elif isinstance(this, exp.TsOrDsToTimestamp):
    1206                func_name = "FORMAT_TIMESTAMP"
    1207            else:
    1208                func_name = "FORMAT_DATE"
    1209
    1210            time_expr = (
    1211                this
    1212                if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
    1213                else expression
    1214            )
    1215            return self.func(
    1216                func_name, self.format_time(expression), time_expr.this, expression.args.get("zone")
    1217            )
    1218
    1219        def eq_sql(self, expression: exp.EQ) -> str:
    1220            # Operands of = cannot be NULL in BigQuery
    1221            if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null):
    1222                if not isinstance(expression.parent, exp.Update):
    1223                    return "NULL"
    1224
    1225            return self.binary(expression, "=")
    1226
    1227        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
    1228            parent = expression.parent
    1229
    1230            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
    1231            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
    1232            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
    1233                return self.func(
    1234                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
    1235                )
    1236
    1237            return super().attimezone_sql(expression)
    1238
    1239        def trycast_sql(self, expression: exp.TryCast) -> str:
    1240            return self.cast_sql(expression, safe_prefix="SAFE_")
    1241
    1242        def bracket_sql(self, expression: exp.Bracket) -> str:
    1243            this = expression.this
    1244            expressions = expression.expressions
    1245
    1246            if len(expressions) == 1 and this and this.is_type(exp.DataType.Type.STRUCT):
    1247                arg = expressions[0]
    1248                if arg.type is None:
    1249                    from sqlglot.optimizer.annotate_types import annotate_types
    1250
    1251                    arg = annotate_types(arg, dialect=self.dialect)
    1252
    1253                if arg.type and arg.type.this in exp.DataType.TEXT_TYPES:
    1254                    # BQ doesn't support bracket syntax with string values for structs
    1255                    return f"{self.sql(this)}.{arg.name}"
    1256
    1257            expressions_sql = self.expressions(expression, flat=True)
    1258            offset = expression.args.get("offset")
    1259
    1260            if offset == 0:
    1261                expressions_sql = f"OFFSET({expressions_sql})"
    1262            elif offset == 1:
    1263                expressions_sql = f"ORDINAL({expressions_sql})"
    1264            elif offset is not None:
    1265                self.unsupported(f"Unsupported array offset: {offset}")
    1266
    1267            if expression.args.get("safe"):
    1268                expressions_sql = f"SAFE_{expressions_sql}"
    1269
    1270            return f"{self.sql(this)}[{expressions_sql}]"
    1271
    1272        def in_unnest_op(self, expression: exp.Unnest) -> str:
    1273            return self.sql(expression)
    1274
    1275        def version_sql(self, expression: exp.Version) -> str:
    1276            if expression.name == "TIMESTAMP":
    1277                expression.set("this", "SYSTEM_TIME")
    1278            return super().version_sql(expression)
    1279
    1280        def contains_sql(self, expression: exp.Contains) -> str:
    1281            this = expression.this
    1282            expr = expression.expression
    1283
    1284            if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
    1285                this = this.this
    1286                expr = expr.this
    1287
    1288            return self.func("CONTAINS_SUBSTR", this, expr)
    1289
    1290        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
    1291            this = expression.this
    1292
    1293            # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3]
    1294            # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions,
    1295            # because they aren't literals and so the above syntax is invalid BigQuery.
    1296            if isinstance(this, exp.Array):
    1297                elem = seq_get(this.expressions, 0)
    1298                if not (elem and elem.find(exp.Query)):
    1299                    return f"{self.sql(expression, 'to')}{self.sql(this)}"
    1300
    1301            return super().cast_sql(expression, safe_prefix=safe_prefix)

WEEK_OFFSET = -1

First day of the week in DATE_TRUNC(week). Defaults to 0 (Monday). -1 would be Sunday.

UNNEST_COLUMN_ONLY = True

Whether `UNNEST` table aliases are treated as column aliases.

SUPPORTS_USER_DEFINED_TYPES = False

Whether user-defined data types are supported.

SUPPORTS_SEMI_ANTI_JOIN = False

Whether `SEMI` or `ANTI` joins are supported.

LOG_BASE_FIRST: Optional[bool] = False

Whether the base comes first in the `LOG` function. Possible values: `True`, `False`, `None` (two arguments are not supported by `LOG`)

HEX_LOWERCASE = True

Whether the `HEX` function returns a lowercase hexadecimal string.

FORCE_EARLY_ALIAS_REF_EXPANSION = True

Whether alias reference expansion (_expand_alias_refs()) should run before column qualification (_qualify_columns()).

###### For example:

> WITH data AS ( SELECT 1 AS id, 2 AS my_id ) SELECT id AS my_id FROM data WHERE my_id = 1 GROUP BY my_id, HAVING my_id = 1

In most dialects, "my_id" would refer to "data.my_id" across the query, except: - BigQuery, which will forward the alias to GROUP BY + HAVING clauses i.e it resolves to "WHERE my_id = 1 GROUP BY id HAVING id = 1" - Clickhouse, which will forward the alias across the query i.e it resolves to "WHERE id = 1 GROUP BY id HAVING id = 1"

PRESERVE_ORIGINAL_NAMES: bool = True

Whether the name of the function should be preserved inside the node's metadata, can be useful for roundtripping deprecated vs new functions that share an AST node e.g JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery

HEX_STRING_IS_INTEGER_TYPE: bool = True

Whether hex strings such as x'CC' evaluate to integer or binary/blob type

NORMALIZATION_STRATEGY = <NormalizationStrategy.CASE_INSENSITIVE: 'CASE_INSENSITIVE'>

Specifies the strategy according to which identifiers should be normalized.

NORMALIZE_FUNCTIONS: bool | str = False

Determines how function names are going to be normalized.

###### Possible values:

> "upper" or True: Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.

TIME_MAPPING: Dict[str, str] = {'%D': '%m/%d/%y', '%E6S': '%S.%f', '%e': '%-d'}

Associates this dialect's time formats with their equivalent Python `strftime` formats.

FORMAT_MAPPING: Dict[str, str] = {'DD': '%d', 'MM': '%m', 'MON': '%b', 'MONTH': '%B', 'YYYY': '%Y', 'YY': '%y', 'HH': '%I', 'HH12': '%I', 'HH24': '%H', 'MI': '%M', 'SS': '%S', 'SSSSS': '%f', 'TZH': '%z'}

Helper which is used for parsing the special syntax `CAST(x AS DATE FORMAT 'yyyy')`. If empty, the corresponding trie will be constructed off of `TIME_MAPPING`.

PSEUDOCOLUMNS: Set[str] = {'_PARTITIONDATE', '_PARTITIONTIME'}

Columns that are auto-generated by the engine corresponding to this dialect. For example, such columns may be excluded from `SELECT *` queries.

SET_OP_DISTINCT_BY_DEFAULT: Dict[Type[sqlglot.expressions.Expression], Optional[bool]] = {<class 'sqlglot.expressions.Except'>: None, <class 'sqlglot.expressions.Intersect'>: None, <class 'sqlglot.expressions.Union'>: None}

Whether a set operation uses DISTINCT by default. This is `None` when either `DISTINCT` or `ALL` must be explicitly specified.

TYPE_TO_EXPRESSIONS: Dict[sqlglot.expressions.DataType.Type, Set[Type[sqlglot.expressions.Expression]]] = {<Type.BIGINT: 'BIGINT'>: {<class 'sqlglot.expressions.ApproxDistinct'>, <class 'sqlglot.expressions.ArraySize'>, <class 'sqlglot.expressions.Length'>}, <Type.BOOLEAN: 'BOOLEAN'>: {<class 'sqlglot.expressions.In'>, <class 'sqlglot.expressions.RegexpLike'>, <class 'sqlglot.expressions.Between'>, <class 'sqlglot.expressions.Boolean'>}, <Type.DATE: 'DATE'>: {<class 'sqlglot.expressions.DateFromParts'>, <class 'sqlglot.expressions.StrToDate'>, <class 'sqlglot.expressions.TimeStrToDate'>, <class 'sqlglot.expressions.CurrentDate'>, <class 'sqlglot.expressions.TsOrDsToDate'>, <class 'sqlglot.expressions.Date'>, <class 'sqlglot.expressions.DiToDate'>, <class 'sqlglot.expressions.DateStrToDate'>}, <Type.DATETIME: 'DATETIME'>: {<class 'sqlglot.expressions.Datetime'>, <class 'sqlglot.expressions.DatetimeSub'>, <class 'sqlglot.expressions.DatetimeAdd'>, <class 'sqlglot.expressions.CurrentDatetime'>}, <Type.DOUBLE: 'DOUBLE'>: {<class 'sqlglot.expressions.Quantile'>, <class 'sqlglot.expressions.Exp'>, <class 'sqlglot.expressions.Avg'>, <class 'sqlglot.expressions.Round'>, <class 'sqlglot.expressions.ToDouble'>, <class 'sqlglot.expressions.VariancePop'>, <class 'sqlglot.expressions.Log'>, <class 'sqlglot.expressions.Variance'>, <class 'sqlglot.expressions.Ln'>, <class 'sqlglot.expressions.Pow'>, <class 'sqlglot.expressions.StddevSamp'>, <class 'sqlglot.expressions.StddevPop'>, <class 'sqlglot.expressions.SafeDivide'>, <class 'sqlglot.expressions.Stddev'>, <class 'sqlglot.expressions.Sqrt'>, <class 'sqlglot.expressions.ApproxQuantile'>}, <Type.INT: 'INT'>: {<class 'sqlglot.expressions.Ceil'>, <class 'sqlglot.expressions.StrPosition'>, <class 'sqlglot.expressions.DateDiff'>, <class 'sqlglot.expressions.TimeDiff'>, <class 'sqlglot.expressions.DateToDi'>, <class 'sqlglot.expressions.Levenshtein'>, <class 'sqlglot.expressions.TimestampDiff'>, <class 'sqlglot.expressions.DatetimeDiff'>, <class 'sqlglot.expressions.Sign'>, <class 'sqlglot.expressions.TsOrDiToDi'>}, <Type.JSON: 'JSON'>: {<class 'sqlglot.expressions.ParseJSON'>}, <Type.TIME: 'TIME'>: {<class 'sqlglot.expressions.TimeAdd'>, <class 'sqlglot.expressions.Time'>, <class 'sqlglot.expressions.CurrentTime'>, <class 'sqlglot.expressions.TimeSub'>}, <Type.TINYINT: 'TINYINT'>: {<class 'sqlglot.expressions.Quarter'>, <class 'sqlglot.expressions.Month'>, <class 'sqlglot.expressions.Day'>, <class 'sqlglot.expressions.Year'>, <class 'sqlglot.expressions.Week'>}, <Type.VARCHAR: 'VARCHAR'>: {<class 'sqlglot.expressions.String'>, <class 'sqlglot.expressions.Trim'>, <class 'sqlglot.expressions.UnixToTimeStr'>, <class 'sqlglot.expressions.Initcap'>, <class 'sqlglot.expressions.TimeToStr'>, <class 'sqlglot.expressions.UnixToStr'>, <class 'sqlglot.expressions.TimeToTimeStr'>, <class 'sqlglot.expressions.TsOrDsToDateStr'>, <class 'sqlglot.expressions.Upper'>, <class 'sqlglot.expressions.ArrayConcat'>, <class 'sqlglot.expressions.ConcatWs'>, <class 'sqlglot.expressions.DateToDateStr'>, <class 'sqlglot.expressions.Concat'>, <class 'sqlglot.expressions.Substring'>, <class 'sqlglot.expressions.Lower'>, <class 'sqlglot.expressions.GroupConcat'>}, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<class 'sqlglot.expressions.CurrentTimestamp'>, <class 'sqlglot.expressions.TimeStrToTime'>, <class 'sqlglot.expressions.UnixToTime'>, <class 'sqlglot.expressions.TimestampSub'>, <class 'sqlglot.expressions.TimestampAdd'>, <class 'sqlglot.expressions.StrToTime'>}}
ANNOTATORS: Dict[Type[~E], Callable[[sqlglot.optimizer.annotate_types.TypeAnnotator, ~E], ~E]] = {<class 'sqlglot.expressions.Alias'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseNot'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Neg'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Not'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Paren'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.PivotAlias'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Unary'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Add'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.And'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayContains'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayContainsAll'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayOverlaps'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Binary'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseAnd'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseLeftShift'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseOr'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseRightShift'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseXor'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Collate'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Connector'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Corr'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.CovarPop'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.CovarSamp'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.DPipe'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Distance'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Div'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Dot'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.EQ'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Escape'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.GT'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.GTE'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Glob'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ILike'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ILikeAny'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.IntDiv'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Is'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONArrayContains'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBContains'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBExtract'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBExtractScalar'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONExtract'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONExtractScalar'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Kwarg'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LT'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LTE'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Like'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LikeAny'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Mod'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Mul'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NEQ'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NullSafeEQ'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NullSafeNEQ'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Operator'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Or'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Overlaps'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Pow'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.PropertyEQ'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.RegexpILike'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.RegexpLike'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SimilarTo'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Slice'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Sub'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Xor'>: <function Dialect.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ApproxDistinct'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ArraySize'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Length'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.In'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Between'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Boolean'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateFromParts'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StrToDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeStrToDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Date'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DiToDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateStrToDate'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Datetime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeSub'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeAdd'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentDatetime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Quantile'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Exp'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Avg'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Round'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ToDouble'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.VariancePop'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Log'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Variance'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Ln'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.StddevSamp'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StddevPop'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SafeDivide'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Stddev'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Sqrt'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ApproxQuantile'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Ceil'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.StrPosition'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateDiff'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeDiff'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateToDi'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Levenshtein'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampDiff'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeDiff'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Sign'>: <function BigQuery.<lambda>>, <class 'sqlglot.expressions.TsOrDiToDi'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ParseJSON'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeAdd'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Time'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentTime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeSub'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentTimestamp'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeStrToTime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToTime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampSub'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampAdd'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StrToTime'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Quarter'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Month'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Day'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Year'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Week'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.String'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Trim'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.UnixToTimeStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Initcap'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeToStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeToTimeStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDateStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Upper'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayConcat'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ConcatWs'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateToDateStr'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Concat'>: <function BigQuery.<lambda>>, <class 'sqlglot.expressions.Substring'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Lower'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.GroupConcat'>: <function annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Abs'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Anonymous'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Array'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.ArrayAgg'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Bracket'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Cast'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Case'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Coalesce'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Count'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.DateAdd'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.DateSub'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.DateTrunc'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Distinct'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Explode'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Extract'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Filter'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.GenerateDateArray'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.GenerateTimestampArray'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Greatest'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.If'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Interval'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Least'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Literal'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Map'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Max'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Min'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Null'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Nullif'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Struct'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Sum'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Timestamp'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.ToMap'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.TryCast'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Unnest'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.VarMap'>: <function Dialect.<lambda>>, <class 'sqlglot.expressions.Floor'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Left'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Right'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Pad'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.RegexpExtract'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.RegexpReplace'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Repeat'>: <function BigQuery.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Split'>: <function BigQuery.<lambda>>}
def normalize_identifier(self, expression: ~E) -> ~E: View Source

    441    def normalize_identifier(self, expression: E) -> E:
    442        if (
    443            isinstance(expression, exp.Identifier)
    444            and self.normalization_strategy is not NormalizationStrategy.CASE_SENSITIVE
    445        ):
    446            parent = expression.parent
    447            while isinstance(parent, exp.Dot):
    448                parent = parent.parent
    449
    450            # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive
    451            # by default. The following check uses a heuristic to detect tables based on whether
    452            # they are qualified. This should generally be correct, because tables in BigQuery
    453            # must be qualified with at least a dataset, unless @@dataset_id is set.
    454            case_sensitive = (
    455                isinstance(parent, exp.UserDefinedFunction)
    456                or (
    457                    isinstance(parent, exp.Table)
    458                    and parent.db
    459                    and (parent.meta.get("quoted_table") or not parent.meta.get("maybe_column"))
    460                )
    461                or expression.meta.get("is_table")
    462            )
    463            if not case_sensitive:
    464                expression.set("this", expression.this.lower())
    465
    466        return expression

Transforms an identifier in a way that resembles how it'd be resolved by this dialect.

For example, an identifier like `FoO` would be resolved as `foo` in Postgres, because it lowercases all unquoted identifiers. On the other hand, Snowflake uppercases them, so it would resolve it as `FOO`. If it was quoted, it'd need to be treated as case-sensitive, and so any normalization would be prohibited in order to avoid "breaking" the identifier.

There are also dialects like Spark, which are case-insensitive even when quotes are present, and dialects like MySQL, whose resolution rules match those employed by the underlying operating system, for example they may always be case-sensitive in Linux.

Finally, the normalization behavior of some engines can even be controlled through flags, like in Redshift's case, where users can explicitly set enable_case_sensitive_identifier.

SQLGlot aims to understand and handle all of these different behaviors gracefully, so that it can analyze queries in the optimizer and successfully capture their semantics.

SUPPORTS_COLUMN_JOIN_MARKS = False

Whether the old-style outer join (+) syntax is supported.

UNESCAPED_SEQUENCES: Dict[str, str] = {'\\a': '\x07', '\\b': '\x08', '\\f': '\x0c', '\\n': '\n', '\\r': '\r', '\\t': '\t', '\\v': '\x0b', '\\\\': '\\'}

Mapping of an escaped sequence (`\n`) to its unescaped version (`` ).

tokenizer_class = <class 'BigQuery.Tokenizer'>
jsonpath_tokenizer_class = <class 'sqlglot.tokens.JSONPathTokenizer'>
parser_class = <class 'BigQuery.Parser'>
generator_class = <class 'BigQuery.Generator'>
TIME_TRIE: Dict = {'%': {'D': {0: True}, 'E': {'6': {'S': {0: True}}}, 'e': {0: True}}}
FORMAT_TRIE: Dict = {'D': {'D': {0: True}}, 'M': {'M': {0: True}, 'O': {'N': {0: True, 'T': {'H': {0: True}}}}, 'I': {0: True}}, 'Y': {'Y': {'Y': {'Y': {0: True}}, 0: True}}, 'H': {'H': {0: True, '1': {'2': {0: True}}, '2': {'4': {0: True}}}}, 'S': {'S': {0: True, 'S': {'S': {'S': {0: True}}}}}, 'T': {'Z': {'H': {0: True}}}}
INVERSE_TIME_MAPPING: Dict[str, str] = {'%m/%d/%y': '%D', '%S.%f': '%E6S', '%-d': '%e'}
INVERSE_TIME_TRIE: Dict = {'%': {'m': {'/': {'%': {'d': {'/': {'%': {'y': {0: True}}}}}}}, 'S': {'.': {'%': {'f': {0: True}}}}, '-': {'d': {0: True}}}}
INVERSE_FORMAT_MAPPING: Dict[str, str] = {'%d': 'DD', '%m': 'MM', '%b': 'MON', '%B': 'MONTH', '%Y': 'YYYY', '%y': 'YY', '%I': 'HH12', '%H': 'HH24', '%M': 'MI', '%S': 'SS', '%f': 'SSSSS', '%z': 'TZH'}
INVERSE_FORMAT_TRIE: Dict = {'%': {'d': {0: True}, 'm': {0: True}, 'b': {0: True}, 'B': {0: True}, 'Y': {0: True}, 'y': {0: True}, 'I': {0: True}, 'H': {0: True}, 'M': {0: True}, 'S': {0: True}, 'f': {0: True}, 'z': {0: True}}}
INVERSE_CREATABLE_KIND_MAPPING: dict[str, str] = {}
ESCAPED_SEQUENCES: Dict[str, str] = {'\x07': '\\a', '\x08': '\\b', '\x0c': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\x0b': '\\v', '\\': '\\\\'}
QUOTE_START = "'"
QUOTE_END = "'"
IDENTIFIER_START = '`'
IDENTIFIER_END = '`'
BIT_START: Optional[str] = None
BIT_END: Optional[str] = None
HEX_START: Optional[str] = '0x'
HEX_END: Optional[str] = ''
BYTE_START: Optional[str] = "b'"
BYTE_END: Optional[str] = "'"
UNICODE_START: Optional[str] = None
UNICODE_END: Optional[str] = None
class BigQuery.Tokenizer(sqlglot.tokens.Tokenizer): View Source

    468    class Tokenizer(tokens.Tokenizer):
    469        QUOTES = ["'", '"', '"""', "'''"]
    470        COMMENTS = ["--", "#", ("/*", "*/")]
    471        IDENTIFIERS = ["`"]
    472        STRING_ESCAPES = ["\\"]
    473
    474        HEX_STRINGS = [("0x", ""), ("0X", "")]
    475
    476        BYTE_STRINGS = [
    477            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
    478        ]
    479
    480        RAW_STRINGS = [
    481            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
    482        ]
    483
    484        KEYWORDS = {
    485            **tokens.Tokenizer.KEYWORDS,
    486            "ANY TYPE": TokenType.VARIANT,
    487            "BEGIN": TokenType.COMMAND,
    488            "BEGIN TRANSACTION": TokenType.BEGIN,
    489            "BYTEINT": TokenType.INT,
    490            "BYTES": TokenType.BINARY,
    491            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
    492            "DATETIME": TokenType.TIMESTAMP,
    493            "DECLARE": TokenType.COMMAND,
    494            "ELSEIF": TokenType.COMMAND,
    495            "EXCEPTION": TokenType.COMMAND,
    496            "EXPORT": TokenType.EXPORT,
    497            "FLOAT64": TokenType.DOUBLE,
    498            "FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
    499            "MODEL": TokenType.MODEL,
    500            "NOT DETERMINISTIC": TokenType.VOLATILE,
    501            "RECORD": TokenType.STRUCT,
    502            "TIMESTAMP": TokenType.TIMESTAMPTZ,
    503        }
    504        KEYWORDS.pop("DIV")
    505        KEYWORDS.pop("VALUES")
    506        KEYWORDS.pop("/*+")

QUOTES = ["'", '"', '"""', "'''"]
COMMENTS = ['--', '#', ('/*', '*/')]
IDENTIFIERS = ['`']
STRING_ESCAPES = ['\\']
HEX_STRINGS = [('0x', ''), ('0X', '')]
BYTE_STRINGS = [("b'", "'"), ("B'", "'"), ('b"', '"'), ('B"', '"'), ('b"""', '"""'), ('B"""', '"""'), ("b'''", "'''"), ("B'''", "'''")]
RAW_STRINGS = [("r'", "'"), ("R'", "'"), ('r"', '"'), ('R"', '"'), ('r"""', '"""'), ('R"""', '"""'), ("r'''", "'''"), ("R'''", "'''")]
KEYWORDS = {'{%': <TokenType.BLOCK_START: 'BLOCK_START'>, '{%+': <TokenType.BLOCK_START: 'BLOCK_START'>, '{%-': <TokenType.BLOCK_START: 'BLOCK_START'>, '%}': <TokenType.BLOCK_END: 'BLOCK_END'>, '+%}': <TokenType.BLOCK_END: 'BLOCK_END'>, '-%}': <TokenType.BLOCK_END: 'BLOCK_END'>, '{{+': <TokenType.BLOCK_START: 'BLOCK_START'>, '{{-': <TokenType.BLOCK_START: 'BLOCK_START'>, '+}}': <TokenType.BLOCK_END: 'BLOCK_END'>, '-}}': <TokenType.BLOCK_END: 'BLOCK_END'>, '==': <TokenType.EQ: 'EQ'>, '::': <TokenType.DCOLON: 'DCOLON'>, '||': <TokenType.DPIPE: 'DPIPE'>, '>=': <TokenType.GTE: 'GTE'>, '<=': <TokenType.LTE: 'LTE'>, '<>': <TokenType.NEQ: 'NEQ'>, '!=': <TokenType.NEQ: 'NEQ'>, ':=': <TokenType.COLON_EQ: 'COLON_EQ'>, '<=>': <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>, '->': <TokenType.ARROW: 'ARROW'>, '->>': <TokenType.DARROW: 'DARROW'>, '=>': <TokenType.FARROW: 'FARROW'>, '#>': <TokenType.HASH_ARROW: 'HASH_ARROW'>, '#>>': <TokenType.DHASH_ARROW: 'DHASH_ARROW'>, '<->': <TokenType.LR_ARROW: 'LR_ARROW'>, '&&': <TokenType.DAMP: 'DAMP'>, '??': <TokenType.DQMARK: 'DQMARK'>, '~~~': <TokenType.GLOB: 'GLOB'>, '~~': <TokenType.LIKE: 'LIKE'>, '~~*': <TokenType.ILIKE: 'ILIKE'>, '~*': <TokenType.IRLIKE: 'IRLIKE'>, 'ALL': <TokenType.ALL: 'ALL'>, 'ALWAYS': <TokenType.ALWAYS: 'ALWAYS'>, 'AND': <TokenType.AND: 'AND'>, 'ANTI': <TokenType.ANTI: 'ANTI'>, 'ANY': <TokenType.ANY: 'ANY'>, 'ASC': <TokenType.ASC: 'ASC'>, 'AS': <TokenType.ALIAS: 'ALIAS'>, 'ASOF': <TokenType.ASOF: 'ASOF'>, 'AUTOINCREMENT': <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, 'AUTO_INCREMENT': <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, 'BEGIN': <TokenType.COMMAND: 'COMMAND'>, 'BETWEEN': <TokenType.BETWEEN: 'BETWEEN'>, 'CACHE': <TokenType.CACHE: 'CACHE'>, 'UNCACHE': <TokenType.UNCACHE: 'UNCACHE'>, 'CASE': <TokenType.CASE: 'CASE'>, 'CHARACTER SET': <TokenType.CHARACTER_SET: 'CHARACTER_SET'>, 'CLUSTER BY': <TokenType.CLUSTER_BY: 'CLUSTER_BY'>, 'COLLATE': <TokenType.COLLATE: 'COLLATE'>, 'COLUMN': <TokenType.COLUMN: 'COLUMN'>, 'COMMIT': <TokenType.COMMIT: 'COMMIT'>, 'CONNECT BY': <TokenType.CONNECT_BY: 'CONNECT_BY'>, 'CONSTRAINT': <TokenType.CONSTRAINT: 'CONSTRAINT'>, 'COPY': <TokenType.COPY: 'COPY'>, 'CREATE': <TokenType.CREATE: 'CREATE'>, 'CROSS': <TokenType.CROSS: 'CROSS'>, 'CUBE': <TokenType.CUBE: 'CUBE'>, 'CURRENT_DATE': <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, 'CURRENT_SCHEMA': <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, 'CURRENT_TIME': <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, 'CURRENT_TIMESTAMP': <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, 'CURRENT_USER': <TokenType.CURRENT_USER: 'CURRENT_USER'>, 'DATABASE': <TokenType.DATABASE: 'DATABASE'>, 'DEFAULT': <TokenType.DEFAULT: 'DEFAULT'>, 'DELETE': <TokenType.DELETE: 'DELETE'>, 'DESC': <TokenType.DESC: 'DESC'>, 'DESCRIBE': <TokenType.DESCRIBE: 'DESCRIBE'>, 'DISTINCT': <TokenType.DISTINCT: 'DISTINCT'>, 'DISTRIBUTE BY': <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>, 'DROP': <TokenType.DROP: 'DROP'>, 'ELSE': <TokenType.ELSE: 'ELSE'>, 'END': <TokenType.END: 'END'>, 'ENUM': <TokenType.ENUM: 'ENUM'>, 'ESCAPE': <TokenType.ESCAPE: 'ESCAPE'>, 'EXCEPT': <TokenType.EXCEPT: 'EXCEPT'>, 'EXECUTE': <TokenType.EXECUTE: 'EXECUTE'>, 'EXISTS': <TokenType.EXISTS: 'EXISTS'>, 'FALSE': <TokenType.FALSE: 'FALSE'>, 'FETCH': <TokenType.FETCH: 'FETCH'>, 'FILTER': <TokenType.FILTER: 'FILTER'>, 'FIRST': <TokenType.FIRST: 'FIRST'>, 'FULL': <TokenType.FULL: 'FULL'>, 'FUNCTION': <TokenType.FUNCTION: 'FUNCTION'>, 'FOR': <TokenType.FOR: 'FOR'>, 'FOREIGN KEY': <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, 'FORMAT': <TokenType.FORMAT: 'FORMAT'>, 'FROM': <TokenType.FROM: 'FROM'>, 'GEOGRAPHY': <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, 'GEOMETRY': <TokenType.GEOMETRY: 'GEOMETRY'>, 'GLOB': <TokenType.GLOB: 'GLOB'>, 'GROUP BY': <TokenType.GROUP_BY: 'GROUP_BY'>, 'GROUPING SETS': <TokenType.GROUPING_SETS: 'GROUPING_SETS'>, 'HAVING': <TokenType.HAVING: 'HAVING'>, 'ILIKE': <TokenType.ILIKE: 'ILIKE'>, 'IN': <TokenType.IN: 'IN'>, 'INDEX': <TokenType.INDEX: 'INDEX'>, 'INET': <TokenType.INET: 'INET'>, 'INNER': <TokenType.INNER: 'INNER'>, 'INSERT': <TokenType.INSERT: 'INSERT'>, 'INTERVAL': <TokenType.INTERVAL: 'INTERVAL'>, 'INTERSECT': <TokenType.INTERSECT: 'INTERSECT'>, 'INTO': <TokenType.INTO: 'INTO'>, 'IS': <TokenType.IS: 'IS'>, 'ISNULL': <TokenType.ISNULL: 'ISNULL'>, 'JOIN': <TokenType.JOIN: 'JOIN'>, 'KEEP': <TokenType.KEEP: 'KEEP'>, 'KILL': <TokenType.KILL: 'KILL'>, 'LATERAL': <TokenType.LATERAL: 'LATERAL'>, 'LEFT': <TokenType.LEFT: 'LEFT'>, 'LIKE': <TokenType.LIKE: 'LIKE'>, 'LIMIT': <TokenType.LIMIT: 'LIMIT'>, 'LOAD': <TokenType.LOAD: 'LOAD'>, 'LOCK': <TokenType.LOCK: 'LOCK'>, 'MERGE': <TokenType.MERGE: 'MERGE'>, 'NAMESPACE': <TokenType.NAMESPACE: 'NAMESPACE'>, 'NATURAL': <TokenType.NATURAL: 'NATURAL'>, 'NEXT': <TokenType.NEXT: 'NEXT'>, 'NOT': <TokenType.NOT: 'NOT'>, 'NOTNULL': <TokenType.NOTNULL: 'NOTNULL'>, 'NULL': <TokenType.NULL: 'NULL'>, 'OBJECT': <TokenType.OBJECT: 'OBJECT'>, 'OFFSET': <TokenType.OFFSET: 'OFFSET'>, 'ON': <TokenType.ON: 'ON'>, 'OR': <TokenType.OR: 'OR'>, 'XOR': <TokenType.XOR: 'XOR'>, 'ORDER BY': <TokenType.ORDER_BY: 'ORDER_BY'>, 'ORDINALITY': <TokenType.ORDINALITY: 'ORDINALITY'>, 'OUTER': <TokenType.OUTER: 'OUTER'>, 'OVER': <TokenType.OVER: 'OVER'>, 'OVERLAPS': <TokenType.OVERLAPS: 'OVERLAPS'>, 'OVERWRITE': <TokenType.OVERWRITE: 'OVERWRITE'>, 'PARTITION': <TokenType.PARTITION: 'PARTITION'>, 'PARTITION BY': <TokenType.PARTITION_BY: 'PARTITION_BY'>, 'PARTITIONED BY': <TokenType.PARTITION_BY: 'PARTITION_BY'>, 'PARTITIONED_BY': <TokenType.PARTITION_BY: 'PARTITION_BY'>, 'PERCENT': <TokenType.PERCENT: 'PERCENT'>, 'PIVOT': <TokenType.PIVOT: 'PIVOT'>, 'PRAGMA': <TokenType.PRAGMA: 'PRAGMA'>, 'PRIMARY KEY': <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, 'PROCEDURE': <TokenType.PROCEDURE: 'PROCEDURE'>, 'QUALIFY': <TokenType.QUALIFY: 'QUALIFY'>, 'RANGE': <TokenType.RANGE: 'RANGE'>, 'RECURSIVE': <TokenType.RECURSIVE: 'RECURSIVE'>, 'REGEXP': <TokenType.RLIKE: 'RLIKE'>, 'RENAME': <TokenType.RENAME: 'RENAME'>, 'REPLACE': <TokenType.REPLACE: 'REPLACE'>, 'RETURNING': <TokenType.RETURNING: 'RETURNING'>, 'REFERENCES': <TokenType.REFERENCES: 'REFERENCES'>, 'RIGHT': <TokenType.RIGHT: 'RIGHT'>, 'RLIKE': <TokenType.RLIKE: 'RLIKE'>, 'ROLLBACK': <TokenType.ROLLBACK: 'ROLLBACK'>, 'ROLLUP': <TokenType.ROLLUP: 'ROLLUP'>, 'ROW': <TokenType.ROW: 'ROW'>, 'ROWS': <TokenType.ROWS: 'ROWS'>, 'SCHEMA': <TokenType.SCHEMA: 'SCHEMA'>, 'SELECT': <TokenType.SELECT: 'SELECT'>, 'SEMI': <TokenType.SEMI: 'SEMI'>, 'SET': <TokenType.SET: 'SET'>, 'SETTINGS': <TokenType.SETTINGS: 'SETTINGS'>, 'SHOW': <TokenType.SHOW: 'SHOW'>, 'SIMILAR TO': <TokenType.SIMILAR_TO: 'SIMILAR_TO'>, 'SOME': <TokenType.SOME: 'SOME'>, 'SORT BY': <TokenType.SORT_BY: 'SORT_BY'>, 'START WITH': <TokenType.START_WITH: 'START_WITH'>, 'STRAIGHT_JOIN': <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, 'TABLE': <TokenType.TABLE: 'TABLE'>, 'TABLESAMPLE': <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>, 'TEMP': <TokenType.TEMPORARY: 'TEMPORARY'>, 'TEMPORARY': <TokenType.TEMPORARY: 'TEMPORARY'>, 'THEN': <TokenType.THEN: 'THEN'>, 'TRUE': <TokenType.TRUE: 'TRUE'>, 'TRUNCATE': <TokenType.TRUNCATE: 'TRUNCATE'>, 'UNION': <TokenType.UNION: 'UNION'>, 'UNKNOWN': <TokenType.UNKNOWN: 'UNKNOWN'>, 'UNNEST': <TokenType.UNNEST: 'UNNEST'>, 'UNPIVOT': <TokenType.UNPIVOT: 'UNPIVOT'>, 'UPDATE': <TokenType.UPDATE: 'UPDATE'>, 'USE': <TokenType.USE: 'USE'>, 'USING': <TokenType.USING: 'USING'>, 'UUID': <TokenType.UUID: 'UUID'>, 'VIEW': <TokenType.VIEW: 'VIEW'>, 'VOLATILE': <TokenType.VOLATILE: 'VOLATILE'>, 'WHEN': <TokenType.WHEN: 'WHEN'>, 'WHERE': <TokenType.WHERE: 'WHERE'>, 'WINDOW': <TokenType.WINDOW: 'WINDOW'>, 'WITH': <TokenType.WITH: 'WITH'>, 'APPLY': <TokenType.APPLY: 'APPLY'>, 'ARRAY': <TokenType.ARRAY: 'ARRAY'>, 'BIT': <TokenType.BIT: 'BIT'>, 'BOOL': <TokenType.BOOLEAN: 'BOOLEAN'>, 'BOOLEAN': <TokenType.BOOLEAN: 'BOOLEAN'>, 'BYTE': <TokenType.TINYINT: 'TINYINT'>, 'MEDIUMINT': <TokenType.MEDIUMINT: 'MEDIUMINT'>, 'INT1': <TokenType.TINYINT: 'TINYINT'>, 'TINYINT': <TokenType.TINYINT: 'TINYINT'>, 'INT16': <TokenType.SMALLINT: 'SMALLINT'>, 'SHORT': <TokenType.SMALLINT: 'SMALLINT'>, 'SMALLINT': <TokenType.SMALLINT: 'SMALLINT'>, 'HUGEINT': <TokenType.INT128: 'INT128'>, 'UHUGEINT': <TokenType.UINT128: 'UINT128'>, 'INT2': <TokenType.SMALLINT: 'SMALLINT'>, 'INTEGER': <TokenType.INT: 'INT'>, 'INT': <TokenType.INT: 'INT'>, 'INT4': <TokenType.INT: 'INT'>, 'INT32': <TokenType.INT: 'INT'>, 'INT64': <TokenType.BIGINT: 'BIGINT'>, 'INT128': <TokenType.INT128: 'INT128'>, 'INT256': <TokenType.INT256: 'INT256'>, 'LONG': <TokenType.BIGINT: 'BIGINT'>, 'BIGINT': <TokenType.BIGINT: 'BIGINT'>, 'INT8': <TokenType.TINYINT: 'TINYINT'>, 'UINT': <TokenType.UINT: 'UINT'>, 'UINT128': <TokenType.UINT128: 'UINT128'>, 'UINT256': <TokenType.UINT256: 'UINT256'>, 'DEC': <TokenType.DECIMAL: 'DECIMAL'>, 'DECIMAL': <TokenType.DECIMAL: 'DECIMAL'>, 'DECIMAL32': <TokenType.DECIMAL32: 'DECIMAL32'>, 'DECIMAL64': <TokenType.DECIMAL64: 'DECIMAL64'>, 'DECIMAL128': <TokenType.DECIMAL128: 'DECIMAL128'>, 'DECIMAL256': <TokenType.DECIMAL256: 'DECIMAL256'>, 'BIGDECIMAL': <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, 'BIGNUMERIC': <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, 'LIST': <TokenType.LIST: 'LIST'>, 'MAP': <TokenType.MAP: 'MAP'>, 'NULLABLE': <TokenType.NULLABLE: 'NULLABLE'>, 'NUMBER': <TokenType.DECIMAL: 'DECIMAL'>, 'NUMERIC': <TokenType.DECIMAL: 'DECIMAL'>, 'FIXED': <TokenType.DECIMAL: 'DECIMAL'>, 'REAL': <TokenType.FLOAT: 'FLOAT'>, 'FLOAT': <TokenType.FLOAT: 'FLOAT'>, 'FLOAT4': <TokenType.FLOAT: 'FLOAT'>, 'FLOAT8': <TokenType.DOUBLE: 'DOUBLE'>, 'DOUBLE': <TokenType.DOUBLE: 'DOUBLE'>, 'DOUBLE PRECISION': <TokenType.DOUBLE: 'DOUBLE'>, 'JSON': <TokenType.JSON: 'JSON'>, 'JSONB': <TokenType.JSONB: 'JSONB'>, 'CHAR': <TokenType.CHAR: 'CHAR'>, 'CHARACTER': <TokenType.CHAR: 'CHAR'>, 'NCHAR': <TokenType.NCHAR: 'NCHAR'>, 'VARCHAR': <TokenType.VARCHAR: 'VARCHAR'>, 'VARCHAR2': <TokenType.VARCHAR: 'VARCHAR'>, 'NVARCHAR': <TokenType.NVARCHAR: 'NVARCHAR'>, 'NVARCHAR2': <TokenType.NVARCHAR: 'NVARCHAR'>, 'BPCHAR': <TokenType.BPCHAR: 'BPCHAR'>, 'STR': <TokenType.TEXT: 'TEXT'>, 'STRING': <TokenType.TEXT: 'TEXT'>, 'TEXT': <TokenType.TEXT: 'TEXT'>, 'LONGTEXT': <TokenType.LONGTEXT: 'LONGTEXT'>, 'MEDIUMTEXT': <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, 'TINYTEXT': <TokenType.TINYTEXT: 'TINYTEXT'>, 'CLOB': <TokenType.TEXT: 'TEXT'>, 'LONGVARCHAR': <TokenType.TEXT: 'TEXT'>, 'BINARY': <TokenType.BINARY: 'BINARY'>, 'BLOB': <TokenType.VARBINARY: 'VARBINARY'>, 'LONGBLOB': <TokenType.LONGBLOB: 'LONGBLOB'>, 'MEDIUMBLOB': <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, 'TINYBLOB': <TokenType.TINYBLOB: 'TINYBLOB'>, 'BYTEA': <TokenType.VARBINARY: 'VARBINARY'>, 'VARBINARY': <TokenType.VARBINARY: 'VARBINARY'>, 'TIME': <TokenType.TIME: 'TIME'>, 'TIMETZ': <TokenType.TIMETZ: 'TIMETZ'>, 'TIMESTAMP': <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, 'TIMESTAMPTZ': <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, 'TIMESTAMPLTZ': <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, 'TIMESTAMP_LTZ': <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, 'TIMESTAMPNTZ': <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, 'TIMESTAMP_NTZ': <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, 'DATE': <TokenType.DATE: 'DATE'>, 'DATETIME': <TokenType.TIMESTAMP: 'TIMESTAMP'>, 'INT4RANGE': <TokenType.INT4RANGE: 'INT4RANGE'>, 'INT4MULTIRANGE': <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, 'INT8RANGE': <TokenType.INT8RANGE: 'INT8RANGE'>, 'INT8MULTIRANGE': <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, 'NUMRANGE': <TokenType.NUMRANGE: 'NUMRANGE'>, 'NUMMULTIRANGE': <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, 'TSRANGE': <TokenType.TSRANGE: 'TSRANGE'>, 'TSMULTIRANGE': <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, 'TSTZRANGE': <TokenType.TSTZRANGE: 'TSTZRANGE'>, 'TSTZMULTIRANGE': <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, 'DATERANGE': <TokenType.DATERANGE: 'DATERANGE'>, 'DATEMULTIRANGE': <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, 'UNIQUE': <TokenType.UNIQUE: 'UNIQUE'>, 'VECTOR': <TokenType.VECTOR: 'VECTOR'>, 'STRUCT': <TokenType.STRUCT: 'STRUCT'>, 'SEQUENCE': <TokenType.SEQUENCE: 'SEQUENCE'>, 'VARIANT': <TokenType.VARIANT: 'VARIANT'>, 'ALTER': <TokenType.ALTER: 'ALTER'>, 'ANALYZE': <TokenType.ANALYZE: 'ANALYZE'>, 'CALL': <TokenType.COMMAND: 'COMMAND'>, 'COMMENT': <TokenType.COMMENT: 'COMMENT'>, 'EXPLAIN': <TokenType.COMMAND: 'COMMAND'>, 'GRANT': <TokenType.GRANT: 'GRANT'>, 'OPTIMIZE': <TokenType.COMMAND: 'COMMAND'>, 'PREPARE': <TokenType.COMMAND: 'COMMAND'>, 'VACUUM': <TokenType.COMMAND: 'COMMAND'>, 'USER-DEFINED': <TokenType.USERDEFINED: 'USERDEFINED'>, 'FOR VERSION': <TokenType.VERSION_SNAPSHOT: 'VERSION_SNAPSHOT'>, 'FOR TIMESTAMP': <TokenType.TIMESTAMP_SNAPSHOT: 'TIMESTAMP_SNAPSHOT'>, 'ANY TYPE': <TokenType.VARIANT: 'VARIANT'>, 'BEGIN TRANSACTION': <TokenType.BEGIN: 'BEGIN'>, 'BYTEINT': <TokenType.INT: 'INT'>, 'BYTES': <TokenType.BINARY: 'BINARY'>, 'CURRENT_DATETIME': <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, 'DECLARE': <TokenType.COMMAND: 'COMMAND'>, 'ELSEIF': <TokenType.COMMAND: 'COMMAND'>, 'EXCEPTION': <TokenType.COMMAND: 'COMMAND'>, 'EXPORT': <TokenType.EXPORT: 'EXPORT'>, 'FLOAT64': <TokenType.DOUBLE: 'DOUBLE'>, 'FOR SYSTEM_TIME': <TokenType.TIMESTAMP_SNAPSHOT: 'TIMESTAMP_SNAPSHOT'>, 'MODEL': <TokenType.MODEL: 'MODEL'>, 'NOT DETERMINISTIC': <TokenType.VOLATILE: 'VOLATILE'>, 'RECORD': <TokenType.STRUCT: 'STRUCT'>}

##### Inherited Members

sqlglot.tokens.Tokenizer
  Tokenizer
  SINGLE_TOKENS
  BIT_STRINGS
  HEREDOC_STRINGS
  UNICODE_STRINGS
  VAR_SINGLE_TOKENS
  IDENTIFIER_ESCAPES
  HEREDOC_TAG_IS_IDENTIFIER
  HEREDOC_STRING_ALTERNATIVE
  STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
  NESTED_COMMENTS
  HINT_START
  TOKENS_PRECEDING_HINT
  WHITE_SPACE
  COMMANDS
  COMMAND_PREFIX_TOKENS
  NUMERIC_LITERALS
  dialect
  use_rs_tokenizer
  reset
  tokenize
  tokenize_rs
  size
  sql
  tokens

class BigQuery.Parser(sqlglot.parser.Parser): View Source

    508    class Parser(parser.Parser):
    509        PREFIXED_PIVOT_COLUMNS = True
    510        LOG_DEFAULTS_TO_LN = True
    511        SUPPORTS_IMPLICIT_UNNEST = True
    512
    513        FUNCTIONS = {
    514            **parser.Parser.FUNCTIONS,
    515            "CONTAINS_SUBSTR": _build_contains_substring,
    516            "DATE": _build_date,
    517            "DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
    518            "DATE_SUB": build_date_delta_with_interval(exp.DateSub),
    519            "DATE_TRUNC": lambda args: exp.DateTrunc(
    520                unit=exp.Literal.string(str(seq_get(args, 1))),
    521                this=seq_get(args, 0),
    522                zone=seq_get(args, 2),
    523            ),
    524            "DATETIME": _build_datetime,
    525            "DATETIME_ADD": build_date_delta_with_interval(exp.DatetimeAdd),
    526            "DATETIME_SUB": build_date_delta_with_interval(exp.DatetimeSub),
    527            "DIV": binary_from_function(exp.IntDiv),
    528            "EDIT_DISTANCE": _build_levenshtein,
    529            "FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
    530            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
    531            "JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
    532            "JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
    533            "JSON_QUERY": parser.build_extract_json_with_path(exp.JSONExtract),
    534            "JSON_QUERY_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
    535            "JSON_VALUE": _build_extract_json_with_default_path(exp.JSONExtractScalar),
    536            "JSON_VALUE_ARRAY": _build_extract_json_with_default_path(exp.JSONValueArray),
    537            "LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
    538            "MD5": exp.MD5Digest.from_arg_list,
    539            "TO_HEX": _build_to_hex,
    540            "PARSE_DATE": lambda args: build_formatted_time(exp.StrToDate, "bigquery")(
    541                [seq_get(args, 1), seq_get(args, 0)]
    542            ),
    543            "PARSE_TIMESTAMP": _build_parse_timestamp,
    544            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
    545            "REGEXP_EXTRACT": _build_regexp_extract(exp.RegexpExtract),
    546            "REGEXP_SUBSTR": _build_regexp_extract(exp.RegexpExtract),
    547            "REGEXP_EXTRACT_ALL": _build_regexp_extract(
    548                exp.RegexpExtractAll, default_group=exp.Literal.number(0)
    549            ),
    550            "SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
    551            "SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
    552            "SPLIT": lambda args: exp.Split(
    553                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
    554                this=seq_get(args, 0),
    555                expression=seq_get(args, 1) or exp.Literal.string(","),
    556            ),
    557            "STRPOS": exp.StrPosition.from_arg_list,
    558            "TIME": _build_time,
    559            "TIME_ADD": build_date_delta_with_interval(exp.TimeAdd),
    560            "TIME_SUB": build_date_delta_with_interval(exp.TimeSub),
    561            "TIMESTAMP": _build_timestamp,
    562            "TIMESTAMP_ADD": build_date_delta_with_interval(exp.TimestampAdd),
    563            "TIMESTAMP_SUB": build_date_delta_with_interval(exp.TimestampSub),
    564            "TIMESTAMP_MICROS": lambda args: exp.UnixToTime(
    565                this=seq_get(args, 0), scale=exp.UnixToTime.MICROS
    566            ),
    567            "TIMESTAMP_MILLIS": lambda args: exp.UnixToTime(
    568                this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS
    569            ),
    570            "TIMESTAMP_SECONDS": lambda args: exp.UnixToTime(this=seq_get(args, 0)),
    571            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
    572            "FORMAT_DATETIME": _build_format_time(exp.TsOrDsToDatetime),
    573            "FORMAT_TIMESTAMP": _build_format_time(exp.TsOrDsToTimestamp),
    574        }
    575
    576        FUNCTION_PARSERS = {
    577            **parser.Parser.FUNCTION_PARSERS,
    578            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
    579            "MAKE_INTERVAL": lambda self: self._parse_make_interval(),
    580            "FEATURES_AT_TIME": lambda self: self._parse_features_at_time(),
    581        }
    582        FUNCTION_PARSERS.pop("TRIM")
    583
    584        NO_PAREN_FUNCTIONS = {
    585            **parser.Parser.NO_PAREN_FUNCTIONS,
    586            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
    587        }
    588
    589        NESTED_TYPE_TOKENS = {
    590            *parser.Parser.NESTED_TYPE_TOKENS,
    591            TokenType.TABLE,
    592        }
    593
    594        PROPERTY_PARSERS = {
    595            **parser.Parser.PROPERTY_PARSERS,
    596            "NOT DETERMINISTIC": lambda self: self.expression(
    597                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
    598            ),
    599            "OPTIONS": lambda self: self._parse_with_property(),
    600        }
    601
    602        CONSTRAINT_PARSERS = {
    603            **parser.Parser.CONSTRAINT_PARSERS,
    604            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
    605        }
    606
    607        RANGE_PARSERS = parser.Parser.RANGE_PARSERS.copy()
    608        RANGE_PARSERS.pop(TokenType.OVERLAPS)
    609
    610        NULL_TOKENS = {TokenType.NULL, TokenType.UNKNOWN}
    611
    612        DASHED_TABLE_PART_FOLLOW_TOKENS = {TokenType.DOT, TokenType.L_PAREN, TokenType.R_PAREN}
    613
    614        STATEMENT_PARSERS = {
    615            **parser.Parser.STATEMENT_PARSERS,
    616            TokenType.ELSE: lambda self: self._parse_as_command(self._prev),
    617            TokenType.END: lambda self: self._parse_as_command(self._prev),
    618            TokenType.FOR: lambda self: self._parse_for_in(),
    619            TokenType.EXPORT: lambda self: self._parse_export_data(),
    620        }
    621
    622        BRACKET_OFFSETS = {
    623            "OFFSET": (0, False),
    624            "ORDINAL": (1, False),
    625            "SAFE_OFFSET": (0, True),
    626            "SAFE_ORDINAL": (1, True),
    627        }
    628
    629        def _parse_for_in(self) -> exp.ForIn:
    630            this = self._parse_range()
    631            self._match_text_seq("DO")
    632            return self.expression(exp.ForIn, this=this, expression=self._parse_statement())
    633
    634        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    635            this = super()._parse_table_part(schema=schema) or self._parse_number()
    636
    637            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
    638            if isinstance(this, exp.Identifier):
    639                table_name = this.name
    640                while self._match(TokenType.DASH, advance=False) and self._next:
    641                    start = self._curr
    642                    while self._is_connected() and not self._match_set(
    643                        self.DASHED_TABLE_PART_FOLLOW_TOKENS, advance=False
    644                    ):
    645                        self._advance()
    646
    647                    table_name += self._find_sql(start, self._prev)
    648
    649                this = exp.Identifier(
    650                    this=table_name, quoted=this.args.get("quoted")
    651                ).update_positions(this)
    652            elif isinstance(this, exp.Literal):
    653                table_name = this.name
    654
    655                if self._is_connected() and self._parse_var(any_token=True):
    656                    table_name += self._prev.text
    657
    658                this = exp.Identifier(this=table_name, quoted=True).update_positions(this)
    659
    660            return this
    661
    662        def _parse_table_parts(
    663            self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    664        ) -> exp.Table:
    665            table = super()._parse_table_parts(
    666                schema=schema, is_db_reference=is_db_reference, wildcard=True
    667            )
    668
    669            # proj-1.db.tbl -- `1.` is tokenized as a float so we need to unravel it here
    670            if not table.catalog:
    671                if table.db:
    672                    previous_db = table.args["db"]
    673                    parts = table.db.split(".")
    674                    if len(parts) == 2 and not table.args["db"].quoted:
    675                        table.set(
    676                            "catalog", exp.Identifier(this=parts[0]).update_positions(previous_db)
    677                        )
    678                        table.set("db", exp.Identifier(this=parts[1]).update_positions(previous_db))
    679                else:
    680                    previous_this = table.this
    681                    parts = table.name.split(".")
    682                    if len(parts) == 2 and not table.this.quoted:
    683                        table.set(
    684                            "db", exp.Identifier(this=parts[0]).update_positions(previous_this)
    685                        )
    686                        table.set(
    687                            "this", exp.Identifier(this=parts[1]).update_positions(previous_this)
    688                        )
    689
    690            if isinstance(table.this, exp.Identifier) and any("." in p.name for p in table.parts):
    691                alias = table.this
    692                catalog, db, this, *rest = (
    693                    exp.to_identifier(p, quoted=True)
    694                    for p in split_num_words(".".join(p.name for p in table.parts), ".", 3)
    695                )
    696
    697                for part in (catalog, db, this):
    698                    if part:
    699                        part.update_positions(table.this)
    700
    701                if rest and this:
    702                    this = exp.Dot.build([this, *rest])  # type: ignore
    703
    704                table = exp.Table(
    705                    this=this, db=db, catalog=catalog, pivots=table.args.get("pivots")
    706                )
    707                table.meta["quoted_table"] = True
    708            else:
    709                alias = None
    710
    711            # The `INFORMATION_SCHEMA` views in BigQuery need to be qualified by a region or
    712            # dataset, so if the project identifier is omitted we need to fix the ast so that
    713            # the `INFORMATION_SCHEMA.X` bit is represented as a single (quoted) Identifier.
    714            # Otherwise, we wouldn't correctly qualify a `Table` node that references these
    715            # views, because it would seem like the "catalog" part is set, when it'd actually
    716            # be the region/dataset. Merging the two identifiers into a single one is done to
    717            # avoid producing a 4-part Table reference, which would cause issues in the schema
    718            # module, when there are 3-part table names mixed with information schema views.
    719            #
    720            # See: https://cloud.google.com/bigquery/docs/information-schema-intro#syntax
    721            table_parts = table.parts
    722            if len(table_parts) > 1 and table_parts[-2].name.upper() == "INFORMATION_SCHEMA":
    723                # We need to alias the table here to avoid breaking existing qualified columns.
    724                # This is expected to be safe, because if there's an actual alias coming up in
    725                # the token stream, it will overwrite this one. If there isn't one, we are only
    726                # exposing the name that can be used to reference the view explicitly (a no-op).
    727                exp.alias_(
    728                    table,
    729                    t.cast(exp.Identifier, alias or table_parts[-1]),
    730                    table=True,
    731                    copy=False,
    732                )
    733
    734                info_schema_view = f"{table_parts[-2].name}.{table_parts[-1].name}"
    735                new_this = exp.Identifier(this=info_schema_view, quoted=True).update_positions(
    736                    line=table_parts[-2].meta.get("line"),
    737                    col=table_parts[-1].meta.get("col"),
    738                    start=table_parts[-2].meta.get("start"),
    739                    end=table_parts[-1].meta.get("end"),
    740                )
    741                table.set("this", new_this)
    742                table.set("db", seq_get(table_parts, -3))
    743                table.set("catalog", seq_get(table_parts, -4))
    744
    745            return table
    746
    747        def _parse_column(self) -> t.Optional[exp.Expression]:
    748            column = super()._parse_column()
    749            if isinstance(column, exp.Column):
    750                parts = column.parts
    751                if any("." in p.name for p in parts):
    752                    catalog, db, table, this, *rest = (
    753                        exp.to_identifier(p, quoted=True)
    754                        for p in split_num_words(".".join(p.name for p in parts), ".", 4)
    755                    )
    756
    757                    if rest and this:
    758                        this = exp.Dot.build([this, *rest])  # type: ignore
    759
    760                    column = exp.Column(this=this, table=table, db=db, catalog=catalog)
    761                    column.meta["quoted_column"] = True
    762
    763            return column
    764
    765        @t.overload
    766        def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    767
    768        @t.overload
    769        def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    770
    771        def _parse_json_object(self, agg=False):
    772            json_object = super()._parse_json_object()
    773            array_kv_pair = seq_get(json_object.expressions, 0)
    774
    775            # Converts BQ's "signature 2" of JSON_OBJECT into SQLGlot's canonical representation
    776            # https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_object_signature2
    777            if (
    778                array_kv_pair
    779                and isinstance(array_kv_pair.this, exp.Array)
    780                and isinstance(array_kv_pair.expression, exp.Array)
    781            ):
    782                keys = array_kv_pair.this.expressions
    783                values = array_kv_pair.expression.expressions
    784
    785                json_object.set(
    786                    "expressions",
    787                    [exp.JSONKeyValue(this=k, expression=v) for k, v in zip(keys, values)],
    788                )
    789
    790            return json_object
    791
    792        def _parse_bracket(
    793            self, this: t.Optional[exp.Expression] = None
    794        ) -> t.Optional[exp.Expression]:
    795            bracket = super()._parse_bracket(this)
    796
    797            if this is bracket:
    798                return bracket
    799
    800            if isinstance(bracket, exp.Bracket):
    801                for expression in bracket.expressions:
    802                    name = expression.name.upper()
    803
    804                    if name not in self.BRACKET_OFFSETS:
    805                        break
    806
    807                    offset, safe = self.BRACKET_OFFSETS[name]
    808                    bracket.set("offset", offset)
    809                    bracket.set("safe", safe)
    810                    expression.replace(expression.expressions[0])
    811
    812            return bracket
    813
    814        def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    815            unnest = super()._parse_unnest(with_alias=with_alias)
    816
    817            if not unnest:
    818                return None
    819
    820            unnest_expr = seq_get(unnest.expressions, 0)
    821            if unnest_expr:
    822                from sqlglot.optimizer.annotate_types import annotate_types
    823
    824                unnest_expr = annotate_types(unnest_expr, dialect=self.dialect)
    825
    826                # Unnesting a nested array (i.e array of structs) explodes the top-level struct fields,
    827                # in contrast to other dialects such as DuckDB which flattens only the array by default
    828                if unnest_expr.is_type(exp.DataType.Type.ARRAY) and any(
    829                    array_elem.is_type(exp.DataType.Type.STRUCT)
    830                    for array_elem in unnest_expr._type.expressions
    831                ):
    832                    unnest.set("explode_array", True)
    833
    834            return unnest
    835
    836        def _parse_make_interval(self) -> exp.MakeInterval:
    837            expr = exp.MakeInterval()
    838
    839            for arg_key in expr.arg_types:
    840                value = self._parse_lambda()
    841
    842                if not value:
    843                    break
    844
    845                # Non-named arguments are filled sequentially, (optionally) followed by named arguments
    846                # that can appear in any order e.g MAKE_INTERVAL(1, minute => 5, day => 2)
    847                if isinstance(value, exp.Kwarg):
    848                    arg_key = value.this.name
    849
    850                expr.set(arg_key, value)
    851
    852                self._match(TokenType.COMMA)
    853
    854            return expr
    855
    856        def _parse_features_at_time(self) -> exp.FeaturesAtTime:
    857            expr = self.expression(
    858                exp.FeaturesAtTime,
    859                this=(self._match(TokenType.TABLE) and self._parse_table())
    860                or self._parse_select(nested=True),
    861            )
    862
    863            while self._match(TokenType.COMMA):
    864                arg = self._parse_lambda()
    865
    866                # Get the LHS of the Kwarg and set the arg to that value, e.g
    867                # "num_rows => 1" sets the expr's `num_rows` arg
    868                if arg:
    869                    expr.set(arg.this.name, arg)
    870
    871            return expr
    872
    873        def _parse_export_data(self) -> exp.Export:
    874            self._match_text_seq("DATA")
    875
    876            return self.expression(
    877                exp.Export,
    878                connection=self._match_text_seq("WITH", "CONNECTION") and self._parse_table_parts(),
    879                options=self._parse_properties(),
    880                this=self._match_text_seq("AS") and self._parse_select(),
    881            )

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

PREFIXED_PIVOT_COLUMNS = True
LOG_DEFAULTS_TO_LN = True
SUPPORTS_IMPLICIT_UNNEST = True
FUNCTIONS = {'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'>>, 'AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.And'>>, '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'>>, 'APPLY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Apply'>>, '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': <function Parser.<lambda>>, 'ARRAY_AGG': <function Parser.<lambda>>, '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': <function Parser.<lambda>>, 'CHAR': <function Parser.<lambda>>, 'COALESCE': <function build_coalesce>, 'IFNULL': <function build_coalesce>, 'NVL': <function build_coalesce>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Columns'>>, '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'>>, 'CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Contains'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, '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_SCHEMA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentSchema'>>, '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': <function _build_date>, 'DATE_ADD': <function build_date_delta_with_interval.<locals>._builder>, 'DATE_BIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateBin'>>, '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': <function build_date_delta_with_interval.<locals>._builder>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <function BigQuery.Parser.<lambda>>, 'DATETIME': <function _build_datetime>, 'DATETIME_ADD': <function build_date_delta_with_interval.<locals>._builder>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <function build_date_delta_with_interval.<locals>._builder>, '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'>>, 'DAYOFWEEK_ISO': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'ISODOW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, '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'>>, 'EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exists'>>, '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'>>, 'EXPLODING_GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodingGenerateSeries'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FEATURES_AT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FeaturesAtTime'>>, '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'>>, 'FROM_ISO8601_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromISO8601Timestamp'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <function Parser.<lambda>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GENERATE_TIMESTAMP_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateTimestampArray'>>, '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'>>, 'INLINE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Inline'>>, 'INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Int64'>>, 'IS_ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsAscii'>>, '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_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExists'>>, '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'>>, 'J_S_O_N_B_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBObjectAgg'>>, 'J_S_O_N_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONCast'>>, 'J_S_O_N_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_ARRAY': <function _build_extract_json_with_default_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function _build_extract_json_with_default_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'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, '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': <function BigQuery.Parser.<lambda>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHAR_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHARACTER_LENGTH': <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.MD5Digest'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAKE_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MakeInterval'>>, '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'>>, 'MEDIAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Median'>>, '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'>>, 'NORMALIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Normalize'>>, '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'>>, 'OBJECT_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ObjectInsert'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Or'>>, 'OVERLAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Overlay'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, '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': <function _build_regexp_extract.<locals>._builder>, 'REGEXP_EXTRACT_ALL': <function _build_regexp_extract.<locals>._builder>, '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': <function BigQuery.Parser.<lambda>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, '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'>>, 'STDEV': <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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, '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'>>, 'SUBSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <function _build_time>, 'TIME_ADD': <function build_date_delta_with_interval.<locals>._builder>, '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': <function build_date_delta_with_interval.<locals>._builder>, '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': <function _build_timestamp>, 'TIMESTAMP_ADD': <function build_date_delta_with_interval.<locals>._builder>, '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': <function build_date_delta_with_interval.<locals>._builder>, '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_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, '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_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDatetime'>>, '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'>>, 'UNICODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unicode'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_SECONDS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixSeconds'>>, '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'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GEN_RANDOM_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GENERATE_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'UUID_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, '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'>>, 'XMLELEMENT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLElement'>>, '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'>>, 'ARRAYAGG': <function Parser.<lambda>>, '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>>, 'LPAD': <function Parser.<lambda>>, 'LEFTPAD': <function Parser.<lambda>>, 'LTRIM': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'RIGHTPAD': <function Parser.<lambda>>, 'RPAD': <function Parser.<lambda>>, 'RTRIM': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'STRPOS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'CHARINDEX': <function Parser.<lambda>>, 'INSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'LOCATE': <function Parser.<lambda>>, 'TO_HEX': <function _build_to_hex>, 'CONTAINS_SUBSTR': <function _build_contains_substring>, 'DIV': <function binary_from_function.<locals>.<lambda>>, 'EDIT_DISTANCE': <function _build_levenshtein>, 'FORMAT_DATE': <function _build_format_time.<locals>._builder>, 'GENERATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'JSON_QUERY': <function build_extract_json_with_path.<locals>._builder>, 'JSON_QUERY_ARRAY': <function _build_extract_json_with_default_path.<locals>._builder>, 'JSON_VALUE': <function _build_extract_json_with_default_path.<locals>._builder>, 'JSON_VALUE_ARRAY': <function _build_extract_json_with_default_path.<locals>._builder>, 'PARSE_DATE': <function BigQuery.Parser.<lambda>>, 'PARSE_TIMESTAMP': <function _build_parse_timestamp>, 'REGEXP_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_SUBSTR': <function _build_regexp_extract.<locals>._builder>, 'SHA256': <function BigQuery.Parser.<lambda>>, 'SHA512': <function BigQuery.Parser.<lambda>>, 'TIMESTAMP_MICROS': <function BigQuery.Parser.<lambda>>, 'TIMESTAMP_MILLIS': <function BigQuery.Parser.<lambda>>, 'TIMESTAMP_SECONDS': <function BigQuery.Parser.<lambda>>, 'TO_JSON_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'FORMAT_DATETIME': <function _build_format_time.<locals>._builder>, 'FORMAT_TIMESTAMP': <function _build_format_time.<locals>._builder>}
FUNCTION_PARSERS = {'ARG_MAX': <function Parser.<dictcomp>.<lambda>>, 'ARGMAX': <function Parser.<dictcomp>.<lambda>>, 'MAX_BY': <function Parser.<dictcomp>.<lambda>>, 'ARG_MIN': <function Parser.<dictcomp>.<lambda>>, 'ARGMIN': <function Parser.<dictcomp>.<lambda>>, 'MIN_BY': <function Parser.<dictcomp>.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <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>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <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>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <function Parser.<lambda>>, 'ARRAY': <function BigQuery.Parser.<lambda>>, 'MAKE_INTERVAL': <function BigQuery.Parser.<lambda>>, 'FEATURES_AT_TIME': <function BigQuery.Parser.<lambda>>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDatetime'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
NESTED_TYPE_TOKENS = {<TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.UNION: 'UNION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>}
PROPERTY_PARSERS = {'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>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <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>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <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>>, 'NOT DETERMINISTIC': <function BigQuery.Parser.<lambda>>, 'OPTIONS': <function BigQuery.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>>, 'WATERMARK': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>, 'BUCKET': <function Parser.<lambda>>, 'TRUNCATE': <function Parser.<lambda>>, 'OPTIONS': <function BigQuery.Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <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.LT_AT: 'LT_AT'>: <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>>}
NULL_TOKENS = {<TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.NULL: 'NULL'>}
DASHED_TABLE_PART_FOLLOW_TOKENS = {<TokenType.DOT: 'DOT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.L_PAREN: 'L_PAREN'>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.ANALYZE: 'ANALYZE'>: <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.GRANT: 'GRANT'>: <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.UNPIVOT: 'UNPIVOT'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>, <TokenType.ELSE: 'ELSE'>: <function BigQuery.Parser.<lambda>>, <TokenType.END: 'END'>: <function BigQuery.Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function BigQuery.Parser.<lambda>>, <TokenType.EXPORT: 'EXPORT'>: <function BigQuery.Parser.<lambda>>}
BRACKET_OFFSETS = {'OFFSET': (0, False), 'ORDINAL': (1, False), 'SAFE_OFFSET': (0, True), 'SAFE_ORDINAL': (1, True)}
ID_VAR_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
TABLE_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ANTI: 'ANTI'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}

##### Inherited Members

sqlglot.parser.Parser
  Parser
  STRUCT_TYPE_TOKENS
  ENUM_TYPE_TOKENS
  AGGREGATE_TYPE_TOKENS
  TYPE_TOKENS
  SIGNED_TO_UNSIGNED_TYPE_TOKEN
  SUBQUERY_PREDICATES
  RESERVED_TOKENS
  DB_CREATABLES
  CREATABLES
  ALTERABLES
  ALIAS_TOKENS
  COLON_PLACEHOLDER_TOKENS
  ARRAY_CONSTRUCTORS
  COMMENT_TABLE_ALIAS_TOKENS
  UPDATE_ALIAS_TOKENS
  TRIM_TYPES
  FUNC_TOKENS
  CONJUNCTION
  ASSIGNMENT
  DISJUNCTION
  EQUALITY
  COMPARISON
  BITWISE
  TERM
  FACTOR
  EXPONENT
  TIMES
  TIMESTAMPS
  SET_OPERATIONS
  JOIN_METHODS
  JOIN_SIDES
  JOIN_KINDS
  JOIN_HINTS
  LAMBDAS
  COLUMN_OPERATORS
  EXPRESSION_PARSERS
  UNARY_PARSERS
  STRING_PARSERS
  NUMERIC_PARSERS
  PRIMARY_PARSERS
  PLACEHOLDER_PARSERS
  ALTER_PARSERS
  ALTER_ALTER_PARSERS
  SCHEMA_UNNAMED_CONSTRAINTS
  NO_PAREN_FUNCTION_PARSERS
  INVALID_FUNC_NAME_TOKENS
  FUNCTIONS_WITH_ALIASED_ARGS
  KEY_VALUE_DEFINITIONS
  QUERY_MODIFIER_PARSERS
  SET_PARSERS
  SHOW_PARSERS
  TYPE_LITERAL_PARSERS
  TYPE_CONVERTERS
  DDL_SELECT_TOKENS
  PRE_VOLATILE_TOKENS
  TRANSACTION_KIND
  TRANSACTION_CHARACTERISTICS
  CONFLICT_ACTIONS
  CREATE_SEQUENCE
  ISOLATED_LOADING_OPTIONS
  USABLES
  CAST_ACTIONS
  SCHEMA_BINDING_OPTIONS
  PROCEDURE_OPTIONS
  EXECUTE_AS_OPTIONS
  KEY_CONSTRAINT_OPTIONS
  INSERT_ALTERNATIVES
  CLONE_KEYWORDS
  HISTORICAL_DATA_PREFIX
  HISTORICAL_DATA_KIND
  OPCLASS_FOLLOW_KEYWORDS
  OPTYPE_FOLLOW_TOKENS
  TABLE_INDEX_HINT_TOKENS
  VIEW_ATTRIBUTES
  WINDOW_ALIAS_TOKENS
  WINDOW_BEFORE_PAREN_TOKENS
  WINDOW_SIDES
  JSON_KEY_VALUE_SEPARATOR_TOKENS
  FETCH_TOKENS
  ADD_CONSTRAINT_TOKENS
  DISTINCT_TOKENS
  UNNEST_OFFSET_ALIAS_TOKENS
  SELECT_START_TOKENS
  COPY_INTO_VARLEN_OPTIONS
  IS_JSON_PREDICATE_KIND
  ODBC_DATETIME_LITERALS
  ON_CONDITION_TOKENS
  PRIVILEGE_FOLLOW_TOKENS
  DESCRIBE_STYLES
  ANALYZE_STYLES
  ANALYZE_EXPRESSION_PARSERS
  PARTITION_KEYWORDS
  AMBIGUOUS_ALIAS_TOKENS
  OPERATION_MODIFIERS
  RECURSIVE_CTE_SEARCH_KIND
  MODIFIABLES
  STRICT_CAST
  IDENTIFY_PIVOT_STRINGS
  ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN
  TABLESAMPLE_CSV
  DEFAULT_SAMPLING_METHOD
  SET_REQUIRES_ASSIGNMENT_DELIMITER
  TRIM_PATTERN_FIRST
  STRING_ALIASES
  MODIFIERS_ATTACHED_TO_SET_OP
  SET_OP_MODIFIERS
  NO_PAREN_IF_COMMANDS
  JSON_ARROWS_REQUIRE_JSON_TYPE
  COLON_IS_VARIANT_EXTRACT
  VALUES_FOLLOWED_BY_PAREN
  INTERVAL_SPANS
  SUPPORTS_PARTITION_SELECTION
  WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
  OPTIONAL_ALIAS_TOKEN_CTE
  error_level
  error_message_context
  max_errors
  dialect
  reset
  parse
  parse_into
  check_errors
  raise_error
  expression
  validate_expression
  parse_set_operation
  errors
  sql

class BigQuery.Generator(sqlglot.generator.Generator): View Source

     883    class Generator(generator.Generator):
     884        INTERVAL_ALLOWS_PLURAL_FORM = False
     885        JOIN_HINTS = False
     886        QUERY_HINTS = False
     887        TABLE_HINTS = False
     888        LIMIT_FETCH = "LIMIT"
     889        RENAME_TABLE_WITH_DB = False
     890        NVL2_SUPPORTED = False
     891        UNNEST_WITH_ORDINALITY = False
     892        COLLATE_IS_FUNC = True
     893        LIMIT_ONLY_LITERALS = True
     894        SUPPORTS_TABLE_ALIAS_COLUMNS = False
     895        UNPIVOT_ALIASES_ARE_IDENTIFIERS = False
     896        JSON_KEY_VALUE_PAIR_SEP = ","
     897        NULL_ORDERING_SUPPORTED = False
     898        IGNORE_NULLS_IN_FUNC = True
     899        JSON_PATH_SINGLE_QUOTE_ESCAPE = True
     900        CAN_IMPLEMENT_ARRAY_ANY = True
     901        SUPPORTS_TO_NUMBER = False
     902        NAMED_PLACEHOLDER_TOKEN = "@"
     903        HEX_FUNC = "TO_HEX"
     904        WITH_PROPERTIES_PREFIX = "OPTIONS"
     905        SUPPORTS_EXPLODING_PROJECTIONS = False
     906        EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
     907        SUPPORTS_UNIX_SECONDS = True
     908
     909        TRANSFORMS = {
     910            **generator.Generator.TRANSFORMS,
     911            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
     912            exp.ArgMax: arg_max_or_min_no_count("MAX_BY"),
     913            exp.ArgMin: arg_max_or_min_no_count("MIN_BY"),
     914            exp.Array: inline_array_unless_query,
     915            exp.ArrayContains: _array_contains_sql,
     916            exp.ArrayFilter: filter_array_using_unnest,
     917            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
     918            exp.CollateProperty: lambda self, e: (
     919                f"DEFAULT COLLATE {self.sql(e, 'this')}"
     920                if e.args.get("default")
     921                else f"COLLATE {self.sql(e, 'this')}"
     922            ),
     923            exp.Commit: lambda *_: "COMMIT TRANSACTION",
     924            exp.CountIf: rename_func("COUNTIF"),
     925            exp.Create: _create_sql,
     926            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
     927            exp.DateAdd: date_add_interval_sql("DATE", "ADD"),
     928            exp.DateDiff: lambda self, e: self.func(
     929                "DATE_DIFF", e.this, e.expression, unit_to_var(e)
     930            ),
     931            exp.DateFromParts: rename_func("DATE"),
     932            exp.DateStrToDate: datestrtodate_sql,
     933            exp.DateSub: date_add_interval_sql("DATE", "SUB"),
     934            exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
     935            exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
     936            exp.DateTrunc: lambda self, e: self.func(
     937                "DATE_TRUNC", e.this, e.text("unit"), e.args.get("zone")
     938            ),
     939            exp.FromTimeZone: lambda self, e: self.func(
     940                "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
     941            ),
     942            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
     943            exp.GroupConcat: lambda self, e: groupconcat_sql(
     944                self, e, func_name="STRING_AGG", within_group=False
     945            ),
     946            exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))),
     947            exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
     948            exp.If: if_sql(false_value="NULL"),
     949            exp.ILike: no_ilike_sql,
     950            exp.IntDiv: rename_func("DIV"),
     951            exp.Int64: rename_func("INT64"),
     952            exp.JSONExtract: _json_extract_sql,
     953            exp.JSONExtractArray: _json_extract_sql,
     954            exp.JSONExtractScalar: _json_extract_sql,
     955            exp.JSONFormat: rename_func("TO_JSON_STRING"),
     956            exp.Levenshtein: _levenshtein_sql,
     957            exp.Max: max_or_greatest,
     958            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
     959            exp.MD5Digest: rename_func("MD5"),
     960            exp.Min: min_or_least,
     961            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
     962            exp.RegexpExtract: lambda self, e: self.func(
     963                "REGEXP_EXTRACT",
     964                e.this,
     965                e.expression,
     966                e.args.get("position"),
     967                e.args.get("occurrence"),
     968            ),
     969            exp.RegexpExtractAll: lambda self, e: self.func(
     970                "REGEXP_EXTRACT_ALL", e.this, e.expression
     971            ),
     972            exp.RegexpReplace: regexp_replace_sql,
     973            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
     974            exp.ReturnsProperty: _returnsproperty_sql,
     975            exp.Rollback: lambda *_: "ROLLBACK TRANSACTION",
     976            exp.Select: transforms.preprocess(
     977                [
     978                    transforms.explode_projection_to_unnest(),
     979                    transforms.unqualify_unnest,
     980                    transforms.eliminate_distinct_on,
     981                    _alias_ordered_group,
     982                    transforms.eliminate_semi_and_anti_joins,
     983                ]
     984            ),
     985            exp.SHA: rename_func("SHA1"),
     986            exp.SHA2: sha256_sql,
     987            exp.StabilityProperty: lambda self, e: (
     988                "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
     989            ),
     990            exp.String: rename_func("STRING"),
     991            exp.StrPosition: lambda self, e: (
     992                strposition_sql(
     993                    self, e, func_name="INSTR", supports_position=True, supports_occurrence=True
     994                )
     995            ),
     996            exp.StrToDate: _str_to_datetime_sql,
     997            exp.StrToTime: _str_to_datetime_sql,
     998            exp.TimeAdd: date_add_interval_sql("TIME", "ADD"),
     999            exp.TimeFromParts: rename_func("TIME"),
    1000            exp.TimestampFromParts: rename_func("DATETIME"),
    1001            exp.TimeSub: date_add_interval_sql("TIME", "SUB"),
    1002            exp.TimestampAdd: date_add_interval_sql("TIMESTAMP", "ADD"),
    1003            exp.TimestampDiff: rename_func("TIMESTAMP_DIFF"),
    1004            exp.TimestampSub: date_add_interval_sql("TIMESTAMP", "SUB"),
    1005            exp.TimeStrToTime: timestrtotime_sql,
    1006            exp.Transaction: lambda *_: "BEGIN TRANSACTION",
    1007            exp.TsOrDsAdd: _ts_or_ds_add_sql,
    1008            exp.TsOrDsDiff: _ts_or_ds_diff_sql,
    1009            exp.TsOrDsToTime: rename_func("TIME"),
    1010            exp.TsOrDsToDatetime: rename_func("DATETIME"),
    1011            exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"),
    1012            exp.Unhex: rename_func("FROM_HEX"),
    1013            exp.UnixDate: rename_func("UNIX_DATE"),
    1014            exp.UnixToTime: _unix_to_time_sql,
    1015            exp.Uuid: lambda *_: "GENERATE_UUID()",
    1016            exp.Values: _derived_table_values_to_unnest,
    1017            exp.VariancePop: rename_func("VAR_POP"),
    1018            exp.SafeDivide: rename_func("SAFE_DIVIDE"),
    1019        }
    1020
    1021        SUPPORTED_JSON_PATH_PARTS = {
    1022            exp.JSONPathKey,
    1023            exp.JSONPathRoot,
    1024            exp.JSONPathSubscript,
    1025        }
    1026
    1027        TYPE_MAPPING = {
    1028            **generator.Generator.TYPE_MAPPING,
    1029            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
    1030            exp.DataType.Type.BIGINT: "INT64",
    1031            exp.DataType.Type.BINARY: "BYTES",
    1032            exp.DataType.Type.BLOB: "BYTES",
    1033            exp.DataType.Type.BOOLEAN: "BOOL",
    1034            exp.DataType.Type.CHAR: "STRING",
    1035            exp.DataType.Type.DECIMAL: "NUMERIC",
    1036            exp.DataType.Type.DOUBLE: "FLOAT64",
    1037            exp.DataType.Type.FLOAT: "FLOAT64",
    1038            exp.DataType.Type.INT: "INT64",
    1039            exp.DataType.Type.NCHAR: "STRING",
    1040            exp.DataType.Type.NVARCHAR: "STRING",
    1041            exp.DataType.Type.SMALLINT: "INT64",
    1042            exp.DataType.Type.TEXT: "STRING",
    1043            exp.DataType.Type.TIMESTAMP: "DATETIME",
    1044            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
    1045            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
    1046            exp.DataType.Type.TINYINT: "INT64",
    1047            exp.DataType.Type.ROWVERSION: "BYTES",
    1048            exp.DataType.Type.UUID: "STRING",
    1049            exp.DataType.Type.VARBINARY: "BYTES",
    1050            exp.DataType.Type.VARCHAR: "STRING",
    1051            exp.DataType.Type.VARIANT: "ANY TYPE",
    1052        }
    1053
    1054        PROPERTIES_LOCATION = {
    1055            **generator.Generator.PROPERTIES_LOCATION,
    1056            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
    1057            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
    1058        }
    1059
    1060        # WINDOW comes after QUALIFY
    1061        # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#window_clause
    1062        AFTER_HAVING_MODIFIER_TRANSFORMS = {
    1063            "qualify": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["qualify"],
    1064            "windows": generator.Generator.AFTER_HAVING_MODIFIER_TRANSFORMS["windows"],
    1065        }
    1066
    1067        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
    1068        RESERVED_KEYWORDS = {
    1069            "all",
    1070            "and",
    1071            "any",
    1072            "array",
    1073            "as",
    1074            "asc",
    1075            "assert_rows_modified",
    1076            "at",
    1077            "between",
    1078            "by",
    1079            "case",
    1080            "cast",
    1081            "collate",
    1082            "contains",
    1083            "create",
    1084            "cross",
    1085            "cube",
    1086            "current",
    1087            "default",
    1088            "define",
    1089            "desc",
    1090            "distinct",
    1091            "else",
    1092            "end",
    1093            "enum",
    1094            "escape",
    1095            "except",
    1096            "exclude",
    1097            "exists",
    1098            "extract",
    1099            "false",
    1100            "fetch",
    1101            "following",
    1102            "for",
    1103            "from",
    1104            "full",
    1105            "group",
    1106            "grouping",
    1107            "groups",
    1108            "hash",
    1109            "having",
    1110            "if",
    1111            "ignore",
    1112            "in",
    1113            "inner",
    1114            "intersect",
    1115            "interval",
    1116            "into",
    1117            "is",
    1118            "join",
    1119            "lateral",
    1120            "left",
    1121            "like",
    1122            "limit",
    1123            "lookup",
    1124            "merge",
    1125            "natural",
    1126            "new",
    1127            "no",
    1128            "not",
    1129            "null",
    1130            "nulls",
    1131            "of",
    1132            "on",
    1133            "or",
    1134            "order",
    1135            "outer",
    1136            "over",
    1137            "partition",
    1138            "preceding",
    1139            "proto",
    1140            "qualify",
    1141            "range",
    1142            "recursive",
    1143            "respect",
    1144            "right",
    1145            "rollup",
    1146            "rows",
    1147            "select",
    1148            "set",
    1149            "some",
    1150            "struct",
    1151            "tablesample",
    1152            "then",
    1153            "to",
    1154            "treat",
    1155            "true",
    1156            "unbounded",
    1157            "union",
    1158            "unnest",
    1159            "using",
    1160            "when",
    1161            "where",
    1162            "window",
    1163            "with",
    1164            "within",
    1165        }
    1166
    1167        def mod_sql(self, expression: exp.Mod) -> str:
    1168            this = expression.this
    1169            expr = expression.expression
    1170            return self.func(
    1171                "MOD",
    1172                this.unnest() if isinstance(this, exp.Paren) else this,
    1173                expr.unnest() if isinstance(expr, exp.Paren) else expr,
    1174            )
    1175
    1176        def column_parts(self, expression: exp.Column) -> str:
    1177            if expression.meta.get("quoted_column"):
    1178                # If a column reference is of the form `dataset.table`.name, we need
    1179                # to preserve the quoted table path, otherwise the reference breaks
    1180                table_parts = ".".join(p.name for p in expression.parts[:-1])
    1181                table_path = self.sql(exp.Identifier(this=table_parts, quoted=True))
    1182                return f"{table_path}.{self.sql(expression, 'this')}"
    1183
    1184            return super().column_parts(expression)
    1185
    1186        def table_parts(self, expression: exp.Table) -> str:
    1187            # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so
    1188            # we need to make sure the correct quoting is used in each case.
    1189            #
    1190            # For example, if there is a CTE x that clashes with a schema name, then the former will
    1191            # return the table y in that schema, whereas the latter will return the CTE's y column:
    1192            #
    1193            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y`   -> cross join
    1194            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest
    1195            if expression.meta.get("quoted_table"):
    1196                table_parts = ".".join(p.name for p in expression.parts)
    1197                return self.sql(exp.Identifier(this=table_parts, quoted=True))
    1198
    1199            return super().table_parts(expression)
    1200
    1201        def timetostr_sql(self, expression: exp.TimeToStr) -> str:
    1202            this = expression.this
    1203            if isinstance(this, exp.TsOrDsToDatetime):
    1204                func_name = "FORMAT_DATETIME"
    1205            elif isinstance(this, exp.TsOrDsToTimestamp):
    1206                func_name = "FORMAT_TIMESTAMP"
    1207            else:
    1208                func_name = "FORMAT_DATE"
    1209
    1210            time_expr = (
    1211                this
    1212                if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
    1213                else expression
    1214            )
    1215            return self.func(
    1216                func_name, self.format_time(expression), time_expr.this, expression.args.get("zone")
    1217            )
    1218
    1219        def eq_sql(self, expression: exp.EQ) -> str:
    1220            # Operands of = cannot be NULL in BigQuery
    1221            if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null):
    1222                if not isinstance(expression.parent, exp.Update):
    1223                    return "NULL"
    1224
    1225            return self.binary(expression, "=")
    1226
    1227        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
    1228            parent = expression.parent
    1229
    1230            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
    1231            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
    1232            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
    1233                return self.func(
    1234                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
    1235                )
    1236
    1237            return super().attimezone_sql(expression)
    1238
    1239        def trycast_sql(self, expression: exp.TryCast) -> str:
    1240            return self.cast_sql(expression, safe_prefix="SAFE_")
    1241
    1242        def bracket_sql(self, expression: exp.Bracket) -> str:
    1243            this = expression.this
    1244            expressions = expression.expressions
    1245
    1246            if len(expressions) == 1 and this and this.is_type(exp.DataType.Type.STRUCT):
    1247                arg = expressions[0]
    1248                if arg.type is None:
    1249                    from sqlglot.optimizer.annotate_types import annotate_types
    1250
    1251                    arg = annotate_types(arg, dialect=self.dialect)
    1252
    1253                if arg.type and arg.type.this in exp.DataType.TEXT_TYPES:
    1254                    # BQ doesn't support bracket syntax with string values for structs
    1255                    return f"{self.sql(this)}.{arg.name}"
    1256
    1257            expressions_sql = self.expressions(expression, flat=True)
    1258            offset = expression.args.get("offset")
    1259
    1260            if offset == 0:
    1261                expressions_sql = f"OFFSET({expressions_sql})"
    1262            elif offset == 1:
    1263                expressions_sql = f"ORDINAL({expressions_sql})"
    1264            elif offset is not None:
    1265                self.unsupported(f"Unsupported array offset: {offset}")
    1266
    1267            if expression.args.get("safe"):
    1268                expressions_sql = f"SAFE_{expressions_sql}"
    1269
    1270            return f"{self.sql(this)}[{expressions_sql}]"
    1271
    1272        def in_unnest_op(self, expression: exp.Unnest) -> str:
    1273            return self.sql(expression)
    1274
    1275        def version_sql(self, expression: exp.Version) -> str:
    1276            if expression.name == "TIMESTAMP":
    1277                expression.set("this", "SYSTEM_TIME")
    1278            return super().version_sql(expression)
    1279
    1280        def contains_sql(self, expression: exp.Contains) -> str:
    1281            this = expression.this
    1282            expr = expression.expression
    1283
    1284            if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
    1285                this = this.this
    1286                expr = expr.this
    1287
    1288            return self.func("CONTAINS_SUBSTR", this, expr)
    1289
    1290        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
    1291            this = expression.this
    1292
    1293            # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3]
    1294            # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions,
    1295            # because they aren't literals and so the above syntax is invalid BigQuery.
    1296            if isinstance(this, exp.Array):
    1297                elem = seq_get(this.expressions, 0)
    1298                if not (elem and elem.find(exp.Query)):
    1299                    return f"{self.sql(expression, 'to')}{self.sql(this)}"
    1300
    1301            return super().cast_sql(expression, safe_prefix=safe_prefix)

Generator converts a given syntax tree to the corresponding SQL string.

###### Arguments:

- pretty: Whether to format the produced SQL string. Default: False.
- identify: Determines when an identifier should be quoted. Possible values are: False (default): Never quote, except in cases where it's mandatory by the dialect. True or 'always': Always quote. 'safe': Only quote identifiers that are case insensitive.
- normalize: Whether to normalize identifiers to lowercase. Default: False.
- pad: The pad size in a formatted string. For example, this affects the indentation of a projection in a query, relative to its nesting level. Default: 2.
- indent: The indentation size in a formatted string. For example, this affects the indentation of subqueries and filters under a `WHERE` clause. Default: 2.
- normalize_functions: How to normalize function names. Possible values are: "upper" or True (default): Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
- unsupported_level: Determines the generator's behavior when it encounters unsupported expressions. Default ErrorLevel.WARN.
- max_unsupported: Maximum number of unsupported messages to include in a raised UnsupportedError. This is only relevant if unsupported_level is ErrorLevel.RAISE. Default: 3
- leading_comma: Whether the comma is leading or trailing in select expressions. This is only relevant when generating in pretty mode. Default: False
- max_text_width: The max number of characters in a segment before creating new lines in pretty mode. The default is on the smaller end because the length only represents a segment and not the true line length. Default: 80
- comments: Whether to preserve comments in the output SQL code. Default: True

INTERVAL_ALLOWS_PLURAL_FORM = False
JOIN_HINTS = False
QUERY_HINTS = False
TABLE_HINTS = False
LIMIT_FETCH = 'LIMIT'
RENAME_TABLE_WITH_DB = False
NVL2_SUPPORTED = False
UNNEST_WITH_ORDINALITY = False
COLLATE_IS_FUNC = True
LIMIT_ONLY_LITERALS = True
SUPPORTS_TABLE_ALIAS_COLUMNS = False
UNPIVOT_ALIASES_ARE_IDENTIFIERS = False
JSON_KEY_VALUE_PAIR_SEP = ','
NULL_ORDERING_SUPPORTED = False
IGNORE_NULLS_IN_FUNC = True
JSON_PATH_SINGLE_QUOTE_ESCAPE = True
CAN_IMPLEMENT_ARRAY_ANY = True
SUPPORTS_TO_NUMBER = False
NAMED_PLACEHOLDER_TOKEN = '@'
HEX_FUNC = 'TO_HEX'
WITH_PROPERTIES_PREFIX = 'OPTIONS'
SUPPORTS_EXPLODING_PROJECTIONS = False
EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
SUPPORTS_UNIX_SECONDS = True
TRANSFORMS = {<class 'sqlglot.expressions.JSONPathKey'>: <function <lambda>>, <class 'sqlglot.expressions.JSONPathRoot'>: <function <lambda>>, <class 'sqlglot.expressions.JSONPathSubscript'>: <function <lambda>>, <class 'sqlglot.expressions.AllowedValuesProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.AnalyzeColumns'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.AnalyzeWith'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DynamicProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.EmptyProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.EphemeralColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExcludeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Except'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Floor'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Get'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.GlobalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.HeapProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.IcebergProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.InheritsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.InlineLengthColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.InputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Intersect'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.IntervalSpan'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Int64'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ReturnsProperty'>: <function _returnsproperty_sql>, <class 'sqlglot.expressions.SampleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SecureProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SetConfigProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SharingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SqlReadWriteProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.StabilityProperty'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.Stream'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.StreamingTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.StrictProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SwapTable'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Tags'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ToMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TransformModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Union'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.UnloggedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.UsingTemplateProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.UsingData'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.Uuid'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ViewAttributeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithProcedureOptions'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithSchemaBindingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithOperator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ForceProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ApproxDistinct'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ArgMax'>: <function arg_max_or_min_no_count.<locals>._arg_max_or_min_sql>, <class 'sqlglot.expressions.ArgMin'>: <function arg_max_or_min_no_count.<locals>._arg_max_or_min_sql>, <class 'sqlglot.expressions.Array'>: <function inline_array_unless_query>, <class 'sqlglot.expressions.ArrayContains'>: <function _array_contains_sql>, <class 'sqlglot.expressions.ArrayFilter'>: <function filter_array_using_unnest>, <class 'sqlglot.expressions.Cast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.CollateProperty'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.Commit'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.CountIf'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Create'>: <function _create_sql>, <class 'sqlglot.expressions.CTE'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.DateAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.DateDiff'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.DateFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.DateSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.DateTrunc'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.FromTimeZone'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.GenerateSeries'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.GroupConcat'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.Hex'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.HexString'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.If'>: <function if_sql.<locals>._if_sql>, <class 'sqlglot.expressions.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.IntDiv'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.JSONExtract'>: <function _json_extract_sql>, <class 'sqlglot.expressions.JSONExtractArray'>: <function _json_extract_sql>, <class 'sqlglot.expressions.JSONExtractScalar'>: <function _json_extract_sql>, <class 'sqlglot.expressions.JSONFormat'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Levenshtein'>: <function _levenshtein_sql>, <class 'sqlglot.expressions.Max'>: <function max_or_greatest>, <class 'sqlglot.expressions.MD5'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.MD5Digest'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Min'>: <function min_or_least>, <class 'sqlglot.expressions.PartitionedByProperty'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.RegexpExtract'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.RegexpExtractAll'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.RegexpReplace'>: <function regexp_replace_sql>, <class 'sqlglot.expressions.RegexpLike'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Rollback'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.SHA'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.SHA2'>: <function sha256_sql>, <class 'sqlglot.expressions.String'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.StrPosition'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.StrToDate'>: <function _str_to_datetime_sql>, <class 'sqlglot.expressions.StrToTime'>: <function _str_to_datetime_sql>, <class 'sqlglot.expressions.TimeAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.TimeFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampDiff'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.TimeStrToTime'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.Transaction'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TsOrDsAdd'>: <function _ts_or_ds_add_sql>, <class 'sqlglot.expressions.TsOrDsDiff'>: <function _ts_or_ds_diff_sql>, <class 'sqlglot.expressions.TsOrDsToTime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDatetime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToTimestamp'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Unhex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixDate'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToTime'>: <function _unix_to_time_sql>, <class 'sqlglot.expressions.Values'>: <function _derived_table_values_to_unnest>, <class 'sqlglot.expressions.VariancePop'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.SafeDivide'>: <function rename_func.<locals>.<lambda>>}
SUPPORTED_JSON_PATH_PARTS = {<class 'sqlglot.expressions.JSONPathRoot'>, <class 'sqlglot.expressions.JSONPathKey'>, <class 'sqlglot.expressions.JSONPathSubscript'>}
TYPE_MAPPING = {<Type.DATETIME2: 'DATETIME2'>: 'TIMESTAMP', <Type.NCHAR: 'NCHAR'>: 'STRING', <Type.NVARCHAR: 'NVARCHAR'>: 'STRING', <Type.MEDIUMTEXT: 'MEDIUMTEXT'>: 'TEXT', <Type.LONGTEXT: 'LONGTEXT'>: 'TEXT', <Type.TINYTEXT: 'TINYTEXT'>: 'TEXT', <Type.BLOB: 'BLOB'>: 'BYTES', <Type.MEDIUMBLOB: 'MEDIUMBLOB'>: 'BLOB', <Type.LONGBLOB: 'LONGBLOB'>: 'BLOB', <Type.TINYBLOB: 'TINYBLOB'>: 'BLOB', <Type.INET: 'INET'>: 'INET', <Type.ROWVERSION: 'ROWVERSION'>: 'BYTES', <Type.SMALLDATETIME: 'SMALLDATETIME'>: 'TIMESTAMP', <Type.BIGDECIMAL: 'BIGDECIMAL'>: 'BIGNUMERIC', <Type.BIGINT: 'BIGINT'>: 'INT64', <Type.BINARY: 'BINARY'>: 'BYTES', <Type.BOOLEAN: 'BOOLEAN'>: 'BOOL', <Type.CHAR: 'CHAR'>: 'STRING', <Type.DECIMAL: 'DECIMAL'>: 'NUMERIC', <Type.DOUBLE: 'DOUBLE'>: 'FLOAT64', <Type.FLOAT: 'FLOAT'>: 'FLOAT64', <Type.INT: 'INT'>: 'INT64', <Type.SMALLINT: 'SMALLINT'>: 'INT64', <Type.TEXT: 'TEXT'>: 'STRING', <Type.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP', <Type.TINYINT: 'TINYINT'>: 'INT64', <Type.UUID: 'UUID'>: 'STRING', <Type.VARBINARY: 'VARBINARY'>: 'BYTES', <Type.VARCHAR: 'VARCHAR'>: 'STRING', <Type.VARIANT: 'VARIANT'>: 'ANY TYPE'}
PROPERTIES_LOCATION = {<class 'sqlglot.expressions.AllowedValuesProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.AlgorithmProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.AutoIncrementProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.AutoRefreshProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.BackupProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.BlockCompressionProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.CharacterSetProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ChecksumProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.CollateProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.CopyGrantsProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.Cluster'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ClusteredByProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DistributedByProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DuplicateKeyProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DataBlocksizeProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.DataDeletionProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DefinerProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.DictRange'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DictProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DynamicProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.DistKeyProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.DistStyleProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.EmptyProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.EncodeProperty'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.EngineProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ExecuteAsProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ExternalProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.FallbackProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.FileFormatProperty'>: <Location.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.FreespaceProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.GlobalProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.HeapProperty'>: <Location.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.InheritsProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.IcebergProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.IncludeProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.InputModelProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.IsolatedLoadingProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.JournalProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.LanguageProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.LikeProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.LocationProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.LockProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.LockingProperty'>: <Location.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.LogProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.MaterializedProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.MergeBlockRatioProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.NoPrimaryIndexProperty'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.OnProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.OnCommitProperty'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.Order'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.OutputModelProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.PartitionedByProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.PartitionedOfProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.PrimaryKey'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.Property'>: <Location.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.RemoteWithConnectionModelProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ReturnsProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.RowFormatProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.RowFormatDelimitedProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.RowFormatSerdeProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SampleProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SchemaCommentProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SecureProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.SecurityProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SerdeProperties'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.Set'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SettingsProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SetProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.SetConfigProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SharingProperty'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.SequenceProperties'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.SortKeyProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SqlReadWriteProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.SqlSecurityProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.StabilityProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.StorageHandlerProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.StreamingTableProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.StrictProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.Tags'>: <Location.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.TemporaryProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.ToTableProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.TransientProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.TransformModelProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.MergeTreeTTL'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.UnloggedProperty'>: <Location.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.UsingTemplateProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ViewAttributeProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.VolatileProperty'>: <Location.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.WithDataProperty'>: <Location.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.WithJournalTableProperty'>: <Location.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.WithProcedureOptions'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.WithSchemaBindingProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.WithSystemVersioningProperty'>: <Location.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ForceProperty'>: <Location.POST_CREATE: 'POST_CREATE'>}
AFTER_HAVING_MODIFIER_TRANSFORMS = {'qualify': <function Generator.<lambda>>, 'windows': <function Generator.<lambda>>}
RESERVED_KEYWORDS = {'else', 'rollup', 'any', 'in', 'into', 'array', 'over', 'preceding', 'true', 'tablesample', 'recursive', 'for', 'window', 'desc', 'select', 'no', 'at', 'by', 'case', 'merge', 'set', 'default', 'exists', 'if', 'right', 'enum', 'qualify', 'create', 'on', 'order', 'escape', 'contains', 'lateral', 'from', 'groups', 'is', 'as', 'lookup', 'or', 'current', 'rows', 'partition', 'assert_rows_modified', 'some', 'treat', 'then', 'full', 'null', 'having', 'respect', 'proto', 'intersect', 'limit', 'not', 'group', 'unbounded', 'distinct', 'unnest', 'end', 'ignore', 'define', 'cast', 'between', 'extract', 'inner', 'new', 'join', 'asc', 'of', 'where', 'using', 'to', 'struct', 'and', 'false', 'fetch', 'hash', 'all', 'range', 'union', 'natural', 'like', 'left', 'interval', 'with', 'within', 'except', 'nulls', 'outer', 'when', 'cross', 'cube', 'following', 'grouping', 'exclude', 'collate'}
def mod_sql(self, expression: sqlglot.expressions.Mod) -> str: View Source

    1167        def mod_sql(self, expression: exp.Mod) -> str:
    1168            this = expression.this
    1169            expr = expression.expression
    1170            return self.func(
    1171                "MOD",
    1172                this.unnest() if isinstance(this, exp.Paren) else this,
    1173                expr.unnest() if isinstance(expr, exp.Paren) else expr,
    1174            )

def column_parts(self, expression: sqlglot.expressions.Column) -> str: View Source

    1176        def column_parts(self, expression: exp.Column) -> str:
    1177            if expression.meta.get("quoted_column"):
    1178                # If a column reference is of the form `dataset.table`.name, we need
    1179                # to preserve the quoted table path, otherwise the reference breaks
    1180                table_parts = ".".join(p.name for p in expression.parts[:-1])
    1181                table_path = self.sql(exp.Identifier(this=table_parts, quoted=True))
    1182                return f"{table_path}.{self.sql(expression, 'this')}"
    1183
    1184            return super().column_parts(expression)

def table_parts(self, expression: sqlglot.expressions.Table) -> str: View Source

    1186        def table_parts(self, expression: exp.Table) -> str:
    1187            # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so
    1188            # we need to make sure the correct quoting is used in each case.
    1189            #
    1190            # For example, if there is a CTE x that clashes with a schema name, then the former will
    1191            # return the table y in that schema, whereas the latter will return the CTE's y column:
    1192            #
    1193            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y`   -> cross join
    1194            # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest
    1195            if expression.meta.get("quoted_table"):
    1196                table_parts = ".".join(p.name for p in expression.parts)
    1197                return self.sql(exp.Identifier(this=table_parts, quoted=True))
    1198
    1199            return super().table_parts(expression)

def timetostr_sql(self, expression: sqlglot.expressions.TimeToStr) -> str: View Source

    1201        def timetostr_sql(self, expression: exp.TimeToStr) -> str:
    1202            this = expression.this
    1203            if isinstance(this, exp.TsOrDsToDatetime):
    1204                func_name = "FORMAT_DATETIME"
    1205            elif isinstance(this, exp.TsOrDsToTimestamp):
    1206                func_name = "FORMAT_TIMESTAMP"
    1207            else:
    1208                func_name = "FORMAT_DATE"
    1209
    1210            time_expr = (
    1211                this
    1212                if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
    1213                else expression
    1214            )
    1215            return self.func(
    1216                func_name, self.format_time(expression), time_expr.this, expression.args.get("zone")
    1217            )

def eq_sql(self, expression: sqlglot.expressions.EQ) -> str: View Source

    1219        def eq_sql(self, expression: exp.EQ) -> str:
    1220            # Operands of = cannot be NULL in BigQuery
    1221            if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null):
    1222                if not isinstance(expression.parent, exp.Update):
    1223                    return "NULL"
    1224
    1225            return self.binary(expression, "=")

def attimezone_sql(self, expression: sqlglot.expressions.AtTimeZone) -> str: View Source

    1227        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
    1228            parent = expression.parent
    1229
    1230            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
    1231            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
    1232            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
    1233                return self.func(
    1234                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
    1235                )
    1236
    1237            return super().attimezone_sql(expression)

def trycast_sql(self, expression: sqlglot.expressions.TryCast) -> str: View Source

    1239        def trycast_sql(self, expression: exp.TryCast) -> str:
    1240            return self.cast_sql(expression, safe_prefix="SAFE_")

def bracket_sql(self, expression: sqlglot.expressions.Bracket) -> str: View Source

    1242        def bracket_sql(self, expression: exp.Bracket) -> str:
    1243            this = expression.this
    1244            expressions = expression.expressions
    1245
    1246            if len(expressions) == 1 and this and this.is_type(exp.DataType.Type.STRUCT):
    1247                arg = expressions[0]
    1248                if arg.type is None:
    1249                    from sqlglot.optimizer.annotate_types import annotate_types
    1250
    1251                    arg = annotate_types(arg, dialect=self.dialect)
    1252
    1253                if arg.type and arg.type.this in exp.DataType.TEXT_TYPES:
    1254                    # BQ doesn't support bracket syntax with string values for structs
    1255                    return f"{self.sql(this)}.{arg.name}"
    1256
    1257            expressions_sql = self.expressions(expression, flat=True)
    1258            offset = expression.args.get("offset")
    1259
    1260            if offset == 0:
    1261                expressions_sql = f"OFFSET({expressions_sql})"
    1262            elif offset == 1:
    1263                expressions_sql = f"ORDINAL({expressions_sql})"
    1264            elif offset is not None:
    1265                self.unsupported(f"Unsupported array offset: {offset}")
    1266
    1267            if expression.args.get("safe"):
    1268                expressions_sql = f"SAFE_{expressions_sql}"
    1269
    1270            return f"{self.sql(this)}[{expressions_sql}]"

def in_unnest_op(self, expression: sqlglot.expressions.Unnest) -> str: View Source

    1272        def in_unnest_op(self, expression: exp.Unnest) -> str:
    1273            return self.sql(expression)

def version_sql(self, expression: sqlglot.expressions.Version) -> str: View Source

    1275        def version_sql(self, expression: exp.Version) -> str:
    1276            if expression.name == "TIMESTAMP":
    1277                expression.set("this", "SYSTEM_TIME")
    1278            return super().version_sql(expression)

def contains_sql(self, expression: sqlglot.expressions.Contains) -> str: View Source

    1280        def contains_sql(self, expression: exp.Contains) -> str:
    1281            this = expression.this
    1282            expr = expression.expression
    1283
    1284            if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
    1285                this = this.this
    1286                expr = expr.this
    1287
    1288            return self.func("CONTAINS_SUBSTR", this, expr)

def cast_sql( self, expression: sqlglot.expressions.Cast, safe_prefix: Optional[str] = None) -> str: View Source

    1290        def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
    1291            this = expression.this
    1292
    1293            # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3]
    1294            # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions,
    1295            # because they aren't literals and so the above syntax is invalid BigQuery.
    1296            if isinstance(this, exp.Array):
    1297                elem = seq_get(this.expressions, 0)
    1298                if not (elem and elem.find(exp.Query)):
    1299                    return f"{self.sql(expression, 'to')}{self.sql(this)}"
    1300
    1301            return super().cast_sql(expression, safe_prefix=safe_prefix)

TRY_SUPPORTED = False
SUPPORTS_UESCAPE = False

##### Inherited Members

sqlglot.generator.Generator
  Generator
  LOCKING_READS_SUPPORTED
  WRAP_DERIVED_VALUES
  CREATE_FUNCTION_RETURN_AS
  MATCHED_BY_SOURCE
  SINGLE_STRING_INTERVAL
  GROUPINGS_SEP
  INDEX_ON
  QUERY_HINT_SEP
  IS_BOOL_ALLOWED
  DUPLICATE_KEY_UPDATE_WITH_SET
  LIMIT_IS_TOP
  RETURNING_END
  EXTRACT_ALLOWS_QUOTES
  TZ_TO_WITH_TIME_ZONE
  SELECT_KINDS
  VALUES_AS_TABLE
  ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
  AGGREGATE_FILTER_SUPPORTED
  SEMI_ANTI_JOIN_WITH_SIDE
  COMPUTED_COLUMN_WITH_TYPE
  SUPPORTS_TABLE_COPY
  TABLESAMPLE_REQUIRES_PARENS
  TABLESAMPLE_SIZE_IS_ROWS
  TABLESAMPLE_KEYWORDS
  TABLESAMPLE_WITH_METHOD
  TABLESAMPLE_SEED_KEYWORD
  DATA_TYPE_SPECIFIERS_ALLOWED
  ENSURE_BOOLS
  CTE_RECURSIVE_KEYWORD_REQUIRED
  SUPPORTS_SINGLE_ARG_CONCAT
  LAST_DAY_SUPPORTS_DATE_PART
  INSERT_OVERWRITE
  SUPPORTS_SELECT_INTO
  SUPPORTS_UNLOGGED_TABLES
  SUPPORTS_CREATE_TABLE_LIKE
  LIKE_PROPERTY_INSIDE_SCHEMA
  MULTI_ARG_DISTINCT
  JSON_TYPE_REQUIRED_FOR_EXTRACTION
  JSON_PATH_BRACKETED_KEY_SUPPORTED
  SET_OP_MODIFIERS
  COPY_PARAMS_ARE_WRAPPED
  COPY_PARAMS_EQ_REQUIRED
  COPY_HAS_INTO_KEYWORD
  STAR_EXCEPT
  QUOTE_JSON_PATH
  PAD_FILL_PATTERN_IS_REQUIRED
  ARRAY_CONCAT_IS_VAR_LEN
  SUPPORTS_CONVERT_TIMEZONE
  SUPPORTS_MEDIAN
  PARSE_JSON_NAME
  ARRAY_SIZE_NAME
  ALTER_SET_TYPE
  ARRAY_SIZE_DIM_REQUIRED
  TIME_PART_SINGULARS
  TOKEN_MAPPING
  STRUCT_DELIMITER
  PARAMETER_TOKEN
  EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
  WITH_SEPARATED_COMMENTS
  EXCLUDE_COMMENTS
  UNWRAPPED_INTERVAL_VALUES
  PARAMETERIZABLE_TEXT_TYPES
  EXPRESSIONS_WITHOUT_NESTED_CTES
  SENTINEL_LINE_BREAK
  pretty
  identify
  normalize
  pad
  unsupported_level
  max_unsupported
  leading_comma
  max_text_width
  comments
  dialect
  normalize_functions
  unsupported_messages
  generate
  preprocess
  unsupported
  sep
  seg
  pad_comment
  maybe_comment
  wrap
  no_identify
  normalize_func
  indent
  sql
  uncache_sql
  cache_sql
  characterset_sql
  column_sql
  columnposition_sql
  columndef_sql
  columnconstraint_sql
  computedcolumnconstraint_sql
  autoincrementcolumnconstraint_sql
  compresscolumnconstraint_sql
  generatedasidentitycolumnconstraint_sql
  generatedasrowcolumnconstraint_sql
  periodforsystemtimeconstraint_sql
  notnullcolumnconstraint_sql
  transformcolumnconstraint_sql
  primarykeycolumnconstraint_sql
  uniquecolumnconstraint_sql
  createable_sql
  create_sql
  sequenceproperties_sql
  clone_sql
  describe_sql
  heredoc_sql
  prepend_ctes
  with_sql
  cte_sql
  tablealias_sql
  bitstring_sql
  hexstring_sql
  bytestring_sql
  unicodestring_sql
  rawstring_sql
  datatypeparam_sql
  datatype_sql
  directory_sql
  delete_sql
  drop_sql
  set_operation
  set_operations
  fetch_sql
  limitoptions_sql
  filter_sql
  hint_sql
  indexparameters_sql
  index_sql
  identifier_sql
  hex_sql
  lowerhex_sql
  inputoutputformat_sql
  national_sql
  partition_sql
  properties_sql
  root_properties
  properties
  with_properties
  locate_properties
  property_name
  property_sql
  likeproperty_sql
  fallbackproperty_sql
  journalproperty_sql
  freespaceproperty_sql
  checksumproperty_sql
  mergeblockratioproperty_sql
  datablocksizeproperty_sql
  blockcompressionproperty_sql
  isolatedloadingproperty_sql
  partitionboundspec_sql
  partitionedofproperty_sql
  lockingproperty_sql
  withdataproperty_sql
  withsystemversioningproperty_sql
  insert_sql
  introducer_sql
  kill_sql
  pseudotype_sql
  objectidentifier_sql
  onconflict_sql
  returning_sql
  rowformatdelimitedproperty_sql
  withtablehint_sql
  indextablehint_sql
  historicaldata_sql
  table_sql
  tablefromrows_sql
  tablesample_sql
  pivot_sql
  tuple_sql
  update_sql
  values_sql
  var_sql
  into_sql
  from_sql
  groupingsets_sql
  rollup_sql
  cube_sql
  group_sql
  having_sql
  connect_sql
  prior_sql
  join_sql
  lambda_sql
  lateral_op
  lateral_sql
  limit_sql
  offset_sql
  setitem_sql
  set_sql
  pragma_sql
  lock_sql
  literal_sql
  escape_str
  loaddata_sql
  null_sql
  boolean_sql
  order_sql
  withfill_sql
  cluster_sql
  distribute_sql
  sort_sql
  ordered_sql
  matchrecognizemeasure_sql
  matchrecognize_sql
  query_modifiers
  options_modifier
  queryoption_sql
  offset_limit_modifiers
  after_limit_modifiers
  select_sql
  schema_sql
  schema_columns_sql
  star_sql
  parameter_sql
  sessionparameter_sql
  placeholder_sql
  subquery_sql
  qualify_sql
  unnest_sql
  prewhere_sql
  where_sql
  window_sql
  partition_by_sql
  windowspec_sql
  withingroup_sql
  between_sql
  bracket_offset_expressions
  all_sql
  any_sql
  exists_sql
  case_sql
  constraint_sql
  nextvaluefor_sql
  extract_sql
  trim_sql
  convert_concat_args
  concat_sql
  concatws_sql
  check_sql
  foreignkey_sql
  primarykey_sql
  if_sql
  matchagainst_sql
  jsonkeyvalue_sql
  jsonpath_sql
  json_path_part
  formatjson_sql
  jsonobject_sql
  jsonobjectagg_sql
  jsonarray_sql
  jsonarrayagg_sql
  jsoncolumndef_sql
  jsonschema_sql
  jsontable_sql
  openjsoncolumndef_sql
  openjson_sql
  in_sql
  interval_sql
  return_sql
  reference_sql
  anonymous_sql
  paren_sql
  neg_sql
  not_sql
  alias_sql
  pivotalias_sql
  aliases_sql
  atindex_sql
  fromtimezone_sql
  add_sql
  and_sql
  or_sql
  xor_sql
  connector_sql
  bitwiseand_sql
  bitwiseleftshift_sql
  bitwisenot_sql
  bitwiseor_sql
  bitwiserightshift_sql
  bitwisexor_sql
  currentdate_sql
  collate_sql
  command_sql
  comment_sql
  mergetreettlaction_sql
  mergetreettl_sql
  transaction_sql
  commit_sql
  rollback_sql
  altercolumn_sql
  alterindex_sql
  alterdiststyle_sql
  altersortkey_sql
  alterrename_sql
  renamecolumn_sql
  alterset_sql
  alter_sql
  add_column_sql
  droppartition_sql
  addconstraint_sql
  distinct_sql
  ignorenulls_sql
  respectnulls_sql
  havingmax_sql
  intdiv_sql
  dpipe_sql
  div_sql
  safedivide_sql
  overlaps_sql
  distance_sql
  dot_sql
  propertyeq_sql
  escape_sql
  glob_sql
  gt_sql
  gte_sql
  ilike_sql
  ilikeany_sql
  is_sql
  like_sql
  likeany_sql
  similarto_sql
  lt_sql
  lte_sql
  mul_sql
  neq_sql
  nullsafeeq_sql
  nullsafeneq_sql
  slice_sql
  sub_sql
  jsoncast_sql
  try_sql
  log_sql
  use_sql
  binary
  ceil_floor
  function_fallback_sql
  func
  format_args
  too_wide
  format_time
  expressions
  op_expressions
  naked_property
  tag_sql
  token_sql
  userdefinedfunction_sql
  joinhint_sql
  kwarg_sql
  when_sql
  whens_sql
  merge_sql
  tochar_sql
  tonumber_sql
  dictproperty_sql
  dictrange_sql
  dictsubproperty_sql
  duplicatekeyproperty_sql
  uniquekeyproperty_sql
  distributedbyproperty_sql
  oncluster_sql
  clusteredbyproperty_sql
  anyvalue_sql
  querytransform_sql
  indexconstraintoption_sql
  checkcolumnconstraint_sql
  indexcolumnconstraint_sql
  nvl2_sql
  comprehension_sql
  columnprefix_sql
  opclass_sql
  predict_sql
  forin_sql
  refresh_sql
  toarray_sql
  tsordstotime_sql
  tsordstotimestamp_sql
  tsordstodatetime_sql
  tsordstodate_sql
  unixdate_sql
  lastday_sql
  dateadd_sql
  arrayany_sql
  struct_sql
  partitionrange_sql
  truncatetable_sql
  convert_sql
  copyparameter_sql
  credentials_sql
  copy_sql
  semicolon_sql
  datadeletionproperty_sql
  maskingpolicycolumnconstraint_sql
  gapfill_sql
  scope_resolution
  scoperesolution_sql
  parsejson_sql
  rand_sql
  changes_sql
  pad_sql
  summarize_sql
  explodinggenerateseries_sql
  arrayconcat_sql
  converttimezone_sql
  json_sql
  jsonvalue_sql
  conditionalinsert_sql
  multitableinserts_sql
  oncondition_sql
  jsonextractquote_sql
  jsonexists_sql
  arrayagg_sql
  apply_sql
  grant_sql
  grantprivilege_sql
  grantprincipal_sql
  columns_sql
  overlay_sql
  todouble_sql
  string_sql
  median_sql
  overflowtruncatebehavior_sql
  unixseconds_sql
  arraysize_sql
  attach_sql
  detach_sql
  attachoption_sql
  featuresattime_sql
  watermarkcolumnconstraint_sql
  encodeproperty_sql
  includeproperty_sql
  xmlelement_sql
  partitionbyrangeproperty_sql
  partitionbyrangepropertydynamic_sql
  unpivotcolumns_sql
  analyzesample_sql
  analyzestatistics_sql
  analyzehistogram_sql
  analyzedelete_sql
  analyzelistchainedrows_sql
  analyzevalidate_sql
  analyze_sql
  xmltable_sql
  xmlnamespace_sql
  export_sql
  declare_sql
  declareitem_sql
  recursivewithsearch_sql
  parameterizedagg_sql
  anonymousaggfunc_sql
  combinedaggfunc_sql
  combinedparameterizedagg_sql
  show_sql
  get_put_sql