From 36db14f4c6c28209371d563d76697df0172e337f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 24 Jul 2023 10:03:48 +0200 Subject: Merging upstream version 17.7.0. Signed-off-by: Daniel Baumann --- docs/sqlglot/dialects/bigquery.html | 3014 ++++++++++++++++++----------------- 1 file changed, 1510 insertions(+), 1504 deletions(-) (limited to 'docs/sqlglot/dialects/bigquery.html') diff --git a/docs/sqlglot/dialects/bigquery.html b/docs/sqlglot/dialects/bigquery.html index 799a1d4..4249e22 100644 --- a/docs/sqlglot/dialects/bigquery.html +++ b/docs/sqlglot/dialects/bigquery.html @@ -354,625 +354,628 @@ 8from sqlglot._typing import E 9from sqlglot.dialects.dialect import ( 10 Dialect, - 11 datestrtodate_sql, - 12 format_time_lambda, - 13 inline_array_sql, - 14 max_or_greatest, - 15 min_or_least, - 16 no_ilike_sql, - 17 parse_date_delta_with_interval, - 18 rename_func, - 19 timestrtotime_sql, - 20 ts_or_ds_to_date_sql, - 21) - 22from sqlglot.helper import seq_get, split_num_words - 23from sqlglot.tokens import TokenType - 24 - 25logger = logging.getLogger("sqlglot") + 11 binary_from_function, + 12 datestrtodate_sql, + 13 format_time_lambda, + 14 inline_array_sql, + 15 max_or_greatest, + 16 min_or_least, + 17 no_ilike_sql, + 18 parse_date_delta_with_interval, + 19 regexp_replace_sql, + 20 rename_func, + 21 timestrtotime_sql, + 22 ts_or_ds_to_date_sql, + 23) + 24from sqlglot.helper import seq_get, split_num_words + 25from sqlglot.tokens import TokenType 26 - 27 - 28def _date_add_sql( - 29 data_type: str, kind: str - 30) -> t.Callable[[generator.Generator, exp.Expression], str]: - 31 def func(self, expression): - 32 this = self.sql(expression, "this") - 33 unit = expression.args.get("unit") - 34 unit = exp.var(unit.name.upper() if unit else "DAY") - 35 interval = exp.Interval(this=expression.expression, unit=unit) - 36 return f"{data_type}_{kind}({this}, {self.sql(interval)})" - 37 - 38 return func + 27logger = logging.getLogger("sqlglot") + 28 + 29 + 30def _date_add_sql( + 31 data_type: str, kind: str + 32) -> t.Callable[[generator.Generator, exp.Expression], str]: + 33 def func(self, expression): + 34 this = self.sql(expression, "this") + 35 unit = expression.args.get("unit") + 36 unit = exp.var(unit.name.upper() if unit else "DAY") + 37 interval = exp.Interval(this=expression.expression, unit=unit) + 38 return f"{data_type}_{kind}({this}, {self.sql(interval)})" 39 - 40 - 41def _derived_table_values_to_unnest(self: generator.Generator, expression: exp.Values) -> str: - 42 if not isinstance(expression.unnest().parent, exp.From): - 43 return self.values_sql(expression) - 44 - 45 alias = expression.args.get("alias") + 40 return func + 41 + 42 + 43def _derived_table_values_to_unnest(self: generator.Generator, expression: exp.Values) -> str: + 44 if not expression.find_ancestor(exp.From, exp.Join): + 45 return self.values_sql(expression) 46 - 47 structs = [ - 48 exp.Struct( - 49 expressions=[ - 50 exp.alias_(value, column_name) - 51 for value, column_name in zip( - 52 t.expressions, - 53 alias.columns - 54 if alias and alias.columns - 55 else (f"_c{i}" for i in range(len(t.expressions))), - 56 ) - 57 ] - 58 ) - 59 for t in expression.find_all(exp.Tuple) - 60 ] - 61 - 62 return self.unnest_sql(exp.Unnest(expressions=[exp.Array(expressions=structs)])) + 47 alias = expression.args.get("alias") + 48 + 49 structs = [ + 50 exp.Struct( + 51 expressions=[ + 52 exp.alias_(value, column_name) + 53 for value, column_name in zip( + 54 t.expressions, + 55 alias.columns + 56 if alias and alias.columns + 57 else (f"_c{i}" for i in range(len(t.expressions))), + 58 ) + 59 ] + 60 ) + 61 for t in expression.find_all(exp.Tuple) + 62 ] 63 - 64 - 65def _returnsproperty_sql(self: generator.Generator, expression: exp.ReturnsProperty) -> str: - 66 this = expression.this - 67 if isinstance(this, exp.Schema): - 68 this = f"{this.this} <{self.expressions(this)}>" - 69 else: - 70 this = self.sql(this) - 71 return f"RETURNS {this}" - 72 - 73 - 74def _create_sql(self: generator.Generator, expression: exp.Create) -> str: - 75 kind = expression.args["kind"] - 76 returns = expression.find(exp.ReturnsProperty) - 77 if kind.upper() == "FUNCTION" and returns and returns.args.get("is_table"): - 78 expression = expression.copy() - 79 expression.set("kind", "TABLE FUNCTION") - 80 if isinstance( - 81 expression.expression, - 82 ( - 83 exp.Subquery, - 84 exp.Literal, - 85 ), - 86 ): - 87 expression.set("expression", expression.expression.this) - 88 - 89 return self.create_sql(expression) + 64 return self.unnest_sql(exp.Unnest(expressions=[exp.Array(expressions=structs)])) + 65 + 66 + 67def _returnsproperty_sql(self: generator.Generator, expression: exp.ReturnsProperty) -> str: + 68 this = expression.this + 69 if isinstance(this, exp.Schema): + 70 this = f"{this.this} <{self.expressions(this)}>" + 71 else: + 72 this = self.sql(this) + 73 return f"RETURNS {this}" + 74 + 75 + 76def _create_sql(self: generator.Generator, expression: exp.Create) -> str: + 77 kind = expression.args["kind"] + 78 returns = expression.find(exp.ReturnsProperty) + 79 if kind.upper() == "FUNCTION" and returns and returns.args.get("is_table"): + 80 expression = expression.copy() + 81 expression.set("kind", "TABLE FUNCTION") + 82 if isinstance( + 83 expression.expression, + 84 ( + 85 exp.Subquery, + 86 exp.Literal, + 87 ), + 88 ): + 89 expression.set("expression", expression.expression.this) 90 - 91 return self.create_sql(expression) + 91 return self.create_sql(expression) 92 - 93 - 94def _unqualify_unnest(expression: exp.Expression) -> exp.Expression: - 95 """Remove references to unnest table aliases since bigquery doesn't allow them. - 96 - 97 These are added by the optimizer's qualify_column step. - 98 """ - 99 from sqlglot.optimizer.scope import Scope -100 -101 if isinstance(expression, exp.Select): -102 for unnest in expression.find_all(exp.Unnest): -103 if isinstance(unnest.parent, (exp.From, exp.Join)) and unnest.alias: -104 for column in Scope(expression).find_all(exp.Column): -105 if column.table == unnest.alias: -106 column.set("table", None) -107 -108 return expression + 93 return self.create_sql(expression) + 94 + 95 + 96def _unqualify_unnest(expression: exp.Expression) -> exp.Expression: + 97 """Remove references to unnest table aliases since bigquery doesn't allow them. + 98 + 99 These are added by the optimizer's qualify_column step. +100 """ +101 from sqlglot.optimizer.scope import Scope +102 +103 if isinstance(expression, exp.Select): +104 for unnest in expression.find_all(exp.Unnest): +105 if isinstance(unnest.parent, (exp.From, exp.Join)) and unnest.alias: +106 for column in Scope(expression).find_all(exp.Column): +107 if column.table == unnest.alias: +108 column.set("table", None) 109 -110 -111# https://issuetracker.google.com/issues/162294746 -112# workaround for bigquery bug when grouping by an expression and then ordering -113# WITH x AS (SELECT 1 y) -114# SELECT y + 1 z -115# FROM x -116# GROUP BY x + 1 -117# ORDER by z -118def _alias_ordered_group(expression: exp.Expression) -> exp.Expression: -119 if isinstance(expression, exp.Select): -120 group = expression.args.get("group") -121 order = expression.args.get("order") -122 -123 if group and order: -124 aliases = { -125 select.this: select.args["alias"] -126 for select in expression.selects -127 if isinstance(select, exp.Alias) -128 } -129 -130 for e in group.expressions: -131 alias = aliases.get(e) -132 -133 if alias: -134 e.replace(exp.column(alias)) -135 -136 return expression +110 return expression +111 +112 +113# https://issuetracker.google.com/issues/162294746 +114# workaround for bigquery bug when grouping by an expression and then ordering +115# WITH x AS (SELECT 1 y) +116# SELECT y + 1 z +117# FROM x +118# GROUP BY x + 1 +119# ORDER by z +120def _alias_ordered_group(expression: exp.Expression) -> exp.Expression: +121 if isinstance(expression, exp.Select): +122 group = expression.args.get("group") +123 order = expression.args.get("order") +124 +125 if group and order: +126 aliases = { +127 select.this: select.args["alias"] +128 for select in expression.selects +129 if isinstance(select, exp.Alias) +130 } +131 +132 for e in group.expressions: +133 alias = aliases.get(e) +134 +135 if alias: +136 e.replace(exp.column(alias)) 137 -138 -139def _pushdown_cte_column_names(expression: exp.Expression) -> exp.Expression: -140 """BigQuery doesn't allow column names when defining a CTE, so we try to push them down.""" -141 if isinstance(expression, exp.CTE) and expression.alias_column_names: -142 cte_query = expression.this -143 -144 if cte_query.is_star: -145 logger.warning( -146 "Can't push down CTE column names for star queries. Run the query through" -147 " the optimizer or use 'qualify' to expand the star projections first." -148 ) -149 return expression -150 -151 column_names = expression.alias_column_names -152 expression.args["alias"].set("columns", None) -153 -154 for name, select in zip(column_names, cte_query.selects): -155 to_replace = select -156 -157 if isinstance(select, exp.Alias): -158 select = select.this -159 -160 # Inner aliases are shadowed by the CTE column names -161 to_replace.replace(exp.alias_(select, name)) -162 -163 return expression +138 return expression +139 +140 +141def _pushdown_cte_column_names(expression: exp.Expression) -> exp.Expression: +142 """BigQuery doesn't allow column names when defining a CTE, so we try to push them down.""" +143 if isinstance(expression, exp.CTE) and expression.alias_column_names: +144 cte_query = expression.this +145 +146 if cte_query.is_star: +147 logger.warning( +148 "Can't push down CTE column names for star queries. Run the query through" +149 " the optimizer or use 'qualify' to expand the star projections first." +150 ) +151 return expression +152 +153 column_names = expression.alias_column_names +154 expression.args["alias"].set("columns", None) +155 +156 for name, select in zip(column_names, cte_query.selects): +157 to_replace = select +158 +159 if isinstance(select, exp.Alias): +160 select = select.this +161 +162 # Inner aliases are shadowed by the CTE column names +163 to_replace.replace(exp.alias_(select, name)) 164 -165 -166def _parse_timestamp(args: t.List) -> exp.StrToTime: -167 this = format_time_lambda(exp.StrToTime, "bigquery")([seq_get(args, 1), seq_get(args, 0)]) -168 this.set("zone", seq_get(args, 2)) -169 return this -170 -171 -172def _parse_date(args: t.List) -> exp.Date | exp.DateFromParts: -173 expr_type = exp.DateFromParts if len(args) == 3 else exp.Date -174 return expr_type.from_arg_list(args) -175 -176 -177def _parse_to_hex(args: t.List) -> exp.Hex | exp.MD5: -178 # TO_HEX(MD5(..)) is common in BigQuery, so it's parsed into MD5 to simplify its transpilation -179 arg = seq_get(args, 0) -180 return exp.MD5(this=arg.this) if isinstance(arg, exp.MD5Digest) else exp.Hex(this=arg) -181 -182 -183class BigQuery(Dialect): -184 UNNEST_COLUMN_ONLY = True -185 -186 # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity -187 RESOLVES_IDENTIFIERS_AS_UPPERCASE = None -188 -189 # bigquery udfs are case sensitive -190 NORMALIZE_FUNCTIONS = False -191 -192 TIME_MAPPING = { -193 "%D": "%m/%d/%y", -194 } -195 -196 FORMAT_MAPPING = { -197 "DD": "%d", -198 "MM": "%m", -199 "MON": "%b", -200 "MONTH": "%B", -201 "YYYY": "%Y", -202 "YY": "%y", -203 "HH": "%I", -204 "HH12": "%I", -205 "HH24": "%H", -206 "MI": "%M", -207 "SS": "%S", -208 "SSSSS": "%f", -209 "TZH": "%z", -210 } -211 -212 @classmethod -213 def normalize_identifier(cls, expression: E) -> E: -214 # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least). -215 # The following check is essentially a heuristic to detect tables based on whether or -216 # not they're qualified. -217 if isinstance(expression, exp.Identifier): -218 parent = expression.parent -219 -220 while isinstance(parent, exp.Dot): -221 parent = parent.parent -222 -223 if ( -224 not isinstance(parent, exp.UserDefinedFunction) -225 and not (isinstance(parent, exp.Table) and parent.db) -226 and not expression.meta.get("is_table") -227 ): -228 expression.set("this", expression.this.lower()) -229 -230 return expression +165 return expression +166 +167 +168def _parse_timestamp(args: t.List) -> exp.StrToTime: +169 this = format_time_lambda(exp.StrToTime, "bigquery")([seq_get(args, 1), seq_get(args, 0)]) +170 this.set("zone", seq_get(args, 2)) +171 return this +172 +173 +174def _parse_date(args: t.List) -> exp.Date | exp.DateFromParts: +175 expr_type = exp.DateFromParts if len(args) == 3 else exp.Date +176 return expr_type.from_arg_list(args) +177 +178 +179def _parse_to_hex(args: t.List) -> exp.Hex | exp.MD5: +180 # TO_HEX(MD5(..)) is common in BigQuery, so it's parsed into MD5 to simplify its transpilation +181 arg = seq_get(args, 0) +182 return exp.MD5(this=arg.this) if isinstance(arg, exp.MD5Digest) else exp.Hex(this=arg) +183 +184 +185class BigQuery(Dialect): +186 UNNEST_COLUMN_ONLY = True +187 +188 # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity +189 RESOLVES_IDENTIFIERS_AS_UPPERCASE = None +190 +191 # bigquery udfs are case sensitive +192 NORMALIZE_FUNCTIONS = False +193 +194 TIME_MAPPING = { +195 "%D": "%m/%d/%y", +196 } +197 +198 FORMAT_MAPPING = { +199 "DD": "%d", +200 "MM": "%m", +201 "MON": "%b", +202 "MONTH": "%B", +203 "YYYY": "%Y", +204 "YY": "%y", +205 "HH": "%I", +206 "HH12": "%I", +207 "HH24": "%H", +208 "MI": "%M", +209 "SS": "%S", +210 "SSSSS": "%f", +211 "TZH": "%z", +212 } +213 +214 @classmethod +215 def normalize_identifier(cls, expression: E) -> E: +216 # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least). +217 # The following check is essentially a heuristic to detect tables based on whether or +218 # not they're qualified. +219 if isinstance(expression, exp.Identifier): +220 parent = expression.parent +221 +222 while isinstance(parent, exp.Dot): +223 parent = parent.parent +224 +225 if ( +226 not isinstance(parent, exp.UserDefinedFunction) +227 and not (isinstance(parent, exp.Table) and parent.db) +228 and not expression.meta.get("is_table") +229 ): +230 expression.set("this", expression.this.lower()) 231 -232 class Tokenizer(tokens.Tokenizer): -233 QUOTES = ["'", '"', '"""', "'''"] -234 COMMENTS = ["--", "#", ("/*", "*/")] -235 IDENTIFIERS = ["`"] -236 STRING_ESCAPES = ["\\"] -237 -238 HEX_STRINGS = [("0x", ""), ("0X", "")] +232 return expression +233 +234 class Tokenizer(tokens.Tokenizer): +235 QUOTES = ["'", '"', '"""', "'''"] +236 COMMENTS = ["--", "#", ("/*", "*/")] +237 IDENTIFIERS = ["`"] +238 STRING_ESCAPES = ["\\"] 239 -240 BYTE_STRINGS = [ -241 (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B") -242 ] -243 -244 RAW_STRINGS = [ -245 (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R") -246 ] -247 -248 KEYWORDS = { -249 **tokens.Tokenizer.KEYWORDS, -250 "ANY TYPE": TokenType.VARIANT, -251 "BEGIN": TokenType.COMMAND, -252 "BEGIN TRANSACTION": TokenType.BEGIN, -253 "CURRENT_DATETIME": TokenType.CURRENT_DATETIME, -254 "BYTES": TokenType.BINARY, -255 "DECLARE": TokenType.COMMAND, -256 "FLOAT64": TokenType.DOUBLE, -257 "INT64": TokenType.BIGINT, -258 "RECORD": TokenType.STRUCT, -259 "TIMESTAMP": TokenType.TIMESTAMPTZ, -260 "NOT DETERMINISTIC": TokenType.VOLATILE, -261 "UNKNOWN": TokenType.NULL, -262 } -263 KEYWORDS.pop("DIV") -264 -265 class Parser(parser.Parser): -266 PREFIXED_PIVOT_COLUMNS = True -267 -268 LOG_BASE_FIRST = False -269 LOG_DEFAULTS_TO_LN = True -270 -271 FUNCTIONS = { -272 **parser.Parser.FUNCTIONS, -273 "DATE": _parse_date, -274 "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd), -275 "DATE_SUB": parse_date_delta_with_interval(exp.DateSub), -276 "DATE_TRUNC": lambda args: exp.DateTrunc( -277 unit=exp.Literal.string(str(seq_get(args, 1))), -278 this=seq_get(args, 0), -279 ), -280 "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd), -281 "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub), -282 "DIV": lambda args: exp.IntDiv(this=seq_get(args, 0), expression=seq_get(args, 1)), -283 "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list, -284 "MD5": exp.MD5Digest.from_arg_list, -285 "TO_HEX": _parse_to_hex, -286 "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")( -287 [seq_get(args, 1), seq_get(args, 0)] -288 ), -289 "PARSE_TIMESTAMP": _parse_timestamp, -290 "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list, -291 "REGEXP_EXTRACT": lambda args: exp.RegexpExtract( -292 this=seq_get(args, 0), -293 expression=seq_get(args, 1), -294 position=seq_get(args, 2), -295 occurrence=seq_get(args, 3), -296 group=exp.Literal.number(1) -297 if re.compile(str(seq_get(args, 1))).groups == 1 -298 else None, -299 ), -300 "SPLIT": lambda args: exp.Split( -301 # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split -302 this=seq_get(args, 0), -303 expression=seq_get(args, 1) or exp.Literal.string(","), -304 ), -305 "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd), -306 "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub), -307 "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd), -308 "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub), -309 "TO_JSON_STRING": exp.JSONFormat.from_arg_list, -310 } -311 -312 FUNCTION_PARSERS = { -313 **parser.Parser.FUNCTION_PARSERS, -314 "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]), -315 } -316 FUNCTION_PARSERS.pop("TRIM") -317 -318 NO_PAREN_FUNCTIONS = { -319 **parser.Parser.NO_PAREN_FUNCTIONS, -320 TokenType.CURRENT_DATETIME: exp.CurrentDatetime, -321 } -322 -323 NESTED_TYPE_TOKENS = { -324 *parser.Parser.NESTED_TYPE_TOKENS, -325 TokenType.TABLE, -326 } -327 -328 ID_VAR_TOKENS = { -329 *parser.Parser.ID_VAR_TOKENS, -330 TokenType.VALUES, -331 } -332 -333 PROPERTY_PARSERS = { -334 **parser.Parser.PROPERTY_PARSERS, -335 "NOT DETERMINISTIC": lambda self: self.expression( -336 exp.StabilityProperty, this=exp.Literal.string("VOLATILE") -337 ), -338 "OPTIONS": lambda self: self._parse_with_property(), -339 } -340 -341 CONSTRAINT_PARSERS = { -342 **parser.Parser.CONSTRAINT_PARSERS, -343 "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()), -344 } -345 -346 def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]: -347 this = super()._parse_table_part(schema=schema) -348 -349 # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names -350 if isinstance(this, exp.Identifier): -351 table_name = this.name -352 while self._match(TokenType.DASH, advance=False) and self._next: -353 self._advance(2) -354 table_name += f"-{self._prev.text}" -355 -356 this = exp.Identifier(this=table_name, quoted=this.args.get("quoted")) +240 HEX_STRINGS = [("0x", ""), ("0X", "")] +241 +242 BYTE_STRINGS = [ +243 (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B") +244 ] +245 +246 RAW_STRINGS = [ +247 (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R") +248 ] +249 +250 KEYWORDS = { +251 **tokens.Tokenizer.KEYWORDS, +252 "ANY TYPE": TokenType.VARIANT, +253 "BEGIN": TokenType.COMMAND, +254 "BEGIN TRANSACTION": TokenType.BEGIN, +255 "CURRENT_DATETIME": TokenType.CURRENT_DATETIME, +256 "BYTES": TokenType.BINARY, +257 "DECLARE": TokenType.COMMAND, +258 "FLOAT64": TokenType.DOUBLE, +259 "INT64": TokenType.BIGINT, +260 "RECORD": TokenType.STRUCT, +261 "TIMESTAMP": TokenType.TIMESTAMPTZ, +262 "NOT DETERMINISTIC": TokenType.VOLATILE, +263 "UNKNOWN": TokenType.NULL, +264 } +265 KEYWORDS.pop("DIV") +266 +267 class Parser(parser.Parser): +268 PREFIXED_PIVOT_COLUMNS = True +269 +270 LOG_BASE_FIRST = False +271 LOG_DEFAULTS_TO_LN = True +272 +273 FUNCTIONS = { +274 **parser.Parser.FUNCTIONS, +275 "DATE": _parse_date, +276 "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd), +277 "DATE_SUB": parse_date_delta_with_interval(exp.DateSub), +278 "DATE_TRUNC": lambda args: exp.DateTrunc( +279 unit=exp.Literal.string(str(seq_get(args, 1))), +280 this=seq_get(args, 0), +281 ), +282 "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd), +283 "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub), +284 "DIV": binary_from_function(exp.IntDiv), +285 "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list, +286 "MD5": exp.MD5Digest.from_arg_list, +287 "TO_HEX": _parse_to_hex, +288 "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")( +289 [seq_get(args, 1), seq_get(args, 0)] +290 ), +291 "PARSE_TIMESTAMP": _parse_timestamp, +292 "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list, +293 "REGEXP_EXTRACT": lambda args: exp.RegexpExtract( +294 this=seq_get(args, 0), +295 expression=seq_get(args, 1), +296 position=seq_get(args, 2), +297 occurrence=seq_get(args, 3), +298 group=exp.Literal.number(1) +299 if re.compile(str(seq_get(args, 1))).groups == 1 +300 else None, +301 ), +302 "SPLIT": lambda args: exp.Split( +303 # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split +304 this=seq_get(args, 0), +305 expression=seq_get(args, 1) or exp.Literal.string(","), +306 ), +307 "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd), +308 "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub), +309 "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd), +310 "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub), +311 "TO_JSON_STRING": exp.JSONFormat.from_arg_list, +312 } +313 +314 FUNCTION_PARSERS = { +315 **parser.Parser.FUNCTION_PARSERS, +316 "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]), +317 } +318 FUNCTION_PARSERS.pop("TRIM") +319 +320 NO_PAREN_FUNCTIONS = { +321 **parser.Parser.NO_PAREN_FUNCTIONS, +322 TokenType.CURRENT_DATETIME: exp.CurrentDatetime, +323 } +324 +325 NESTED_TYPE_TOKENS = { +326 *parser.Parser.NESTED_TYPE_TOKENS, +327 TokenType.TABLE, +328 } +329 +330 ID_VAR_TOKENS = { +331 *parser.Parser.ID_VAR_TOKENS, +332 TokenType.VALUES, +333 } +334 +335 PROPERTY_PARSERS = { +336 **parser.Parser.PROPERTY_PARSERS, +337 "NOT DETERMINISTIC": lambda self: self.expression( +338 exp.StabilityProperty, this=exp.Literal.string("VOLATILE") +339 ), +340 "OPTIONS": lambda self: self._parse_with_property(), +341 } +342 +343 CONSTRAINT_PARSERS = { +344 **parser.Parser.CONSTRAINT_PARSERS, +345 "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()), +346 } +347 +348 def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]: +349 this = super()._parse_table_part(schema=schema) +350 +351 # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names +352 if isinstance(this, exp.Identifier): +353 table_name = this.name +354 while self._match(TokenType.DASH, advance=False) and self._next: +355 self._advance(2) +356 table_name += f"-{self._prev.text}" 357 -358 return this +358 this = exp.Identifier(this=table_name, quoted=this.args.get("quoted")) 359 -360 def _parse_table_parts(self, schema: bool = False) -> exp.Table: -361 table = super()._parse_table_parts(schema=schema) -362 if isinstance(table.this, exp.Identifier) and "." in table.name: -363 catalog, db, this, *rest = ( -364 t.cast(t.Optional[exp.Expression], exp.to_identifier(x)) -365 for x in split_num_words(table.name, ".", 3) -366 ) -367 -368 if rest and this: -369 this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest])) -370 -371 table = exp.Table(this=this, db=db, catalog=catalog) +360 return this +361 +362 def _parse_table_parts(self, schema: bool = False) -> exp.Table: +363 table = super()._parse_table_parts(schema=schema) +364 if isinstance(table.this, exp.Identifier) and "." in table.name: +365 catalog, db, this, *rest = ( +366 t.cast(t.Optional[exp.Expression], exp.to_identifier(x)) +367 for x in split_num_words(table.name, ".", 3) +368 ) +369 +370 if rest and this: +371 this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest])) 372 -373 return table +373 table = exp.Table(this=this, db=db, catalog=catalog) 374 -375 class Generator(generator.Generator): -376 EXPLICIT_UNION = True -377 INTERVAL_ALLOWS_PLURAL_FORM = False -378 JOIN_HINTS = False -379 QUERY_HINTS = False -380 TABLE_HINTS = False -381 LIMIT_FETCH = "LIMIT" -382 RENAME_TABLE_WITH_DB = False -383 ESCAPE_LINE_BREAK = True -384 -385 TRANSFORMS = { -386 **generator.Generator.TRANSFORMS, -387 exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"), -388 exp.ArraySize: rename_func("ARRAY_LENGTH"), -389 exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]), -390 exp.Create: _create_sql, -391 exp.CTE: transforms.preprocess([_pushdown_cte_column_names]), -392 exp.DateAdd: _date_add_sql("DATE", "ADD"), -393 exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})", -394 exp.DateFromParts: rename_func("DATE"), -395 exp.DateStrToDate: datestrtodate_sql, -396 exp.DateSub: _date_add_sql("DATE", "SUB"), -397 exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"), -398 exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"), -399 exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")), -400 exp.GenerateSeries: rename_func("GENERATE_ARRAY"), -401 exp.GroupConcat: rename_func("STRING_AGG"), -402 exp.Hex: rename_func("TO_HEX"), -403 exp.ILike: no_ilike_sql, -404 exp.IntDiv: rename_func("DIV"), -405 exp.JSONFormat: rename_func("TO_JSON_STRING"), -406 exp.Max: max_or_greatest, -407 exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)), -408 exp.MD5Digest: rename_func("MD5"), -409 exp.Min: min_or_least, -410 exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}", -411 exp.RegexpExtract: lambda self, e: self.func( -412 "REGEXP_EXTRACT", -413 e.this, -414 e.expression, -415 e.args.get("position"), -416 e.args.get("occurrence"), -417 ), -418 exp.RegexpLike: rename_func("REGEXP_CONTAINS"), -419 exp.ReturnsProperty: _returnsproperty_sql, -420 exp.Select: transforms.preprocess( -421 [ -422 transforms.explode_to_unnest, -423 _unqualify_unnest, -424 transforms.eliminate_distinct_on, -425 _alias_ordered_group, -426 ] -427 ), -428 exp.StabilityProperty: lambda self, e: f"DETERMINISTIC" -429 if e.name == "IMMUTABLE" -430 else "NOT DETERMINISTIC", -431 exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})", -432 exp.StrToTime: lambda self, e: self.func( -433 "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone") -434 ), -435 exp.TimeAdd: _date_add_sql("TIME", "ADD"), -436 exp.TimeSub: _date_add_sql("TIME", "SUB"), -437 exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"), -438 exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"), -439 exp.TimeStrToTime: timestrtotime_sql, -440 exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression), -441 exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"), -442 exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"), -443 exp.Unhex: rename_func("FROM_HEX"), -444 exp.Values: _derived_table_values_to_unnest, -445 exp.VariancePop: rename_func("VAR_POP"), -446 } -447 -448 TYPE_MAPPING = { -449 **generator.Generator.TYPE_MAPPING, -450 exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC", -451 exp.DataType.Type.BIGINT: "INT64", -452 exp.DataType.Type.BINARY: "BYTES", -453 exp.DataType.Type.BOOLEAN: "BOOL", -454 exp.DataType.Type.CHAR: "STRING", -455 exp.DataType.Type.DECIMAL: "NUMERIC", -456 exp.DataType.Type.DOUBLE: "FLOAT64", -457 exp.DataType.Type.FLOAT: "FLOAT64", -458 exp.DataType.Type.INT: "INT64", -459 exp.DataType.Type.NCHAR: "STRING", -460 exp.DataType.Type.NVARCHAR: "STRING", -461 exp.DataType.Type.SMALLINT: "INT64", -462 exp.DataType.Type.TEXT: "STRING", -463 exp.DataType.Type.TIMESTAMP: "DATETIME", -464 exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP", -465 exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP", -466 exp.DataType.Type.TINYINT: "INT64", -467 exp.DataType.Type.VARBINARY: "BYTES", -468 exp.DataType.Type.VARCHAR: "STRING", -469 exp.DataType.Type.VARIANT: "ANY TYPE", -470 } -471 -472 PROPERTIES_LOCATION = { -473 **generator.Generator.PROPERTIES_LOCATION, -474 exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA, -475 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, -476 } -477 -478 # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords -479 RESERVED_KEYWORDS = { -480 *generator.Generator.RESERVED_KEYWORDS, -481 "all", -482 "and", -483 "any", -484 "array", -485 "as", -486 "asc", -487 "assert_rows_modified", -488 "at", -489 "between", -490 "by", -491 "case", -492 "cast", -493 "collate", -494 "contains", -495 "create", -496 "cross", -497 "cube", -498 "current", -499 "default", -500 "define", -501 "desc", -502 "distinct", -503 "else", -504 "end", -505 "enum", -506 "escape", -507 "except", -508 "exclude", -509 "exists", -510 "extract", -511 "false", -512 "fetch", -513 "following", -514 "for", -515 "from", -516 "full", -517 "group", -518 "grouping", -519 "groups", -520 "hash", -521 "having", -522 "if", -523 "ignore", -524 "in", -525 "inner", -526 "intersect", -527 "interval", -528 "into", -529 "is", -530 "join", -531 "lateral", -532 "left", -533 "like", -534 "limit", -535 "lookup", -536 "merge", -537 "natural", -538 "new", -539 "no", -540 "not", -541 "null", -542 "nulls", -543 "of", -544 "on", -545 "or", -546 "order", -547 "outer", -548 "over", -549 "partition", -550 "preceding", -551 "proto", -552 "qualify", -553 "range", -554 "recursive", -555 "respect", -556 "right", -557 "rollup", -558 "rows", -559 "select", -560 "set", -561 "some", -562 "struct", -563 "tablesample", -564 "then", -565 "to", -566 "treat", -567 "true", -568 "unbounded", -569 "union", -570 "unnest", -571 "using", -572 "when", -573 "where", -574 "window", -575 "with", -576 "within", -577 } -578 -579 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: -580 parent = expression.parent +375 return table +376 +377 class Generator(generator.Generator): +378 EXPLICIT_UNION = True +379 INTERVAL_ALLOWS_PLURAL_FORM = False +380 JOIN_HINTS = False +381 QUERY_HINTS = False +382 TABLE_HINTS = False +383 LIMIT_FETCH = "LIMIT" +384 RENAME_TABLE_WITH_DB = False +385 ESCAPE_LINE_BREAK = True +386 +387 TRANSFORMS = { +388 **generator.Generator.TRANSFORMS, +389 exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"), +390 exp.ArraySize: rename_func("ARRAY_LENGTH"), +391 exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]), +392 exp.Create: _create_sql, +393 exp.CTE: transforms.preprocess([_pushdown_cte_column_names]), +394 exp.DateAdd: _date_add_sql("DATE", "ADD"), +395 exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})", +396 exp.DateFromParts: rename_func("DATE"), +397 exp.DateStrToDate: datestrtodate_sql, +398 exp.DateSub: _date_add_sql("DATE", "SUB"), +399 exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"), +400 exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"), +401 exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")), +402 exp.GenerateSeries: rename_func("GENERATE_ARRAY"), +403 exp.GroupConcat: rename_func("STRING_AGG"), +404 exp.Hex: rename_func("TO_HEX"), +405 exp.ILike: no_ilike_sql, +406 exp.IntDiv: rename_func("DIV"), +407 exp.JSONFormat: rename_func("TO_JSON_STRING"), +408 exp.Max: max_or_greatest, +409 exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)), +410 exp.MD5Digest: rename_func("MD5"), +411 exp.Min: min_or_least, +412 exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}", +413 exp.RegexpExtract: lambda self, e: self.func( +414 "REGEXP_EXTRACT", +415 e.this, +416 e.expression, +417 e.args.get("position"), +418 e.args.get("occurrence"), +419 ), +420 exp.RegexpReplace: regexp_replace_sql, +421 exp.RegexpLike: rename_func("REGEXP_CONTAINS"), +422 exp.ReturnsProperty: _returnsproperty_sql, +423 exp.Select: transforms.preprocess( +424 [ +425 transforms.explode_to_unnest, +426 _unqualify_unnest, +427 transforms.eliminate_distinct_on, +428 _alias_ordered_group, +429 ] +430 ), +431 exp.StabilityProperty: lambda self, e: f"DETERMINISTIC" +432 if e.name == "IMMUTABLE" +433 else "NOT DETERMINISTIC", +434 exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})", +435 exp.StrToTime: lambda self, e: self.func( +436 "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone") +437 ), +438 exp.TimeAdd: _date_add_sql("TIME", "ADD"), +439 exp.TimeSub: _date_add_sql("TIME", "SUB"), +440 exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"), +441 exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"), +442 exp.TimeStrToTime: timestrtotime_sql, +443 exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression), +444 exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"), +445 exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"), +446 exp.Unhex: rename_func("FROM_HEX"), +447 exp.Values: _derived_table_values_to_unnest, +448 exp.VariancePop: rename_func("VAR_POP"), +449 } +450 +451 TYPE_MAPPING = { +452 **generator.Generator.TYPE_MAPPING, +453 exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC", +454 exp.DataType.Type.BIGINT: "INT64", +455 exp.DataType.Type.BINARY: "BYTES", +456 exp.DataType.Type.BOOLEAN: "BOOL", +457 exp.DataType.Type.CHAR: "STRING", +458 exp.DataType.Type.DECIMAL: "NUMERIC", +459 exp.DataType.Type.DOUBLE: "FLOAT64", +460 exp.DataType.Type.FLOAT: "FLOAT64", +461 exp.DataType.Type.INT: "INT64", +462 exp.DataType.Type.NCHAR: "STRING", +463 exp.DataType.Type.NVARCHAR: "STRING", +464 exp.DataType.Type.SMALLINT: "INT64", +465 exp.DataType.Type.TEXT: "STRING", +466 exp.DataType.Type.TIMESTAMP: "DATETIME", +467 exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP", +468 exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP", +469 exp.DataType.Type.TINYINT: "INT64", +470 exp.DataType.Type.VARBINARY: "BYTES", +471 exp.DataType.Type.VARCHAR: "STRING", +472 exp.DataType.Type.VARIANT: "ANY TYPE", +473 } +474 +475 PROPERTIES_LOCATION = { +476 **generator.Generator.PROPERTIES_LOCATION, +477 exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA, +478 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, +479 } +480 +481 # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords +482 RESERVED_KEYWORDS = { +483 *generator.Generator.RESERVED_KEYWORDS, +484 "all", +485 "and", +486 "any", +487 "array", +488 "as", +489 "asc", +490 "assert_rows_modified", +491 "at", +492 "between", +493 "by", +494 "case", +495 "cast", +496 "collate", +497 "contains", +498 "create", +499 "cross", +500 "cube", +501 "current", +502 "default", +503 "define", +504 "desc", +505 "distinct", +506 "else", +507 "end", +508 "enum", +509 "escape", +510 "except", +511 "exclude", +512 "exists", +513 "extract", +514 "false", +515 "fetch", +516 "following", +517 "for", +518 "from", +519 "full", +520 "group", +521 "grouping", +522 "groups", +523 "hash", +524 "having", +525 "if", +526 "ignore", +527 "in", +528 "inner", +529 "intersect", +530 "interval", +531 "into", +532 "is", +533 "join", +534 "lateral", +535 "left", +536 "like", +537 "limit", +538 "lookup", +539 "merge", +540 "natural", +541 "new", +542 "no", +543 "not", +544 "null", +545 "nulls", +546 "of", +547 "on", +548 "or", +549 "order", +550 "outer", +551 "over", +552 "partition", +553 "preceding", +554 "proto", +555 "qualify", +556 "range", +557 "recursive", +558 "respect", +559 "right", +560 "rollup", +561 "rows", +562 "select", +563 "set", +564 "some", +565 "struct", +566 "tablesample", +567 "then", +568 "to", +569 "treat", +570 "true", +571 "unbounded", +572 "union", +573 "unnest", +574 "using", +575 "when", +576 "where", +577 "window", +578 "with", +579 "within", +580 } 581 -582 # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]). -583 # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included. -584 if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"): -585 return self.func( -586 "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone")) -587 ) -588 -589 return super().attimezone_sql(expression) -590 -591 def trycast_sql(self, expression: exp.TryCast) -> str: -592 return self.cast_sql(expression, safe_prefix="SAFE_") +582 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: +583 parent = expression.parent +584 +585 # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]). +586 # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included. +587 if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"): +588 return self.func( +589 "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone")) +590 ) +591 +592 return super().attimezone_sql(expression) 593 -594 def cte_sql(self, expression: exp.CTE) -> str: -595 if expression.alias_column_names: -596 self.unsupported("Column names in CTE definition are not supported.") -597 return super().cte_sql(expression) -598 -599 def array_sql(self, expression: exp.Array) -> str: -600 first_arg = seq_get(expression.expressions, 0) -601 if isinstance(first_arg, exp.Subqueryable): -602 return f"ARRAY{self.wrap(self.sql(first_arg))}" -603 -604 return inline_array_sql(self, expression) -605 -606 def transaction_sql(self, *_) -> str: -607 return "BEGIN TRANSACTION" +594 def trycast_sql(self, expression: exp.TryCast) -> str: +595 return self.cast_sql(expression, safe_prefix="SAFE_") +596 +597 def cte_sql(self, expression: exp.CTE) -> str: +598 if expression.alias_column_names: +599 self.unsupported("Column names in CTE definition are not supported.") +600 return super().cte_sql(expression) +601 +602 def array_sql(self, expression: exp.Array) -> str: +603 first_arg = seq_get(expression.expressions, 0) +604 if isinstance(first_arg, exp.Subqueryable): +605 return f"ARRAY{self.wrap(self.sql(first_arg))}" +606 +607 return inline_array_sql(self, expression) 608 -609 def commit_sql(self, *_) -> str: -610 return "COMMIT TRANSACTION" +609 def transaction_sql(self, *_) -> str: +610 return "BEGIN TRANSACTION" 611 -612 def rollback_sql(self, *_) -> str: -613 return "ROLLBACK TRANSACTION" +612 def commit_sql(self, *_) -> str: +613 return "COMMIT TRANSACTION" 614 -615 def in_unnest_op(self, expression: exp.Unnest) -> str: -616 return self.sql(expression) +615 def rollback_sql(self, *_) -> str: +616 return "ROLLBACK TRANSACTION" 617 -618 def except_op(self, expression: exp.Except) -> str: -619 if not expression.args.get("distinct", False): -620 self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery") -621 return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}" -622 -623 def intersect_op(self, expression: exp.Intersect) -> str: -624 if not expression.args.get("distinct", False): -625 self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery") -626 return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}" -627 -628 def with_properties(self, properties: exp.Properties) -> str: -629 return self.properties(properties, prefix=self.seg("OPTIONS")) +618 def in_unnest_op(self, expression: exp.Unnest) -> str: +619 return self.sql(expression) +620 +621 def except_op(self, expression: exp.Except) -> str: +622 if not expression.args.get("distinct", False): +623 self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery") +624 return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}" +625 +626 def intersect_op(self, expression: exp.Intersect) -> str: +627 if not expression.args.get("distinct", False): +628 self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery") +629 return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}" +630 +631 def with_properties(self, properties: exp.Properties) -> str: +632 return self.properties(properties, prefix=self.seg("OPTIONS")) @@ -1000,453 +1003,454 @@ -
184class BigQuery(Dialect):
-185    UNNEST_COLUMN_ONLY = True
-186
-187    # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
-188    RESOLVES_IDENTIFIERS_AS_UPPERCASE = None
-189
-190    # bigquery udfs are case sensitive
-191    NORMALIZE_FUNCTIONS = False
-192
-193    TIME_MAPPING = {
-194        "%D": "%m/%d/%y",
-195    }
-196
-197    FORMAT_MAPPING = {
-198        "DD": "%d",
-199        "MM": "%m",
-200        "MON": "%b",
-201        "MONTH": "%B",
-202        "YYYY": "%Y",
-203        "YY": "%y",
-204        "HH": "%I",
-205        "HH12": "%I",
-206        "HH24": "%H",
-207        "MI": "%M",
-208        "SS": "%S",
-209        "SSSSS": "%f",
-210        "TZH": "%z",
-211    }
-212
-213    @classmethod
-214    def normalize_identifier(cls, expression: E) -> E:
-215        # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least).
-216        # The following check is essentially a heuristic to detect tables based on whether or
-217        # not they're qualified.
-218        if isinstance(expression, exp.Identifier):
-219            parent = expression.parent
-220
-221            while isinstance(parent, exp.Dot):
-222                parent = parent.parent
-223
-224            if (
-225                not isinstance(parent, exp.UserDefinedFunction)
-226                and not (isinstance(parent, exp.Table) and parent.db)
-227                and not expression.meta.get("is_table")
-228            ):
-229                expression.set("this", expression.this.lower())
-230
-231        return expression
+            
186class BigQuery(Dialect):
+187    UNNEST_COLUMN_ONLY = True
+188
+189    # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
+190    RESOLVES_IDENTIFIERS_AS_UPPERCASE = None
+191
+192    # bigquery udfs are case sensitive
+193    NORMALIZE_FUNCTIONS = False
+194
+195    TIME_MAPPING = {
+196        "%D": "%m/%d/%y",
+197    }
+198
+199    FORMAT_MAPPING = {
+200        "DD": "%d",
+201        "MM": "%m",
+202        "MON": "%b",
+203        "MONTH": "%B",
+204        "YYYY": "%Y",
+205        "YY": "%y",
+206        "HH": "%I",
+207        "HH12": "%I",
+208        "HH24": "%H",
+209        "MI": "%M",
+210        "SS": "%S",
+211        "SSSSS": "%f",
+212        "TZH": "%z",
+213    }
+214
+215    @classmethod
+216    def normalize_identifier(cls, expression: E) -> E:
+217        # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least).
+218        # The following check is essentially a heuristic to detect tables based on whether or
+219        # not they're qualified.
+220        if isinstance(expression, exp.Identifier):
+221            parent = expression.parent
+222
+223            while isinstance(parent, exp.Dot):
+224                parent = parent.parent
+225
+226            if (
+227                not isinstance(parent, exp.UserDefinedFunction)
+228                and not (isinstance(parent, exp.Table) and parent.db)
+229                and not expression.meta.get("is_table")
+230            ):
+231                expression.set("this", expression.this.lower())
 232
-233    class Tokenizer(tokens.Tokenizer):
-234        QUOTES = ["'", '"', '"""', "'''"]
-235        COMMENTS = ["--", "#", ("/*", "*/")]
-236        IDENTIFIERS = ["`"]
-237        STRING_ESCAPES = ["\\"]
-238
-239        HEX_STRINGS = [("0x", ""), ("0X", "")]
+233        return expression
+234
+235    class Tokenizer(tokens.Tokenizer):
+236        QUOTES = ["'", '"', '"""', "'''"]
+237        COMMENTS = ["--", "#", ("/*", "*/")]
+238        IDENTIFIERS = ["`"]
+239        STRING_ESCAPES = ["\\"]
 240
-241        BYTE_STRINGS = [
-242            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
-243        ]
-244
-245        RAW_STRINGS = [
-246            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
-247        ]
-248
-249        KEYWORDS = {
-250            **tokens.Tokenizer.KEYWORDS,
-251            "ANY TYPE": TokenType.VARIANT,
-252            "BEGIN": TokenType.COMMAND,
-253            "BEGIN TRANSACTION": TokenType.BEGIN,
-254            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
-255            "BYTES": TokenType.BINARY,
-256            "DECLARE": TokenType.COMMAND,
-257            "FLOAT64": TokenType.DOUBLE,
-258            "INT64": TokenType.BIGINT,
-259            "RECORD": TokenType.STRUCT,
-260            "TIMESTAMP": TokenType.TIMESTAMPTZ,
-261            "NOT DETERMINISTIC": TokenType.VOLATILE,
-262            "UNKNOWN": TokenType.NULL,
-263        }
-264        KEYWORDS.pop("DIV")
-265
-266    class Parser(parser.Parser):
-267        PREFIXED_PIVOT_COLUMNS = True
-268
-269        LOG_BASE_FIRST = False
-270        LOG_DEFAULTS_TO_LN = True
-271
-272        FUNCTIONS = {
-273            **parser.Parser.FUNCTIONS,
-274            "DATE": _parse_date,
-275            "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd),
-276            "DATE_SUB": parse_date_delta_with_interval(exp.DateSub),
-277            "DATE_TRUNC": lambda args: exp.DateTrunc(
-278                unit=exp.Literal.string(str(seq_get(args, 1))),
-279                this=seq_get(args, 0),
-280            ),
-281            "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd),
-282            "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub),
-283            "DIV": lambda args: exp.IntDiv(this=seq_get(args, 0), expression=seq_get(args, 1)),
-284            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
-285            "MD5": exp.MD5Digest.from_arg_list,
-286            "TO_HEX": _parse_to_hex,
-287            "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")(
-288                [seq_get(args, 1), seq_get(args, 0)]
-289            ),
-290            "PARSE_TIMESTAMP": _parse_timestamp,
-291            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
-292            "REGEXP_EXTRACT": lambda args: exp.RegexpExtract(
-293                this=seq_get(args, 0),
-294                expression=seq_get(args, 1),
-295                position=seq_get(args, 2),
-296                occurrence=seq_get(args, 3),
-297                group=exp.Literal.number(1)
-298                if re.compile(str(seq_get(args, 1))).groups == 1
-299                else None,
-300            ),
-301            "SPLIT": lambda args: exp.Split(
-302                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
-303                this=seq_get(args, 0),
-304                expression=seq_get(args, 1) or exp.Literal.string(","),
-305            ),
-306            "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd),
-307            "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub),
-308            "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd),
-309            "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub),
-310            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
-311        }
-312
-313        FUNCTION_PARSERS = {
-314            **parser.Parser.FUNCTION_PARSERS,
-315            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
-316        }
-317        FUNCTION_PARSERS.pop("TRIM")
-318
-319        NO_PAREN_FUNCTIONS = {
-320            **parser.Parser.NO_PAREN_FUNCTIONS,
-321            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
-322        }
-323
-324        NESTED_TYPE_TOKENS = {
-325            *parser.Parser.NESTED_TYPE_TOKENS,
-326            TokenType.TABLE,
-327        }
-328
-329        ID_VAR_TOKENS = {
-330            *parser.Parser.ID_VAR_TOKENS,
-331            TokenType.VALUES,
-332        }
-333
-334        PROPERTY_PARSERS = {
-335            **parser.Parser.PROPERTY_PARSERS,
-336            "NOT DETERMINISTIC": lambda self: self.expression(
-337                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
-338            ),
-339            "OPTIONS": lambda self: self._parse_with_property(),
-340        }
-341
-342        CONSTRAINT_PARSERS = {
-343            **parser.Parser.CONSTRAINT_PARSERS,
-344            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
-345        }
-346
-347        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
-348            this = super()._parse_table_part(schema=schema)
-349
-350            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
-351            if isinstance(this, exp.Identifier):
-352                table_name = this.name
-353                while self._match(TokenType.DASH, advance=False) and self._next:
-354                    self._advance(2)
-355                    table_name += f"-{self._prev.text}"
-356
-357                this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
+241        HEX_STRINGS = [("0x", ""), ("0X", "")]
+242
+243        BYTE_STRINGS = [
+244            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
+245        ]
+246
+247        RAW_STRINGS = [
+248            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
+249        ]
+250
+251        KEYWORDS = {
+252            **tokens.Tokenizer.KEYWORDS,
+253            "ANY TYPE": TokenType.VARIANT,
+254            "BEGIN": TokenType.COMMAND,
+255            "BEGIN TRANSACTION": TokenType.BEGIN,
+256            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
+257            "BYTES": TokenType.BINARY,
+258            "DECLARE": TokenType.COMMAND,
+259            "FLOAT64": TokenType.DOUBLE,
+260            "INT64": TokenType.BIGINT,
+261            "RECORD": TokenType.STRUCT,
+262            "TIMESTAMP": TokenType.TIMESTAMPTZ,
+263            "NOT DETERMINISTIC": TokenType.VOLATILE,
+264            "UNKNOWN": TokenType.NULL,
+265        }
+266        KEYWORDS.pop("DIV")
+267
+268    class Parser(parser.Parser):
+269        PREFIXED_PIVOT_COLUMNS = True
+270
+271        LOG_BASE_FIRST = False
+272        LOG_DEFAULTS_TO_LN = True
+273
+274        FUNCTIONS = {
+275            **parser.Parser.FUNCTIONS,
+276            "DATE": _parse_date,
+277            "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd),
+278            "DATE_SUB": parse_date_delta_with_interval(exp.DateSub),
+279            "DATE_TRUNC": lambda args: exp.DateTrunc(
+280                unit=exp.Literal.string(str(seq_get(args, 1))),
+281                this=seq_get(args, 0),
+282            ),
+283            "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd),
+284            "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub),
+285            "DIV": binary_from_function(exp.IntDiv),
+286            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
+287            "MD5": exp.MD5Digest.from_arg_list,
+288            "TO_HEX": _parse_to_hex,
+289            "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")(
+290                [seq_get(args, 1), seq_get(args, 0)]
+291            ),
+292            "PARSE_TIMESTAMP": _parse_timestamp,
+293            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
+294            "REGEXP_EXTRACT": lambda args: exp.RegexpExtract(
+295                this=seq_get(args, 0),
+296                expression=seq_get(args, 1),
+297                position=seq_get(args, 2),
+298                occurrence=seq_get(args, 3),
+299                group=exp.Literal.number(1)
+300                if re.compile(str(seq_get(args, 1))).groups == 1
+301                else None,
+302            ),
+303            "SPLIT": lambda args: exp.Split(
+304                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
+305                this=seq_get(args, 0),
+306                expression=seq_get(args, 1) or exp.Literal.string(","),
+307            ),
+308            "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd),
+309            "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub),
+310            "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd),
+311            "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub),
+312            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
+313        }
+314
+315        FUNCTION_PARSERS = {
+316            **parser.Parser.FUNCTION_PARSERS,
+317            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
+318        }
+319        FUNCTION_PARSERS.pop("TRIM")
+320
+321        NO_PAREN_FUNCTIONS = {
+322            **parser.Parser.NO_PAREN_FUNCTIONS,
+323            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
+324        }
+325
+326        NESTED_TYPE_TOKENS = {
+327            *parser.Parser.NESTED_TYPE_TOKENS,
+328            TokenType.TABLE,
+329        }
+330
+331        ID_VAR_TOKENS = {
+332            *parser.Parser.ID_VAR_TOKENS,
+333            TokenType.VALUES,
+334        }
+335
+336        PROPERTY_PARSERS = {
+337            **parser.Parser.PROPERTY_PARSERS,
+338            "NOT DETERMINISTIC": lambda self: self.expression(
+339                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
+340            ),
+341            "OPTIONS": lambda self: self._parse_with_property(),
+342        }
+343
+344        CONSTRAINT_PARSERS = {
+345            **parser.Parser.CONSTRAINT_PARSERS,
+346            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
+347        }
+348
+349        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
+350            this = super()._parse_table_part(schema=schema)
+351
+352            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
+353            if isinstance(this, exp.Identifier):
+354                table_name = this.name
+355                while self._match(TokenType.DASH, advance=False) and self._next:
+356                    self._advance(2)
+357                    table_name += f"-{self._prev.text}"
 358
-359            return this
+359                this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
 360
-361        def _parse_table_parts(self, schema: bool = False) -> exp.Table:
-362            table = super()._parse_table_parts(schema=schema)
-363            if isinstance(table.this, exp.Identifier) and "." in table.name:
-364                catalog, db, this, *rest = (
-365                    t.cast(t.Optional[exp.Expression], exp.to_identifier(x))
-366                    for x in split_num_words(table.name, ".", 3)
-367                )
-368
-369                if rest and this:
-370                    this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
-371
-372                table = exp.Table(this=this, db=db, catalog=catalog)
+361            return this
+362
+363        def _parse_table_parts(self, schema: bool = False) -> exp.Table:
+364            table = super()._parse_table_parts(schema=schema)
+365            if isinstance(table.this, exp.Identifier) and "." in table.name:
+366                catalog, db, this, *rest = (
+367                    t.cast(t.Optional[exp.Expression], exp.to_identifier(x))
+368                    for x in split_num_words(table.name, ".", 3)
+369                )
+370
+371                if rest and this:
+372                    this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
 373
-374            return table
+374                table = exp.Table(this=this, db=db, catalog=catalog)
 375
-376    class Generator(generator.Generator):
-377        EXPLICIT_UNION = True
-378        INTERVAL_ALLOWS_PLURAL_FORM = False
-379        JOIN_HINTS = False
-380        QUERY_HINTS = False
-381        TABLE_HINTS = False
-382        LIMIT_FETCH = "LIMIT"
-383        RENAME_TABLE_WITH_DB = False
-384        ESCAPE_LINE_BREAK = True
-385
-386        TRANSFORMS = {
-387            **generator.Generator.TRANSFORMS,
-388            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
-389            exp.ArraySize: rename_func("ARRAY_LENGTH"),
-390            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
-391            exp.Create: _create_sql,
-392            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
-393            exp.DateAdd: _date_add_sql("DATE", "ADD"),
-394            exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})",
-395            exp.DateFromParts: rename_func("DATE"),
-396            exp.DateStrToDate: datestrtodate_sql,
-397            exp.DateSub: _date_add_sql("DATE", "SUB"),
-398            exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"),
-399            exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"),
-400            exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")),
-401            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
-402            exp.GroupConcat: rename_func("STRING_AGG"),
-403            exp.Hex: rename_func("TO_HEX"),
-404            exp.ILike: no_ilike_sql,
-405            exp.IntDiv: rename_func("DIV"),
-406            exp.JSONFormat: rename_func("TO_JSON_STRING"),
-407            exp.Max: max_or_greatest,
-408            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
-409            exp.MD5Digest: rename_func("MD5"),
-410            exp.Min: min_or_least,
-411            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
-412            exp.RegexpExtract: lambda self, e: self.func(
-413                "REGEXP_EXTRACT",
-414                e.this,
-415                e.expression,
-416                e.args.get("position"),
-417                e.args.get("occurrence"),
-418            ),
-419            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
-420            exp.ReturnsProperty: _returnsproperty_sql,
-421            exp.Select: transforms.preprocess(
-422                [
-423                    transforms.explode_to_unnest,
-424                    _unqualify_unnest,
-425                    transforms.eliminate_distinct_on,
-426                    _alias_ordered_group,
-427                ]
-428            ),
-429            exp.StabilityProperty: lambda self, e: f"DETERMINISTIC"
-430            if e.name == "IMMUTABLE"
-431            else "NOT DETERMINISTIC",
-432            exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})",
-433            exp.StrToTime: lambda self, e: self.func(
-434                "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone")
-435            ),
-436            exp.TimeAdd: _date_add_sql("TIME", "ADD"),
-437            exp.TimeSub: _date_add_sql("TIME", "SUB"),
-438            exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"),
-439            exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"),
-440            exp.TimeStrToTime: timestrtotime_sql,
-441            exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression),
-442            exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"),
-443            exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"),
-444            exp.Unhex: rename_func("FROM_HEX"),
-445            exp.Values: _derived_table_values_to_unnest,
-446            exp.VariancePop: rename_func("VAR_POP"),
-447        }
-448
-449        TYPE_MAPPING = {
-450            **generator.Generator.TYPE_MAPPING,
-451            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
-452            exp.DataType.Type.BIGINT: "INT64",
-453            exp.DataType.Type.BINARY: "BYTES",
-454            exp.DataType.Type.BOOLEAN: "BOOL",
-455            exp.DataType.Type.CHAR: "STRING",
-456            exp.DataType.Type.DECIMAL: "NUMERIC",
-457            exp.DataType.Type.DOUBLE: "FLOAT64",
-458            exp.DataType.Type.FLOAT: "FLOAT64",
-459            exp.DataType.Type.INT: "INT64",
-460            exp.DataType.Type.NCHAR: "STRING",
-461            exp.DataType.Type.NVARCHAR: "STRING",
-462            exp.DataType.Type.SMALLINT: "INT64",
-463            exp.DataType.Type.TEXT: "STRING",
-464            exp.DataType.Type.TIMESTAMP: "DATETIME",
-465            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
-466            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
-467            exp.DataType.Type.TINYINT: "INT64",
-468            exp.DataType.Type.VARBINARY: "BYTES",
-469            exp.DataType.Type.VARCHAR: "STRING",
-470            exp.DataType.Type.VARIANT: "ANY TYPE",
-471        }
-472
-473        PROPERTIES_LOCATION = {
-474            **generator.Generator.PROPERTIES_LOCATION,
-475            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
-476            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
-477        }
-478
-479        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
-480        RESERVED_KEYWORDS = {
-481            *generator.Generator.RESERVED_KEYWORDS,
-482            "all",
-483            "and",
-484            "any",
-485            "array",
-486            "as",
-487            "asc",
-488            "assert_rows_modified",
-489            "at",
-490            "between",
-491            "by",
-492            "case",
-493            "cast",
-494            "collate",
-495            "contains",
-496            "create",
-497            "cross",
-498            "cube",
-499            "current",
-500            "default",
-501            "define",
-502            "desc",
-503            "distinct",
-504            "else",
-505            "end",
-506            "enum",
-507            "escape",
-508            "except",
-509            "exclude",
-510            "exists",
-511            "extract",
-512            "false",
-513            "fetch",
-514            "following",
-515            "for",
-516            "from",
-517            "full",
-518            "group",
-519            "grouping",
-520            "groups",
-521            "hash",
-522            "having",
-523            "if",
-524            "ignore",
-525            "in",
-526            "inner",
-527            "intersect",
-528            "interval",
-529            "into",
-530            "is",
-531            "join",
-532            "lateral",
-533            "left",
-534            "like",
-535            "limit",
-536            "lookup",
-537            "merge",
-538            "natural",
-539            "new",
-540            "no",
-541            "not",
-542            "null",
-543            "nulls",
-544            "of",
-545            "on",
-546            "or",
-547            "order",
-548            "outer",
-549            "over",
-550            "partition",
-551            "preceding",
-552            "proto",
-553            "qualify",
-554            "range",
-555            "recursive",
-556            "respect",
-557            "right",
-558            "rollup",
-559            "rows",
-560            "select",
-561            "set",
-562            "some",
-563            "struct",
-564            "tablesample",
-565            "then",
-566            "to",
-567            "treat",
-568            "true",
-569            "unbounded",
-570            "union",
-571            "unnest",
-572            "using",
-573            "when",
-574            "where",
-575            "window",
-576            "with",
-577            "within",
-578        }
-579
-580        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
-581            parent = expression.parent
+376            return table
+377
+378    class Generator(generator.Generator):
+379        EXPLICIT_UNION = True
+380        INTERVAL_ALLOWS_PLURAL_FORM = False
+381        JOIN_HINTS = False
+382        QUERY_HINTS = False
+383        TABLE_HINTS = False
+384        LIMIT_FETCH = "LIMIT"
+385        RENAME_TABLE_WITH_DB = False
+386        ESCAPE_LINE_BREAK = True
+387
+388        TRANSFORMS = {
+389            **generator.Generator.TRANSFORMS,
+390            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
+391            exp.ArraySize: rename_func("ARRAY_LENGTH"),
+392            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
+393            exp.Create: _create_sql,
+394            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
+395            exp.DateAdd: _date_add_sql("DATE", "ADD"),
+396            exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})",
+397            exp.DateFromParts: rename_func("DATE"),
+398            exp.DateStrToDate: datestrtodate_sql,
+399            exp.DateSub: _date_add_sql("DATE", "SUB"),
+400            exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"),
+401            exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"),
+402            exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")),
+403            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
+404            exp.GroupConcat: rename_func("STRING_AGG"),
+405            exp.Hex: rename_func("TO_HEX"),
+406            exp.ILike: no_ilike_sql,
+407            exp.IntDiv: rename_func("DIV"),
+408            exp.JSONFormat: rename_func("TO_JSON_STRING"),
+409            exp.Max: max_or_greatest,
+410            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
+411            exp.MD5Digest: rename_func("MD5"),
+412            exp.Min: min_or_least,
+413            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
+414            exp.RegexpExtract: lambda self, e: self.func(
+415                "REGEXP_EXTRACT",
+416                e.this,
+417                e.expression,
+418                e.args.get("position"),
+419                e.args.get("occurrence"),
+420            ),
+421            exp.RegexpReplace: regexp_replace_sql,
+422            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
+423            exp.ReturnsProperty: _returnsproperty_sql,
+424            exp.Select: transforms.preprocess(
+425                [
+426                    transforms.explode_to_unnest,
+427                    _unqualify_unnest,
+428                    transforms.eliminate_distinct_on,
+429                    _alias_ordered_group,
+430                ]
+431            ),
+432            exp.StabilityProperty: lambda self, e: f"DETERMINISTIC"
+433            if e.name == "IMMUTABLE"
+434            else "NOT DETERMINISTIC",
+435            exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})",
+436            exp.StrToTime: lambda self, e: self.func(
+437                "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone")
+438            ),
+439            exp.TimeAdd: _date_add_sql("TIME", "ADD"),
+440            exp.TimeSub: _date_add_sql("TIME", "SUB"),
+441            exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"),
+442            exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"),
+443            exp.TimeStrToTime: timestrtotime_sql,
+444            exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression),
+445            exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"),
+446            exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"),
+447            exp.Unhex: rename_func("FROM_HEX"),
+448            exp.Values: _derived_table_values_to_unnest,
+449            exp.VariancePop: rename_func("VAR_POP"),
+450        }
+451
+452        TYPE_MAPPING = {
+453            **generator.Generator.TYPE_MAPPING,
+454            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
+455            exp.DataType.Type.BIGINT: "INT64",
+456            exp.DataType.Type.BINARY: "BYTES",
+457            exp.DataType.Type.BOOLEAN: "BOOL",
+458            exp.DataType.Type.CHAR: "STRING",
+459            exp.DataType.Type.DECIMAL: "NUMERIC",
+460            exp.DataType.Type.DOUBLE: "FLOAT64",
+461            exp.DataType.Type.FLOAT: "FLOAT64",
+462            exp.DataType.Type.INT: "INT64",
+463            exp.DataType.Type.NCHAR: "STRING",
+464            exp.DataType.Type.NVARCHAR: "STRING",
+465            exp.DataType.Type.SMALLINT: "INT64",
+466            exp.DataType.Type.TEXT: "STRING",
+467            exp.DataType.Type.TIMESTAMP: "DATETIME",
+468            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
+469            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
+470            exp.DataType.Type.TINYINT: "INT64",
+471            exp.DataType.Type.VARBINARY: "BYTES",
+472            exp.DataType.Type.VARCHAR: "STRING",
+473            exp.DataType.Type.VARIANT: "ANY TYPE",
+474        }
+475
+476        PROPERTIES_LOCATION = {
+477            **generator.Generator.PROPERTIES_LOCATION,
+478            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
+479            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
+480        }
+481
+482        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
+483        RESERVED_KEYWORDS = {
+484            *generator.Generator.RESERVED_KEYWORDS,
+485            "all",
+486            "and",
+487            "any",
+488            "array",
+489            "as",
+490            "asc",
+491            "assert_rows_modified",
+492            "at",
+493            "between",
+494            "by",
+495            "case",
+496            "cast",
+497            "collate",
+498            "contains",
+499            "create",
+500            "cross",
+501            "cube",
+502            "current",
+503            "default",
+504            "define",
+505            "desc",
+506            "distinct",
+507            "else",
+508            "end",
+509            "enum",
+510            "escape",
+511            "except",
+512            "exclude",
+513            "exists",
+514            "extract",
+515            "false",
+516            "fetch",
+517            "following",
+518            "for",
+519            "from",
+520            "full",
+521            "group",
+522            "grouping",
+523            "groups",
+524            "hash",
+525            "having",
+526            "if",
+527            "ignore",
+528            "in",
+529            "inner",
+530            "intersect",
+531            "interval",
+532            "into",
+533            "is",
+534            "join",
+535            "lateral",
+536            "left",
+537            "like",
+538            "limit",
+539            "lookup",
+540            "merge",
+541            "natural",
+542            "new",
+543            "no",
+544            "not",
+545            "null",
+546            "nulls",
+547            "of",
+548            "on",
+549            "or",
+550            "order",
+551            "outer",
+552            "over",
+553            "partition",
+554            "preceding",
+555            "proto",
+556            "qualify",
+557            "range",
+558            "recursive",
+559            "respect",
+560            "right",
+561            "rollup",
+562            "rows",
+563            "select",
+564            "set",
+565            "some",
+566            "struct",
+567            "tablesample",
+568            "then",
+569            "to",
+570            "treat",
+571            "true",
+572            "unbounded",
+573            "union",
+574            "unnest",
+575            "using",
+576            "when",
+577            "where",
+578            "window",
+579            "with",
+580            "within",
+581        }
 582
-583            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
-584            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
-585            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
-586                return self.func(
-587                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
-588                )
-589
-590            return super().attimezone_sql(expression)
-591
-592        def trycast_sql(self, expression: exp.TryCast) -> str:
-593            return self.cast_sql(expression, safe_prefix="SAFE_")
+583        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
+584            parent = expression.parent
+585
+586            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
+587            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
+588            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
+589                return self.func(
+590                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
+591                )
+592
+593            return super().attimezone_sql(expression)
 594
-595        def cte_sql(self, expression: exp.CTE) -> str:
-596            if expression.alias_column_names:
-597                self.unsupported("Column names in CTE definition are not supported.")
-598            return super().cte_sql(expression)
-599
-600        def array_sql(self, expression: exp.Array) -> str:
-601            first_arg = seq_get(expression.expressions, 0)
-602            if isinstance(first_arg, exp.Subqueryable):
-603                return f"ARRAY{self.wrap(self.sql(first_arg))}"
-604
-605            return inline_array_sql(self, expression)
-606
-607        def transaction_sql(self, *_) -> str:
-608            return "BEGIN TRANSACTION"
+595        def trycast_sql(self, expression: exp.TryCast) -> str:
+596            return self.cast_sql(expression, safe_prefix="SAFE_")
+597
+598        def cte_sql(self, expression: exp.CTE) -> str:
+599            if expression.alias_column_names:
+600                self.unsupported("Column names in CTE definition are not supported.")
+601            return super().cte_sql(expression)
+602
+603        def array_sql(self, expression: exp.Array) -> str:
+604            first_arg = seq_get(expression.expressions, 0)
+605            if isinstance(first_arg, exp.Subqueryable):
+606                return f"ARRAY{self.wrap(self.sql(first_arg))}"
+607
+608            return inline_array_sql(self, expression)
 609
-610        def commit_sql(self, *_) -> str:
-611            return "COMMIT TRANSACTION"
+610        def transaction_sql(self, *_) -> str:
+611            return "BEGIN TRANSACTION"
 612
-613        def rollback_sql(self, *_) -> str:
-614            return "ROLLBACK TRANSACTION"
+613        def commit_sql(self, *_) -> str:
+614            return "COMMIT TRANSACTION"
 615
-616        def in_unnest_op(self, expression: exp.Unnest) -> str:
-617            return self.sql(expression)
+616        def rollback_sql(self, *_) -> str:
+617            return "ROLLBACK TRANSACTION"
 618
-619        def except_op(self, expression: exp.Except) -> str:
-620            if not expression.args.get("distinct", False):
-621                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
-622            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
-623
-624        def intersect_op(self, expression: exp.Intersect) -> str:
-625            if not expression.args.get("distinct", False):
-626                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
-627            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
-628
-629        def with_properties(self, properties: exp.Properties) -> str:
-630            return self.properties(properties, prefix=self.seg("OPTIONS"))
+619        def in_unnest_op(self, expression: exp.Unnest) -> str:
+620            return self.sql(expression)
+621
+622        def except_op(self, expression: exp.Except) -> str:
+623            if not expression.args.get("distinct", False):
+624                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
+625            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+626
+627        def intersect_op(self, expression: exp.Intersect) -> str:
+628            if not expression.args.get("distinct", False):
+629                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
+630            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+631
+632        def with_properties(self, properties: exp.Properties) -> str:
+633            return self.properties(properties, prefix=self.seg("OPTIONS"))
 
@@ -1525,25 +1529,25 @@
-
213    @classmethod
-214    def normalize_identifier(cls, expression: E) -> E:
-215        # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least).
-216        # The following check is essentially a heuristic to detect tables based on whether or
-217        # not they're qualified.
-218        if isinstance(expression, exp.Identifier):
-219            parent = expression.parent
-220
-221            while isinstance(parent, exp.Dot):
-222                parent = parent.parent
-223
-224            if (
-225                not isinstance(parent, exp.UserDefinedFunction)
-226                and not (isinstance(parent, exp.Table) and parent.db)
-227                and not expression.meta.get("is_table")
-228            ):
-229                expression.set("this", expression.this.lower())
-230
-231        return expression
+            
215    @classmethod
+216    def normalize_identifier(cls, expression: E) -> E:
+217        # In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least).
+218        # The following check is essentially a heuristic to detect tables based on whether or
+219        # not they're qualified.
+220        if isinstance(expression, exp.Identifier):
+221            parent = expression.parent
+222
+223            while isinstance(parent, exp.Dot):
+224                parent = parent.parent
+225
+226            if (
+227                not isinstance(parent, exp.UserDefinedFunction)
+228                and not (isinstance(parent, exp.Table) and parent.db)
+229                and not expression.meta.get("is_table")
+230            ):
+231                expression.set("this", expression.this.lower())
+232
+233        return expression
 
@@ -1800,38 +1804,38 @@ they will be normalized regardless of being quoted or not.

-
233    class Tokenizer(tokens.Tokenizer):
-234        QUOTES = ["'", '"', '"""', "'''"]
-235        COMMENTS = ["--", "#", ("/*", "*/")]
-236        IDENTIFIERS = ["`"]
-237        STRING_ESCAPES = ["\\"]
-238
-239        HEX_STRINGS = [("0x", ""), ("0X", "")]
+            
235    class Tokenizer(tokens.Tokenizer):
+236        QUOTES = ["'", '"', '"""', "'''"]
+237        COMMENTS = ["--", "#", ("/*", "*/")]
+238        IDENTIFIERS = ["`"]
+239        STRING_ESCAPES = ["\\"]
 240
-241        BYTE_STRINGS = [
-242            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
-243        ]
-244
-245        RAW_STRINGS = [
-246            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
-247        ]
-248
-249        KEYWORDS = {
-250            **tokens.Tokenizer.KEYWORDS,
-251            "ANY TYPE": TokenType.VARIANT,
-252            "BEGIN": TokenType.COMMAND,
-253            "BEGIN TRANSACTION": TokenType.BEGIN,
-254            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
-255            "BYTES": TokenType.BINARY,
-256            "DECLARE": TokenType.COMMAND,
-257            "FLOAT64": TokenType.DOUBLE,
-258            "INT64": TokenType.BIGINT,
-259            "RECORD": TokenType.STRUCT,
-260            "TIMESTAMP": TokenType.TIMESTAMPTZ,
-261            "NOT DETERMINISTIC": TokenType.VOLATILE,
-262            "UNKNOWN": TokenType.NULL,
-263        }
-264        KEYWORDS.pop("DIV")
+241        HEX_STRINGS = [("0x", ""), ("0X", "")]
+242
+243        BYTE_STRINGS = [
+244            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("b", "B")
+245        ]
+246
+247        RAW_STRINGS = [
+248            (prefix + q, q) for q in t.cast(t.List[str], QUOTES) for prefix in ("r", "R")
+249        ]
+250
+251        KEYWORDS = {
+252            **tokens.Tokenizer.KEYWORDS,
+253            "ANY TYPE": TokenType.VARIANT,
+254            "BEGIN": TokenType.COMMAND,
+255            "BEGIN TRANSACTION": TokenType.BEGIN,
+256            "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
+257            "BYTES": TokenType.BINARY,
+258            "DECLARE": TokenType.COMMAND,
+259            "FLOAT64": TokenType.DOUBLE,
+260            "INT64": TokenType.BIGINT,
+261            "RECORD": TokenType.STRUCT,
+262            "TIMESTAMP": TokenType.TIMESTAMPTZ,
+263            "NOT DETERMINISTIC": TokenType.VOLATILE,
+264            "UNKNOWN": TokenType.NULL,
+265        }
+266        KEYWORDS.pop("DIV")
 
@@ -1972,115 +1976,115 @@ they will be normalized regardless of being quoted or not.

-
266    class Parser(parser.Parser):
-267        PREFIXED_PIVOT_COLUMNS = True
-268
-269        LOG_BASE_FIRST = False
-270        LOG_DEFAULTS_TO_LN = True
-271
-272        FUNCTIONS = {
-273            **parser.Parser.FUNCTIONS,
-274            "DATE": _parse_date,
-275            "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd),
-276            "DATE_SUB": parse_date_delta_with_interval(exp.DateSub),
-277            "DATE_TRUNC": lambda args: exp.DateTrunc(
-278                unit=exp.Literal.string(str(seq_get(args, 1))),
-279                this=seq_get(args, 0),
-280            ),
-281            "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd),
-282            "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub),
-283            "DIV": lambda args: exp.IntDiv(this=seq_get(args, 0), expression=seq_get(args, 1)),
-284            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
-285            "MD5": exp.MD5Digest.from_arg_list,
-286            "TO_HEX": _parse_to_hex,
-287            "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")(
-288                [seq_get(args, 1), seq_get(args, 0)]
-289            ),
-290            "PARSE_TIMESTAMP": _parse_timestamp,
-291            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
-292            "REGEXP_EXTRACT": lambda args: exp.RegexpExtract(
-293                this=seq_get(args, 0),
-294                expression=seq_get(args, 1),
-295                position=seq_get(args, 2),
-296                occurrence=seq_get(args, 3),
-297                group=exp.Literal.number(1)
-298                if re.compile(str(seq_get(args, 1))).groups == 1
-299                else None,
-300            ),
-301            "SPLIT": lambda args: exp.Split(
-302                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
-303                this=seq_get(args, 0),
-304                expression=seq_get(args, 1) or exp.Literal.string(","),
-305            ),
-306            "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd),
-307            "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub),
-308            "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd),
-309            "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub),
-310            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
-311        }
-312
-313        FUNCTION_PARSERS = {
-314            **parser.Parser.FUNCTION_PARSERS,
-315            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
-316        }
-317        FUNCTION_PARSERS.pop("TRIM")
-318
-319        NO_PAREN_FUNCTIONS = {
-320            **parser.Parser.NO_PAREN_FUNCTIONS,
-321            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
-322        }
-323
-324        NESTED_TYPE_TOKENS = {
-325            *parser.Parser.NESTED_TYPE_TOKENS,
-326            TokenType.TABLE,
-327        }
-328
-329        ID_VAR_TOKENS = {
-330            *parser.Parser.ID_VAR_TOKENS,
-331            TokenType.VALUES,
-332        }
-333
-334        PROPERTY_PARSERS = {
-335            **parser.Parser.PROPERTY_PARSERS,
-336            "NOT DETERMINISTIC": lambda self: self.expression(
-337                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
-338            ),
-339            "OPTIONS": lambda self: self._parse_with_property(),
-340        }
-341
-342        CONSTRAINT_PARSERS = {
-343            **parser.Parser.CONSTRAINT_PARSERS,
-344            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
-345        }
-346
-347        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
-348            this = super()._parse_table_part(schema=schema)
-349
-350            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
-351            if isinstance(this, exp.Identifier):
-352                table_name = this.name
-353                while self._match(TokenType.DASH, advance=False) and self._next:
-354                    self._advance(2)
-355                    table_name += f"-{self._prev.text}"
-356
-357                this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
+            
268    class Parser(parser.Parser):
+269        PREFIXED_PIVOT_COLUMNS = True
+270
+271        LOG_BASE_FIRST = False
+272        LOG_DEFAULTS_TO_LN = True
+273
+274        FUNCTIONS = {
+275            **parser.Parser.FUNCTIONS,
+276            "DATE": _parse_date,
+277            "DATE_ADD": parse_date_delta_with_interval(exp.DateAdd),
+278            "DATE_SUB": parse_date_delta_with_interval(exp.DateSub),
+279            "DATE_TRUNC": lambda args: exp.DateTrunc(
+280                unit=exp.Literal.string(str(seq_get(args, 1))),
+281                this=seq_get(args, 0),
+282            ),
+283            "DATETIME_ADD": parse_date_delta_with_interval(exp.DatetimeAdd),
+284            "DATETIME_SUB": parse_date_delta_with_interval(exp.DatetimeSub),
+285            "DIV": binary_from_function(exp.IntDiv),
+286            "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
+287            "MD5": exp.MD5Digest.from_arg_list,
+288            "TO_HEX": _parse_to_hex,
+289            "PARSE_DATE": lambda args: format_time_lambda(exp.StrToDate, "bigquery")(
+290                [seq_get(args, 1), seq_get(args, 0)]
+291            ),
+292            "PARSE_TIMESTAMP": _parse_timestamp,
+293            "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
+294            "REGEXP_EXTRACT": lambda args: exp.RegexpExtract(
+295                this=seq_get(args, 0),
+296                expression=seq_get(args, 1),
+297                position=seq_get(args, 2),
+298                occurrence=seq_get(args, 3),
+299                group=exp.Literal.number(1)
+300                if re.compile(str(seq_get(args, 1))).groups == 1
+301                else None,
+302            ),
+303            "SPLIT": lambda args: exp.Split(
+304                # https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split
+305                this=seq_get(args, 0),
+306                expression=seq_get(args, 1) or exp.Literal.string(","),
+307            ),
+308            "TIME_ADD": parse_date_delta_with_interval(exp.TimeAdd),
+309            "TIME_SUB": parse_date_delta_with_interval(exp.TimeSub),
+310            "TIMESTAMP_ADD": parse_date_delta_with_interval(exp.TimestampAdd),
+311            "TIMESTAMP_SUB": parse_date_delta_with_interval(exp.TimestampSub),
+312            "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
+313        }
+314
+315        FUNCTION_PARSERS = {
+316            **parser.Parser.FUNCTION_PARSERS,
+317            "ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
+318        }
+319        FUNCTION_PARSERS.pop("TRIM")
+320
+321        NO_PAREN_FUNCTIONS = {
+322            **parser.Parser.NO_PAREN_FUNCTIONS,
+323            TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
+324        }
+325
+326        NESTED_TYPE_TOKENS = {
+327            *parser.Parser.NESTED_TYPE_TOKENS,
+328            TokenType.TABLE,
+329        }
+330
+331        ID_VAR_TOKENS = {
+332            *parser.Parser.ID_VAR_TOKENS,
+333            TokenType.VALUES,
+334        }
+335
+336        PROPERTY_PARSERS = {
+337            **parser.Parser.PROPERTY_PARSERS,
+338            "NOT DETERMINISTIC": lambda self: self.expression(
+339                exp.StabilityProperty, this=exp.Literal.string("VOLATILE")
+340            ),
+341            "OPTIONS": lambda self: self._parse_with_property(),
+342        }
+343
+344        CONSTRAINT_PARSERS = {
+345            **parser.Parser.CONSTRAINT_PARSERS,
+346            "OPTIONS": lambda self: exp.Properties(expressions=self._parse_with_property()),
+347        }
+348
+349        def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
+350            this = super()._parse_table_part(schema=schema)
+351
+352            # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#table_names
+353            if isinstance(this, exp.Identifier):
+354                table_name = this.name
+355                while self._match(TokenType.DASH, advance=False) and self._next:
+356                    self._advance(2)
+357                    table_name += f"-{self._prev.text}"
 358
-359            return this
+359                this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
 360
-361        def _parse_table_parts(self, schema: bool = False) -> exp.Table:
-362            table = super()._parse_table_parts(schema=schema)
-363            if isinstance(table.this, exp.Identifier) and "." in table.name:
-364                catalog, db, this, *rest = (
-365                    t.cast(t.Optional[exp.Expression], exp.to_identifier(x))
-366                    for x in split_num_words(table.name, ".", 3)
-367                )
-368
-369                if rest and this:
-370                    this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
-371
-372                table = exp.Table(this=this, db=db, catalog=catalog)
+361            return this
+362
+363        def _parse_table_parts(self, schema: bool = False) -> exp.Table:
+364            table = super()._parse_table_parts(schema=schema)
+365            if isinstance(table.this, exp.Identifier) and "." in table.name:
+366                catalog, db, this, *rest = (
+367                    t.cast(t.Optional[exp.Expression], exp.to_identifier(x))
+368                    for x in split_num_words(table.name, ".", 3)
+369                )
+370
+371                if rest and this:
+372                    this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
 373
-374            return table
+374                table = exp.Table(this=this, db=db, catalog=catalog)
+375
+376            return table
 
@@ -2141,7 +2145,7 @@ Default: 3
FUNCTIONS = - {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Concat'>>, 'CONCAT_WS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConcatWs'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <function _parse_date>, 'DATE_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <function parse_date_delta_with_interval.<locals>.func>, '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_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hex'>>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'LAST_DATE_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDateOfMonth'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log'>>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <function BigQuery.Parser.<lambda>>, '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_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeConcat'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SET_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SetAgg'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <function BigQuery.Parser.<lambda>>, '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'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'LIKE': <function parse_like>, 'DIV': <function BigQuery.Parser.<lambda>>, 'GENERATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'TO_HEX': <function _parse_to_hex>, 'PARSE_DATE': <function BigQuery.Parser.<lambda>>, 'PARSE_TIMESTAMP': <function _parse_timestamp>, 'REGEXP_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'TO_JSON_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>} + {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Concat'>>, 'CONCAT_WS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConcatWs'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <function _parse_date>, 'DATE_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <function parse_date_delta_with_interval.<locals>.func>, '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_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hex'>>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'JSON_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'LAST_DATE_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDateOfMonth'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log'>>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <function BigQuery.Parser.<lambda>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeConcat'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SET_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SetAgg'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <function BigQuery.Parser.<lambda>>, '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'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP_ADD': <function parse_date_delta_with_interval.<locals>.func>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_SUB': <function parse_date_delta_with_interval.<locals>.func>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'GLOB': <function Parser.<lambda>>, 'LIKE': <function parse_like>, 'DIV': <function binary_from_function.<locals>.<lambda>>, 'GENERATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'TO_HEX': <function _parse_to_hex>, 'PARSE_DATE': <function BigQuery.Parser.<lambda>>, 'PARSE_TIMESTAMP': <function _parse_timestamp>, 'REGEXP_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'TO_JSON_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>}
@@ -2180,7 +2184,7 @@ Default: 3
NESTED_TYPE_TOKENS = - {<TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>} + {<TokenType.TABLE: 'TABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.MAP: 'MAP'>, <TokenType.NULLABLE: 'NULLABLE'>}
@@ -2193,7 +2197,7 @@ Default: 3
ID_VAR_TOKENS = - {<TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.JSON: 'JSON'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.ALL: 'ALL'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CACHE: 'CACHE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.FALSE: 'FALSE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TIME: 'TIME'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.IS: 'IS'>, <TokenType.DESC: 'DESC'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FULL: 'FULL'>, <TokenType.INT: 'INT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.IF: 'IF'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TEXT: 'TEXT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ROW: 'ROW'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.VAR: 'VAR'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DELETE: 'DELETE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.INT128: 'INT128'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.XML: 'XML'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VIEW: 'VIEW'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TOP: 'TOP'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.JSONB: 'JSONB'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.DATE: 'DATE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.ANY: 'ANY'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ENUM: 'ENUM'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DIV: 'DIV'>, <TokenType.UINT: 'UINT'>, <TokenType.BIT: 'BIT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.ASC: 'ASC'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SET: 'SET'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UUID: 'UUID'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.MAP: 'MAP'>, <TokenType.MERGE: 'MERGE'>, <TokenType.VALUES: 'VALUES'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>} + {<TokenType.PARTITION: 'PARTITION'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.END: 'END'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SUPER: 'SUPER'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MAP: 'MAP'>, <TokenType.LEFT: 'LEFT'>, <TokenType.DATE: 'DATE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.INT: 'INT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.VALUES: 'VALUES'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UINT: 'UINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.IS: 'IS'>, <TokenType.FALSE: 'FALSE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TIME: 'TIME'>, <TokenType.DIV: 'DIV'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.NEXT: 'NEXT'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IF: 'IF'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.FULL: 'FULL'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SOME: 'SOME'>, <TokenType.ASC: 'ASC'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ROW: 'ROW'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.RANGE: 'RANGE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SET: 'SET'>, <TokenType.MERGE: 'MERGE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.INT256: 'INT256'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.VAR: 'VAR'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.INT128: 'INT128'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.JSON: 'JSON'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UUID: 'UUID'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ANY: 'ANY'>, <TokenType.ALL: 'ALL'>, <TokenType.APPLY: 'APPLY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.INET: 'INET'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUE: 'TRUE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FIRST: 'FIRST'>, <TokenType.INDEX: 'INDEX'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.BIT: 'BIT'>, <TokenType.DESC: 'DESC'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.XML: 'XML'>}
@@ -2406,261 +2410,262 @@ Default: 3
-
376    class Generator(generator.Generator):
-377        EXPLICIT_UNION = True
-378        INTERVAL_ALLOWS_PLURAL_FORM = False
-379        JOIN_HINTS = False
-380        QUERY_HINTS = False
-381        TABLE_HINTS = False
-382        LIMIT_FETCH = "LIMIT"
-383        RENAME_TABLE_WITH_DB = False
-384        ESCAPE_LINE_BREAK = True
-385
-386        TRANSFORMS = {
-387            **generator.Generator.TRANSFORMS,
-388            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
-389            exp.ArraySize: rename_func("ARRAY_LENGTH"),
-390            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
-391            exp.Create: _create_sql,
-392            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
-393            exp.DateAdd: _date_add_sql("DATE", "ADD"),
-394            exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})",
-395            exp.DateFromParts: rename_func("DATE"),
-396            exp.DateStrToDate: datestrtodate_sql,
-397            exp.DateSub: _date_add_sql("DATE", "SUB"),
-398            exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"),
-399            exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"),
-400            exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")),
-401            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
-402            exp.GroupConcat: rename_func("STRING_AGG"),
-403            exp.Hex: rename_func("TO_HEX"),
-404            exp.ILike: no_ilike_sql,
-405            exp.IntDiv: rename_func("DIV"),
-406            exp.JSONFormat: rename_func("TO_JSON_STRING"),
-407            exp.Max: max_or_greatest,
-408            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
-409            exp.MD5Digest: rename_func("MD5"),
-410            exp.Min: min_or_least,
-411            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
-412            exp.RegexpExtract: lambda self, e: self.func(
-413                "REGEXP_EXTRACT",
-414                e.this,
-415                e.expression,
-416                e.args.get("position"),
-417                e.args.get("occurrence"),
-418            ),
-419            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
-420            exp.ReturnsProperty: _returnsproperty_sql,
-421            exp.Select: transforms.preprocess(
-422                [
-423                    transforms.explode_to_unnest,
-424                    _unqualify_unnest,
-425                    transforms.eliminate_distinct_on,
-426                    _alias_ordered_group,
-427                ]
-428            ),
-429            exp.StabilityProperty: lambda self, e: f"DETERMINISTIC"
-430            if e.name == "IMMUTABLE"
-431            else "NOT DETERMINISTIC",
-432            exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})",
-433            exp.StrToTime: lambda self, e: self.func(
-434                "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone")
-435            ),
-436            exp.TimeAdd: _date_add_sql("TIME", "ADD"),
-437            exp.TimeSub: _date_add_sql("TIME", "SUB"),
-438            exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"),
-439            exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"),
-440            exp.TimeStrToTime: timestrtotime_sql,
-441            exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression),
-442            exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"),
-443            exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"),
-444            exp.Unhex: rename_func("FROM_HEX"),
-445            exp.Values: _derived_table_values_to_unnest,
-446            exp.VariancePop: rename_func("VAR_POP"),
-447        }
-448
-449        TYPE_MAPPING = {
-450            **generator.Generator.TYPE_MAPPING,
-451            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
-452            exp.DataType.Type.BIGINT: "INT64",
-453            exp.DataType.Type.BINARY: "BYTES",
-454            exp.DataType.Type.BOOLEAN: "BOOL",
-455            exp.DataType.Type.CHAR: "STRING",
-456            exp.DataType.Type.DECIMAL: "NUMERIC",
-457            exp.DataType.Type.DOUBLE: "FLOAT64",
-458            exp.DataType.Type.FLOAT: "FLOAT64",
-459            exp.DataType.Type.INT: "INT64",
-460            exp.DataType.Type.NCHAR: "STRING",
-461            exp.DataType.Type.NVARCHAR: "STRING",
-462            exp.DataType.Type.SMALLINT: "INT64",
-463            exp.DataType.Type.TEXT: "STRING",
-464            exp.DataType.Type.TIMESTAMP: "DATETIME",
-465            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
-466            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
-467            exp.DataType.Type.TINYINT: "INT64",
-468            exp.DataType.Type.VARBINARY: "BYTES",
-469            exp.DataType.Type.VARCHAR: "STRING",
-470            exp.DataType.Type.VARIANT: "ANY TYPE",
-471        }
-472
-473        PROPERTIES_LOCATION = {
-474            **generator.Generator.PROPERTIES_LOCATION,
-475            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
-476            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
-477        }
-478
-479        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
-480        RESERVED_KEYWORDS = {
-481            *generator.Generator.RESERVED_KEYWORDS,
-482            "all",
-483            "and",
-484            "any",
-485            "array",
-486            "as",
-487            "asc",
-488            "assert_rows_modified",
-489            "at",
-490            "between",
-491            "by",
-492            "case",
-493            "cast",
-494            "collate",
-495            "contains",
-496            "create",
-497            "cross",
-498            "cube",
-499            "current",
-500            "default",
-501            "define",
-502            "desc",
-503            "distinct",
-504            "else",
-505            "end",
-506            "enum",
-507            "escape",
-508            "except",
-509            "exclude",
-510            "exists",
-511            "extract",
-512            "false",
-513            "fetch",
-514            "following",
-515            "for",
-516            "from",
-517            "full",
-518            "group",
-519            "grouping",
-520            "groups",
-521            "hash",
-522            "having",
-523            "if",
-524            "ignore",
-525            "in",
-526            "inner",
-527            "intersect",
-528            "interval",
-529            "into",
-530            "is",
-531            "join",
-532            "lateral",
-533            "left",
-534            "like",
-535            "limit",
-536            "lookup",
-537            "merge",
-538            "natural",
-539            "new",
-540            "no",
-541            "not",
-542            "null",
-543            "nulls",
-544            "of",
-545            "on",
-546            "or",
-547            "order",
-548            "outer",
-549            "over",
-550            "partition",
-551            "preceding",
-552            "proto",
-553            "qualify",
-554            "range",
-555            "recursive",
-556            "respect",
-557            "right",
-558            "rollup",
-559            "rows",
-560            "select",
-561            "set",
-562            "some",
-563            "struct",
-564            "tablesample",
-565            "then",
-566            "to",
-567            "treat",
-568            "true",
-569            "unbounded",
-570            "union",
-571            "unnest",
-572            "using",
-573            "when",
-574            "where",
-575            "window",
-576            "with",
-577            "within",
-578        }
-579
-580        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
-581            parent = expression.parent
+            
378    class Generator(generator.Generator):
+379        EXPLICIT_UNION = True
+380        INTERVAL_ALLOWS_PLURAL_FORM = False
+381        JOIN_HINTS = False
+382        QUERY_HINTS = False
+383        TABLE_HINTS = False
+384        LIMIT_FETCH = "LIMIT"
+385        RENAME_TABLE_WITH_DB = False
+386        ESCAPE_LINE_BREAK = True
+387
+388        TRANSFORMS = {
+389            **generator.Generator.TRANSFORMS,
+390            exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
+391            exp.ArraySize: rename_func("ARRAY_LENGTH"),
+392            exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
+393            exp.Create: _create_sql,
+394            exp.CTE: transforms.preprocess([_pushdown_cte_column_names]),
+395            exp.DateAdd: _date_add_sql("DATE", "ADD"),
+396            exp.DateDiff: lambda self, e: f"DATE_DIFF({self.sql(e, 'this')}, {self.sql(e, 'expression')}, {self.sql(e.args.get('unit', 'DAY'))})",
+397            exp.DateFromParts: rename_func("DATE"),
+398            exp.DateStrToDate: datestrtodate_sql,
+399            exp.DateSub: _date_add_sql("DATE", "SUB"),
+400            exp.DatetimeAdd: _date_add_sql("DATETIME", "ADD"),
+401            exp.DatetimeSub: _date_add_sql("DATETIME", "SUB"),
+402            exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, e.text("unit")),
+403            exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
+404            exp.GroupConcat: rename_func("STRING_AGG"),
+405            exp.Hex: rename_func("TO_HEX"),
+406            exp.ILike: no_ilike_sql,
+407            exp.IntDiv: rename_func("DIV"),
+408            exp.JSONFormat: rename_func("TO_JSON_STRING"),
+409            exp.Max: max_or_greatest,
+410            exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
+411            exp.MD5Digest: rename_func("MD5"),
+412            exp.Min: min_or_least,
+413            exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
+414            exp.RegexpExtract: lambda self, e: self.func(
+415                "REGEXP_EXTRACT",
+416                e.this,
+417                e.expression,
+418                e.args.get("position"),
+419                e.args.get("occurrence"),
+420            ),
+421            exp.RegexpReplace: regexp_replace_sql,
+422            exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
+423            exp.ReturnsProperty: _returnsproperty_sql,
+424            exp.Select: transforms.preprocess(
+425                [
+426                    transforms.explode_to_unnest,
+427                    _unqualify_unnest,
+428                    transforms.eliminate_distinct_on,
+429                    _alias_ordered_group,
+430                ]
+431            ),
+432            exp.StabilityProperty: lambda self, e: f"DETERMINISTIC"
+433            if e.name == "IMMUTABLE"
+434            else "NOT DETERMINISTIC",
+435            exp.StrToDate: lambda self, e: f"PARSE_DATE({self.format_time(e)}, {self.sql(e, 'this')})",
+436            exp.StrToTime: lambda self, e: self.func(
+437                "PARSE_TIMESTAMP", self.format_time(e), e.this, e.args.get("zone")
+438            ),
+439            exp.TimeAdd: _date_add_sql("TIME", "ADD"),
+440            exp.TimeSub: _date_add_sql("TIME", "SUB"),
+441            exp.TimestampAdd: _date_add_sql("TIMESTAMP", "ADD"),
+442            exp.TimestampSub: _date_add_sql("TIMESTAMP", "SUB"),
+443            exp.TimeStrToTime: timestrtotime_sql,
+444            exp.Trim: lambda self, e: self.func(f"TRIM", e.this, e.expression),
+445            exp.TsOrDsAdd: _date_add_sql("DATE", "ADD"),
+446            exp.TsOrDsToDate: ts_or_ds_to_date_sql("bigquery"),
+447            exp.Unhex: rename_func("FROM_HEX"),
+448            exp.Values: _derived_table_values_to_unnest,
+449            exp.VariancePop: rename_func("VAR_POP"),
+450        }
+451
+452        TYPE_MAPPING = {
+453            **generator.Generator.TYPE_MAPPING,
+454            exp.DataType.Type.BIGDECIMAL: "BIGNUMERIC",
+455            exp.DataType.Type.BIGINT: "INT64",
+456            exp.DataType.Type.BINARY: "BYTES",
+457            exp.DataType.Type.BOOLEAN: "BOOL",
+458            exp.DataType.Type.CHAR: "STRING",
+459            exp.DataType.Type.DECIMAL: "NUMERIC",
+460            exp.DataType.Type.DOUBLE: "FLOAT64",
+461            exp.DataType.Type.FLOAT: "FLOAT64",
+462            exp.DataType.Type.INT: "INT64",
+463            exp.DataType.Type.NCHAR: "STRING",
+464            exp.DataType.Type.NVARCHAR: "STRING",
+465            exp.DataType.Type.SMALLINT: "INT64",
+466            exp.DataType.Type.TEXT: "STRING",
+467            exp.DataType.Type.TIMESTAMP: "DATETIME",
+468            exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
+469            exp.DataType.Type.TIMESTAMPLTZ: "TIMESTAMP",
+470            exp.DataType.Type.TINYINT: "INT64",
+471            exp.DataType.Type.VARBINARY: "BYTES",
+472            exp.DataType.Type.VARCHAR: "STRING",
+473            exp.DataType.Type.VARIANT: "ANY TYPE",
+474        }
+475
+476        PROPERTIES_LOCATION = {
+477            **generator.Generator.PROPERTIES_LOCATION,
+478            exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
+479            exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
+480        }
+481
+482        # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
+483        RESERVED_KEYWORDS = {
+484            *generator.Generator.RESERVED_KEYWORDS,
+485            "all",
+486            "and",
+487            "any",
+488            "array",
+489            "as",
+490            "asc",
+491            "assert_rows_modified",
+492            "at",
+493            "between",
+494            "by",
+495            "case",
+496            "cast",
+497            "collate",
+498            "contains",
+499            "create",
+500            "cross",
+501            "cube",
+502            "current",
+503            "default",
+504            "define",
+505            "desc",
+506            "distinct",
+507            "else",
+508            "end",
+509            "enum",
+510            "escape",
+511            "except",
+512            "exclude",
+513            "exists",
+514            "extract",
+515            "false",
+516            "fetch",
+517            "following",
+518            "for",
+519            "from",
+520            "full",
+521            "group",
+522            "grouping",
+523            "groups",
+524            "hash",
+525            "having",
+526            "if",
+527            "ignore",
+528            "in",
+529            "inner",
+530            "intersect",
+531            "interval",
+532            "into",
+533            "is",
+534            "join",
+535            "lateral",
+536            "left",
+537            "like",
+538            "limit",
+539            "lookup",
+540            "merge",
+541            "natural",
+542            "new",
+543            "no",
+544            "not",
+545            "null",
+546            "nulls",
+547            "of",
+548            "on",
+549            "or",
+550            "order",
+551            "outer",
+552            "over",
+553            "partition",
+554            "preceding",
+555            "proto",
+556            "qualify",
+557            "range",
+558            "recursive",
+559            "respect",
+560            "right",
+561            "rollup",
+562            "rows",
+563            "select",
+564            "set",
+565            "some",
+566            "struct",
+567            "tablesample",
+568            "then",
+569            "to",
+570            "treat",
+571            "true",
+572            "unbounded",
+573            "union",
+574            "unnest",
+575            "using",
+576            "when",
+577            "where",
+578            "window",
+579            "with",
+580            "within",
+581        }
 582
-583            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
-584            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
-585            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
-586                return self.func(
-587                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
-588                )
-589
-590            return super().attimezone_sql(expression)
-591
-592        def trycast_sql(self, expression: exp.TryCast) -> str:
-593            return self.cast_sql(expression, safe_prefix="SAFE_")
+583        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
+584            parent = expression.parent
+585
+586            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
+587            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
+588            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
+589                return self.func(
+590                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
+591                )
+592
+593            return super().attimezone_sql(expression)
 594
-595        def cte_sql(self, expression: exp.CTE) -> str:
-596            if expression.alias_column_names:
-597                self.unsupported("Column names in CTE definition are not supported.")
-598            return super().cte_sql(expression)
-599
-600        def array_sql(self, expression: exp.Array) -> str:
-601            first_arg = seq_get(expression.expressions, 0)
-602            if isinstance(first_arg, exp.Subqueryable):
-603                return f"ARRAY{self.wrap(self.sql(first_arg))}"
-604
-605            return inline_array_sql(self, expression)
-606
-607        def transaction_sql(self, *_) -> str:
-608            return "BEGIN TRANSACTION"
+595        def trycast_sql(self, expression: exp.TryCast) -> str:
+596            return self.cast_sql(expression, safe_prefix="SAFE_")
+597
+598        def cte_sql(self, expression: exp.CTE) -> str:
+599            if expression.alias_column_names:
+600                self.unsupported("Column names in CTE definition are not supported.")
+601            return super().cte_sql(expression)
+602
+603        def array_sql(self, expression: exp.Array) -> str:
+604            first_arg = seq_get(expression.expressions, 0)
+605            if isinstance(first_arg, exp.Subqueryable):
+606                return f"ARRAY{self.wrap(self.sql(first_arg))}"
+607
+608            return inline_array_sql(self, expression)
 609
-610        def commit_sql(self, *_) -> str:
-611            return "COMMIT TRANSACTION"
+610        def transaction_sql(self, *_) -> str:
+611            return "BEGIN TRANSACTION"
 612
-613        def rollback_sql(self, *_) -> str:
-614            return "ROLLBACK TRANSACTION"
+613        def commit_sql(self, *_) -> str:
+614            return "COMMIT TRANSACTION"
 615
-616        def in_unnest_op(self, expression: exp.Unnest) -> str:
-617            return self.sql(expression)
+616        def rollback_sql(self, *_) -> str:
+617            return "ROLLBACK TRANSACTION"
 618
-619        def except_op(self, expression: exp.Except) -> str:
-620            if not expression.args.get("distinct", False):
-621                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
-622            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
-623
-624        def intersect_op(self, expression: exp.Intersect) -> str:
-625            if not expression.args.get("distinct", False):
-626                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
-627            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
-628
-629        def with_properties(self, properties: exp.Properties) -> str:
-630            return self.properties(properties, prefix=self.seg("OPTIONS"))
+619        def in_unnest_op(self, expression: exp.Unnest) -> str:
+620            return self.sql(expression)
+621
+622        def except_op(self, expression: exp.Except) -> str:
+623            if not expression.args.get("distinct", False):
+624                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
+625            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+626
+627        def intersect_op(self, expression: exp.Intersect) -> str:
+628            if not expression.args.get("distinct", False):
+629                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
+630            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+631
+632        def with_properties(self, properties: exp.Properties) -> str:
+633            return self.properties(properties, prefix=self.seg("OPTIONS"))
 
@@ -2803,7 +2808,7 @@ Default: True
TRANSFORMS = - {<class 'sqlglot.expressions.DateAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TsOrDsAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CheckColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.InlineLengthColumnConstraint'>: <function Generator.<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.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ReturnsProperty'>: <function _returnsproperty_sql>, <class 'sqlglot.expressions.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.StabilityProperty'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ApproxDistinct'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ArraySize'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Cast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.Create'>: <function _create_sql>, <class 'sqlglot.expressions.CTE'>: <function preprocess.<locals>._to_sql>, <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_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.DateTrunc'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.GenerateSeries'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.GroupConcat'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Hex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.IntDiv'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.JSONFormat'>: <function rename_func.<locals>.<lambda>>, <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.RegexpLike'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.StrToDate'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.StrToTime'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TimeAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimeSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimeStrToTime'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.Trim'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDate'>: <function ts_or_ds_to_date_sql.<locals>._ts_or_ds_to_date_sql>, <class 'sqlglot.expressions.Unhex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Values'>: <function _derived_table_values_to_unnest>, <class 'sqlglot.expressions.VariancePop'>: <function rename_func.<locals>.<lambda>>} + {<class 'sqlglot.expressions.DateAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TsOrDsAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CheckColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.InlineLengthColumnConstraint'>: <function Generator.<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.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ReturnsProperty'>: <function _returnsproperty_sql>, <class 'sqlglot.expressions.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.StabilityProperty'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ApproxDistinct'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ArraySize'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Cast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.Create'>: <function _create_sql>, <class 'sqlglot.expressions.CTE'>: <function preprocess.<locals>._to_sql>, <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_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.DatetimeSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.DateTrunc'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.GenerateSeries'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.GroupConcat'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Hex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.IntDiv'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.JSONFormat'>: <function rename_func.<locals>.<lambda>>, <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.RegexpReplace'>: <function regexp_replace_sql>, <class 'sqlglot.expressions.RegexpLike'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.StrToDate'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.StrToTime'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TimeAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimeSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampAdd'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimestampSub'>: <function _date_add_sql.<locals>.func>, <class 'sqlglot.expressions.TimeStrToTime'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.Trim'>: <function BigQuery.Generator.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDate'>: <function ts_or_ds_to_date_sql.<locals>._ts_or_ds_to_date_sql>, <class 'sqlglot.expressions.Unhex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.Values'>: <function _derived_table_values_to_unnest>, <class 'sqlglot.expressions.VariancePop'>: <function rename_func.<locals>.<lambda>>}
@@ -2842,7 +2847,7 @@ Default: True
RESERVED_KEYWORDS = - {'exists', 'into', 'by', 'at', 'following', 'lookup', 'with', 'full', 'join', 'escape', 'if', 'except', 'exclude', 'qualify', 'is', 'from', 'order', 'as', 'like', 'partition', 'create', 'asc', 'between', 'enum', 'ignore', 'using', 'then', 'else', 'right', 'all', 'some', 'recursive', 'having', 'nulls', 'over', 'rows', 'in', 'when', 'for', 'tablesample', 'null', 'groups', 'select', 'struct', 'left', 'union', 'distinct', 'to', 'within', 'desc', 'intersect', 'current', 'cast', 'on', 'not', 'unnest', 'of', 'contains', 'outer', 'interval', 'and', 'window', 'assert_rows_modified', 'collate', 'cross', 'any', 'default', 'merge', 'or', 'cube', 'range', 'inner', 'natural', 'treat', 'no', 'rollup', 'true', 'group', 'fetch', 'extract', 'hash', 'end', 'lateral', 'respect', 'set', 'unbounded', 'new', 'limit', 'array', 'false', 'where', 'proto', 'case', 'grouping', 'define', 'preceding'} + {'any', 'default', 'following', 'define', 'merge', 'is', 'if', 'asc', 'cube', 'recursive', 'then', 'hash', 'proto', 'intersect', 'enum', 'new', 'for', 'lookup', 'natural', 'case', 'or', 'assert_rows_modified', 'like', 'exclude', 'using', 'having', 'select', 'no', 'some', 'null', 'tablesample', 'partition', 'nulls', 'from', 'on', 'into', 'set', 'except', 'join', 'all', 'and', 'limit', 'rollup', 'group', 'in', 'desc', 'between', 'qualify', 'exists', 'union', 'full', 'outer', 'order', 'fetch', 'inner', 'respect', 'with', 'struct', 'within', 'preceding', 'false', 'cast', 'rows', 'end', 'as', 'array', 'left', 'when', 'else', 'distinct', 'current', 'true', 'window', 'at', 'cross', 'ignore', 'groups', 'escape', 'unbounded', 'interval', 'where', 'extract', 'lateral', 'unnest', 'treat', 'not', 'contains', 'of', 'by', 'right', 'over', 'collate', 'range', 'create', 'to', 'grouping'}
@@ -2862,17 +2867,17 @@ Default: True
-
580        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
-581            parent = expression.parent
-582
-583            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
-584            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
-585            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
-586                return self.func(
-587                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
-588                )
-589
-590            return super().attimezone_sql(expression)
+            
583        def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
+584            parent = expression.parent
+585
+586            # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]).
+587            # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included.
+588            if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"):
+589                return self.func(
+590                    "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone"))
+591                )
+592
+593            return super().attimezone_sql(expression)
 
@@ -2890,8 +2895,8 @@ Default: True
-
592        def trycast_sql(self, expression: exp.TryCast) -> str:
-593            return self.cast_sql(expression, safe_prefix="SAFE_")
+            
595        def trycast_sql(self, expression: exp.TryCast) -> str:
+596            return self.cast_sql(expression, safe_prefix="SAFE_")
 
@@ -2909,10 +2914,10 @@ Default: True
-
595        def cte_sql(self, expression: exp.CTE) -> str:
-596            if expression.alias_column_names:
-597                self.unsupported("Column names in CTE definition are not supported.")
-598            return super().cte_sql(expression)
+            
598        def cte_sql(self, expression: exp.CTE) -> str:
+599            if expression.alias_column_names:
+600                self.unsupported("Column names in CTE definition are not supported.")
+601            return super().cte_sql(expression)
 
@@ -2930,12 +2935,12 @@ Default: True
-
600        def array_sql(self, expression: exp.Array) -> str:
-601            first_arg = seq_get(expression.expressions, 0)
-602            if isinstance(first_arg, exp.Subqueryable):
-603                return f"ARRAY{self.wrap(self.sql(first_arg))}"
-604
-605            return inline_array_sql(self, expression)
+            
603        def array_sql(self, expression: exp.Array) -> str:
+604            first_arg = seq_get(expression.expressions, 0)
+605            if isinstance(first_arg, exp.Subqueryable):
+606                return f"ARRAY{self.wrap(self.sql(first_arg))}"
+607
+608            return inline_array_sql(self, expression)
 
@@ -2953,8 +2958,8 @@ Default: True
-
607        def transaction_sql(self, *_) -> str:
-608            return "BEGIN TRANSACTION"
+            
610        def transaction_sql(self, *_) -> str:
+611            return "BEGIN TRANSACTION"
 
@@ -2972,8 +2977,8 @@ Default: True
-
610        def commit_sql(self, *_) -> str:
-611            return "COMMIT TRANSACTION"
+            
613        def commit_sql(self, *_) -> str:
+614            return "COMMIT TRANSACTION"
 
@@ -2991,8 +2996,8 @@ Default: True
-
613        def rollback_sql(self, *_) -> str:
-614            return "ROLLBACK TRANSACTION"
+            
616        def rollback_sql(self, *_) -> str:
+617            return "ROLLBACK TRANSACTION"
 
@@ -3010,8 +3015,8 @@ Default: True
-
616        def in_unnest_op(self, expression: exp.Unnest) -> str:
-617            return self.sql(expression)
+            
619        def in_unnest_op(self, expression: exp.Unnest) -> str:
+620            return self.sql(expression)
 
@@ -3029,10 +3034,10 @@ Default: True
-
619        def except_op(self, expression: exp.Except) -> str:
-620            if not expression.args.get("distinct", False):
-621                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
-622            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+            
622        def except_op(self, expression: exp.Except) -> str:
+623            if not expression.args.get("distinct", False):
+624                self.unsupported("EXCEPT without DISTINCT is not supported in BigQuery")
+625            return f"EXCEPT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
 
@@ -3050,10 +3055,10 @@ Default: True
-
624        def intersect_op(self, expression: exp.Intersect) -> str:
-625            if not expression.args.get("distinct", False):
-626                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
-627            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
+            
627        def intersect_op(self, expression: exp.Intersect) -> str:
+628            if not expression.args.get("distinct", False):
+629                self.unsupported("INTERSECT without DISTINCT is not supported in BigQuery")
+630            return f"INTERSECT{' DISTINCT' if expression.args.get('distinct') else ' ALL'}"
 
@@ -3071,8 +3076,8 @@ Default: True
-
629        def with_properties(self, properties: exp.Properties) -> str:
-630            return self.properties(properties, prefix=self.seg("OPTIONS"))
+            
632        def with_properties(self, properties: exp.Properties) -> str:
+633            return self.properties(properties, prefix=self.seg("OPTIONS"))
 
@@ -3139,26 +3144,26 @@ Default: True
-
246    @classmethod
-247    def can_identify(cls, text: str, identify: str | bool = "safe") -> bool:
-248        """Checks if text can be identified given an identify option.
-249
-250        Args:
-251            text: The text to check.
-252            identify:
-253                "always" or `True`: Always returns true.
-254                "safe": True if the identifier is case-insensitive.
-255
-256        Returns:
-257            Whether or not the given text can be identified.
-258        """
-259        if identify is True or identify == "always":
-260            return True
-261
-262        if identify == "safe":
-263            return not cls.case_sensitive(text)
-264
-265        return False
+            
248    @classmethod
+249    def can_identify(cls, text: str, identify: str | bool = "safe") -> bool:
+250        """Checks if text can be identified given an identify option.
+251
+252        Args:
+253            text: The text to check.
+254            identify:
+255                "always" or `True`: Always returns true.
+256                "safe": True if the identifier is case-insensitive.
+257
+258        Returns:
+259            Whether or not the given text can be identified.
+260        """
+261        if identify is True or identify == "always":
+262            return True
+263
+264        if identify == "safe":
+265            return not cls.case_sensitive(text)
+266
+267        return False
 
@@ -3606,6 +3611,7 @@ Default: True
oncluster_sql
clusteredbyproperty_sql
anyvalue_sql
+
querytransform_sql
-- cgit v1.2.3