Adding upstream version 18.7.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c4fc25c23b
commit
be16920347
96 changed files with 59037 additions and 52828 deletions
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||
import logging
|
||||
import typing as t
|
||||
from collections import defaultdict
|
||||
from functools import reduce
|
||||
|
||||
from sqlglot import exp
|
||||
from sqlglot.errors import ErrorLevel, UnsupportedError, concat_messages
|
||||
|
@ -99,6 +100,9 @@ class Generator:
|
|||
exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}",
|
||||
}
|
||||
|
||||
# Whether the base comes first
|
||||
LOG_BASE_FIRST = True
|
||||
|
||||
# Whether or not null ordering is supported in order by
|
||||
NULL_ORDERING_SUPPORTED = True
|
||||
|
||||
|
@ -188,6 +192,18 @@ class Generator:
|
|||
# Whether or not the word COLUMN is included when adding a column with ALTER TABLE
|
||||
ALTER_TABLE_ADD_COLUMN_KEYWORD = True
|
||||
|
||||
# UNNEST WITH ORDINALITY (presto) instead of UNNEST WITH OFFSET (bigquery)
|
||||
UNNEST_WITH_ORDINALITY = True
|
||||
|
||||
# Whether or not FILTER (WHERE cond) can be used for conditional aggregation
|
||||
AGGREGATE_FILTER_SUPPORTED = True
|
||||
|
||||
# Whether or not JOIN sides (LEFT, RIGHT) are supported in conjunction with SEMI/ANTI join kinds
|
||||
SEMI_ANTI_JOIN_WITH_SIDE = True
|
||||
|
||||
# Whether or not session variables / parameters are supported, e.g. @x in T-SQL
|
||||
SUPPORTS_PARAMETERS = True
|
||||
|
||||
TYPE_MAPPING = {
|
||||
exp.DataType.Type.NCHAR: "CHAR",
|
||||
exp.DataType.Type.NVARCHAR: "VARCHAR",
|
||||
|
@ -308,6 +324,8 @@ class Generator:
|
|||
exp.Paren,
|
||||
)
|
||||
|
||||
UNESCAPED_SEQUENCE_TABLE = None # type: ignore
|
||||
|
||||
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
|
||||
|
||||
# Autofilled
|
||||
|
@ -320,7 +338,6 @@ class Generator:
|
|||
STRICT_STRING_CONCAT = False
|
||||
NORMALIZE_FUNCTIONS: bool | str = "upper"
|
||||
NULL_ORDERING = "nulls_are_small"
|
||||
ESCAPE_LINE_BREAK = False
|
||||
|
||||
can_identify: t.Callable[[str, str | bool], bool]
|
||||
|
||||
|
@ -955,9 +972,16 @@ class Generator:
|
|||
return f"{self.seg('FETCH')}{direction}{count} ROWS {with_ties_or_only}"
|
||||
|
||||
def filter_sql(self, expression: exp.Filter) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
where = self.sql(expression, "expression").strip()
|
||||
return f"{this} FILTER({where})"
|
||||
if self.AGGREGATE_FILTER_SUPPORTED:
|
||||
this = self.sql(expression, "this")
|
||||
where = self.sql(expression, "expression").strip()
|
||||
return f"{this} FILTER({where})"
|
||||
|
||||
agg = expression.this.copy()
|
||||
agg_arg = agg.this
|
||||
cond = expression.expression.this
|
||||
agg_arg.replace(exp.If(this=cond.copy(), true=agg_arg.copy()))
|
||||
return self.sql(agg)
|
||||
|
||||
def hint_sql(self, expression: exp.Hint) -> str:
|
||||
if not self.QUERY_HINTS:
|
||||
|
@ -975,13 +999,14 @@ class Generator:
|
|||
table = self.sql(expression, "table")
|
||||
table = f"{self.INDEX_ON} {table}" if table else ""
|
||||
using = self.sql(expression, "using")
|
||||
using = f" USING {using} " if using else ""
|
||||
using = f" USING {using}" if using else ""
|
||||
index = "INDEX " if not table else ""
|
||||
columns = self.expressions(expression, key="columns", flat=True)
|
||||
columns = f"({columns})" if columns else ""
|
||||
partition_by = self.expressions(expression, key="partition_by", flat=True)
|
||||
partition_by = f" PARTITION BY {partition_by}" if partition_by else ""
|
||||
return f"{unique}{primary}{amp}{index}{name}{table}{using}{columns}{partition_by}"
|
||||
where = self.sql(expression, "where")
|
||||
return f"{unique}{primary}{amp}{index}{name}{table}{using}{columns}{partition_by}{where}"
|
||||
|
||||
def identifier_sql(self, expression: exp.Identifier) -> str:
|
||||
text = expression.name
|
||||
|
@ -1060,10 +1085,15 @@ class Generator:
|
|||
|
||||
return properties_locs
|
||||
|
||||
def property_name(self, expression: exp.Property, string_key: bool = False) -> str:
|
||||
if isinstance(expression.this, exp.Dot):
|
||||
return self.sql(expression, "this")
|
||||
return f"'{expression.name}'" if string_key else expression.name
|
||||
|
||||
def property_sql(self, expression: exp.Property) -> str:
|
||||
property_cls = expression.__class__
|
||||
if property_cls == exp.Property:
|
||||
return f"{expression.name}={self.sql(expression, 'value')}"
|
||||
return f"{self.property_name(expression)}={self.sql(expression, 'value')}"
|
||||
|
||||
property_name = exp.Properties.PROPERTY_TO_NAME.get(property_cls)
|
||||
if not property_name:
|
||||
|
@ -1224,6 +1254,13 @@ class Generator:
|
|||
def introducer_sql(self, expression: exp.Introducer) -> str:
|
||||
return f"{self.sql(expression, 'this')} {self.sql(expression, 'expression')}"
|
||||
|
||||
def kill_sql(self, expression: exp.Kill) -> str:
|
||||
kind = self.sql(expression, "kind")
|
||||
kind = f" {kind}" if kind else ""
|
||||
this = self.sql(expression, "this")
|
||||
this = f" {this}" if this else ""
|
||||
return f"KILL{kind}{this}"
|
||||
|
||||
def pseudotype_sql(self, expression: exp.PseudoType) -> str:
|
||||
return expression.name.upper()
|
||||
|
||||
|
@ -1386,13 +1423,11 @@ class Generator:
|
|||
return f"{values} AS {alias}" if alias else values
|
||||
|
||||
# Converts `VALUES...` expression into a series of select unions.
|
||||
# Note: If you have a lot of unions then this will result in a large number of recursive statements to
|
||||
# evaluate the expression. You may need to increase `sys.setrecursionlimit` to run and it can also be
|
||||
# very slow.
|
||||
expression = expression.copy()
|
||||
column_names = expression.alias and expression.args["alias"].columns
|
||||
alias_node = expression.args.get("alias")
|
||||
column_names = alias_node and alias_node.columns
|
||||
|
||||
selects = []
|
||||
selects: t.List[exp.Subqueryable] = []
|
||||
|
||||
for i, tup in enumerate(expression.expressions):
|
||||
row = tup.expressions
|
||||
|
@ -1404,14 +1439,18 @@ class Generator:
|
|||
|
||||
selects.append(exp.Select(expressions=row))
|
||||
|
||||
subquery_expression: exp.Select | exp.Union = selects[0]
|
||||
if len(selects) > 1:
|
||||
for select in selects[1:]:
|
||||
subquery_expression = exp.union(
|
||||
subquery_expression, select, distinct=False, copy=False
|
||||
)
|
||||
if self.pretty:
|
||||
# This may result in poor performance for large-cardinality `VALUES` tables, due to
|
||||
# the deep nesting of the resulting exp.Unions. If this is a problem, either increase
|
||||
# `sys.setrecursionlimit` to avoid RecursionErrors, or don't set `pretty`.
|
||||
subqueryable = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
|
||||
return self.subquery_sql(
|
||||
subqueryable.subquery(alias_node and alias_node.this, copy=False)
|
||||
)
|
||||
|
||||
return self.subquery_sql(subquery_expression.subquery(expression.alias, copy=False))
|
||||
alias = f" AS {self.sql(alias_node, 'this')}" if alias_node else ""
|
||||
unions = " UNION ALL ".join(self.sql(select) for select in selects)
|
||||
return f"({unions}){alias}"
|
||||
|
||||
def var_sql(self, expression: exp.Var) -> str:
|
||||
return self.sql(expression, "this")
|
||||
|
@ -1477,12 +1516,17 @@ class Generator:
|
|||
return f"PRIOR {self.sql(expression, 'this')}"
|
||||
|
||||
def join_sql(self, expression: exp.Join) -> str:
|
||||
if not self.SEMI_ANTI_JOIN_WITH_SIDE and expression.kind in ("SEMI", "ANTI"):
|
||||
side = None
|
||||
else:
|
||||
side = expression.side
|
||||
|
||||
op_sql = " ".join(
|
||||
op
|
||||
for op in (
|
||||
expression.method,
|
||||
"GLOBAL" if expression.args.get("global") else None,
|
||||
expression.side,
|
||||
side,
|
||||
expression.kind,
|
||||
expression.hint if self.JOIN_HINTS else None,
|
||||
)
|
||||
|
@ -1594,8 +1638,8 @@ class Generator:
|
|||
|
||||
def escape_str(self, text: str) -> str:
|
||||
text = text.replace(self.QUOTE_END, self._escaped_quote_end)
|
||||
if self.ESCAPE_LINE_BREAK:
|
||||
text = text.replace("\n", "\\n")
|
||||
if self.UNESCAPED_SEQUENCE_TABLE:
|
||||
text = text.translate(self.UNESCAPED_SEQUENCE_TABLE)
|
||||
elif self.pretty:
|
||||
text = text.replace("\n", self.SENTINEL_LINE_BREAK)
|
||||
return text
|
||||
|
@ -1643,7 +1687,7 @@ class Generator:
|
|||
nulls_are_small = self.NULL_ORDERING == "nulls_are_small"
|
||||
nulls_are_last = self.NULL_ORDERING == "nulls_are_last"
|
||||
|
||||
sort_order = " DESC" if desc else ""
|
||||
sort_order = " DESC" if desc else (" ASC" if desc is False else "")
|
||||
nulls_sort_change = ""
|
||||
if nulls_first and (
|
||||
(asc and nulls_are_large) or (desc and nulls_are_small) or nulls_are_last
|
||||
|
@ -1817,8 +1861,7 @@ class Generator:
|
|||
|
||||
def parameter_sql(self, expression: exp.Parameter) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
this = f"{{{this}}}" if expression.args.get("wrapped") else f"{this}"
|
||||
return f"{self.PARAMETER_TOKEN}{this}"
|
||||
return f"{self.PARAMETER_TOKEN}{this}" if self.SUPPORTS_PARAMETERS else this
|
||||
|
||||
def sessionparameter_sql(self, expression: exp.SessionParameter) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
|
@ -1858,17 +1901,33 @@ class Generator:
|
|||
|
||||
def unnest_sql(self, expression: exp.Unnest) -> str:
|
||||
args = self.expressions(expression, flat=True)
|
||||
|
||||
alias = expression.args.get("alias")
|
||||
offset = expression.args.get("offset")
|
||||
|
||||
if self.UNNEST_WITH_ORDINALITY:
|
||||
if alias and isinstance(offset, exp.Expression):
|
||||
alias = alias.copy()
|
||||
alias.append("columns", offset.copy())
|
||||
|
||||
if alias and self.UNNEST_COLUMN_ONLY:
|
||||
columns = alias.columns
|
||||
alias = self.sql(columns[0]) if columns else ""
|
||||
else:
|
||||
alias = self.sql(expression, "alias")
|
||||
alias = self.sql(alias)
|
||||
|
||||
alias = f" AS {alias}" if alias else alias
|
||||
ordinality = " WITH ORDINALITY" if expression.args.get("ordinality") else ""
|
||||
offset = expression.args.get("offset")
|
||||
offset = f" WITH OFFSET AS {self.sql(offset)}" if offset else ""
|
||||
return f"UNNEST({args}){ordinality}{alias}{offset}"
|
||||
if self.UNNEST_WITH_ORDINALITY:
|
||||
suffix = f" WITH ORDINALITY{alias}" if offset else alias
|
||||
else:
|
||||
if isinstance(offset, exp.Expression):
|
||||
suffix = f"{alias} WITH OFFSET AS {self.sql(offset)}"
|
||||
elif offset:
|
||||
suffix = f"{alias} WITH OFFSET"
|
||||
else:
|
||||
suffix = alias
|
||||
|
||||
return f"UNNEST({args}){suffix}"
|
||||
|
||||
def where_sql(self, expression: exp.Where) -> str:
|
||||
this = self.indent(self.sql(expression, "this"))
|
||||
|
@ -2471,6 +2530,12 @@ class Generator:
|
|||
def trycast_sql(self, expression: exp.TryCast) -> str:
|
||||
return self.cast_sql(expression, safe_prefix="TRY_")
|
||||
|
||||
def log_sql(self, expression: exp.Log) -> str:
|
||||
args = list(expression.args.values())
|
||||
if not self.LOG_BASE_FIRST:
|
||||
args.reverse()
|
||||
return self.func("LOG", *args)
|
||||
|
||||
def use_sql(self, expression: exp.Use) -> str:
|
||||
kind = self.sql(expression, "kind")
|
||||
kind = f" {kind}" if kind else ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue