Adding upstream version 20.9.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
943dfc0887
commit
8a068da99c
144 changed files with 78309 additions and 59609 deletions
|
@ -68,6 +68,7 @@ class Generator:
|
|||
exp.CheckColumnConstraint: lambda self, e: f"CHECK ({self.sql(e, 'this')})",
|
||||
exp.ClusteredColumnConstraint: lambda self, e: f"CLUSTERED ({self.expressions(e, 'this', indent=False)})",
|
||||
exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}",
|
||||
exp.AutoRefreshProperty: lambda self, e: f"AUTO REFRESH {self.sql(e, 'this')}",
|
||||
exp.CopyGrantsProperty: lambda self, e: "COPY GRANTS",
|
||||
exp.CommentColumnConstraint: lambda self, e: f"COMMENT {self.sql(e, 'this')}",
|
||||
exp.DateFormatColumnConstraint: lambda self, e: f"FORMAT {self.sql(e, 'this')}",
|
||||
|
@ -96,6 +97,7 @@ class Generator:
|
|||
exp.SampleProperty: lambda self, e: f"SAMPLE BY {self.sql(e, 'this')}",
|
||||
exp.SetProperty: lambda self, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
|
||||
exp.SettingsProperty: lambda self, e: f"SETTINGS{self.seg('')}{(self.expressions(e))}",
|
||||
exp.SqlReadWriteProperty: lambda self, e: e.name,
|
||||
exp.SqlSecurityProperty: lambda self, e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}",
|
||||
exp.StabilityProperty: lambda self, e: e.name,
|
||||
exp.TemporaryProperty: lambda self, e: f"TEMPORARY",
|
||||
|
@ -110,7 +112,8 @@ class Generator:
|
|||
}
|
||||
|
||||
# Whether or not null ordering is supported in order by
|
||||
NULL_ORDERING_SUPPORTED = True
|
||||
# True: Full Support, None: No support, False: No support in window specifications
|
||||
NULL_ORDERING_SUPPORTED: t.Optional[bool] = True
|
||||
|
||||
# Whether or not locking reads (i.e. SELECT ... FOR UPDATE/SHARE) are supported
|
||||
LOCKING_READS_SUPPORTED = False
|
||||
|
@ -133,12 +136,6 @@ class Generator:
|
|||
# Whether or not the plural form of date parts like day (i.e. "days") is supported in INTERVALs
|
||||
INTERVAL_ALLOWS_PLURAL_FORM = True
|
||||
|
||||
# Whether or not the TABLESAMPLE clause supports a method name, like BERNOULLI
|
||||
TABLESAMPLE_WITH_METHOD = True
|
||||
|
||||
# Whether or not to treat the number in TABLESAMPLE (50) as a percentage
|
||||
TABLESAMPLE_SIZE_IS_PERCENT = False
|
||||
|
||||
# Whether or not limit and fetch are supported (possible values: "ALL", "LIMIT", "FETCH")
|
||||
LIMIT_FETCH = "ALL"
|
||||
|
||||
|
@ -219,6 +216,18 @@ class Generator:
|
|||
# Whether or not parentheses are required around the table sample's expression
|
||||
TABLESAMPLE_REQUIRES_PARENS = True
|
||||
|
||||
# Whether or not a table sample clause's size needs to be followed by the ROWS keyword
|
||||
TABLESAMPLE_SIZE_IS_ROWS = True
|
||||
|
||||
# The keyword(s) to use when generating a sample clause
|
||||
TABLESAMPLE_KEYWORDS = "TABLESAMPLE"
|
||||
|
||||
# Whether or not the TABLESAMPLE clause supports a method name, like BERNOULLI
|
||||
TABLESAMPLE_WITH_METHOD = True
|
||||
|
||||
# The keyword to use when specifying the seed of a sample clause
|
||||
TABLESAMPLE_SEED_KEYWORD = "SEED"
|
||||
|
||||
# Whether or not COLLATE is a function instead of a binary operator
|
||||
COLLATE_IS_FUNC = False
|
||||
|
||||
|
@ -234,6 +243,27 @@ class Generator:
|
|||
# Whether or not CONCAT requires >1 arguments
|
||||
SUPPORTS_SINGLE_ARG_CONCAT = True
|
||||
|
||||
# Whether or not LAST_DAY function supports a date part argument
|
||||
LAST_DAY_SUPPORTS_DATE_PART = True
|
||||
|
||||
# Whether or not named columns are allowed in table aliases
|
||||
SUPPORTS_TABLE_ALIAS_COLUMNS = True
|
||||
|
||||
# Whether or not UNPIVOT aliases are Identifiers (False means they're Literals)
|
||||
UNPIVOT_ALIASES_ARE_IDENTIFIERS = True
|
||||
|
||||
# What delimiter to use for separating JSON key/value pairs
|
||||
JSON_KEY_VALUE_PAIR_SEP = ":"
|
||||
|
||||
# INSERT OVERWRITE TABLE x override
|
||||
INSERT_OVERWRITE = " OVERWRITE TABLE"
|
||||
|
||||
# Whether or not the SELECT .. INTO syntax is used instead of CTAS
|
||||
SUPPORTS_SELECT_INTO = False
|
||||
|
||||
# Whether or not UNLOGGED tables can be created
|
||||
SUPPORTS_UNLOGGED_TABLES = False
|
||||
|
||||
TYPE_MAPPING = {
|
||||
exp.DataType.Type.NCHAR: "CHAR",
|
||||
exp.DataType.Type.NVARCHAR: "VARCHAR",
|
||||
|
@ -252,15 +282,15 @@ class Generator:
|
|||
}
|
||||
|
||||
TIME_PART_SINGULARS = {
|
||||
"microseconds": "microsecond",
|
||||
"seconds": "second",
|
||||
"minutes": "minute",
|
||||
"hours": "hour",
|
||||
"days": "day",
|
||||
"weeks": "week",
|
||||
"months": "month",
|
||||
"quarters": "quarter",
|
||||
"years": "year",
|
||||
"MICROSECONDS": "MICROSECOND",
|
||||
"SECONDS": "SECOND",
|
||||
"MINUTES": "MINUTE",
|
||||
"HOURS": "HOUR",
|
||||
"DAYS": "DAY",
|
||||
"WEEKS": "WEEK",
|
||||
"MONTHS": "MONTH",
|
||||
"QUARTERS": "QUARTER",
|
||||
"YEARS": "YEAR",
|
||||
}
|
||||
|
||||
TOKEN_MAPPING: t.Dict[TokenType, str] = {}
|
||||
|
@ -272,6 +302,7 @@ class Generator:
|
|||
PROPERTIES_LOCATION = {
|
||||
exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.AutoIncrementProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.AutoRefreshProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.BlockCompressionProperty: exp.Properties.Location.POST_NAME,
|
||||
exp.CharacterSetProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.ChecksumProperty: exp.Properties.Location.POST_NAME,
|
||||
|
@ -323,6 +354,7 @@ class Generator:
|
|||
exp.SettingsProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SetProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.SortKeyProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SqlReadWriteProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SqlSecurityProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.StabilityProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.TemporaryProperty: exp.Properties.Location.POST_CREATE,
|
||||
|
@ -370,7 +402,7 @@ class Generator:
|
|||
# Expressions that need to have all CTEs under them bubbled up to them
|
||||
EXPRESSIONS_WITHOUT_NESTED_CTES: t.Set[t.Type[exp.Expression]] = set()
|
||||
|
||||
KEY_VALUE_DEFINITONS = (exp.Bracket, exp.EQ, exp.PropertyEQ, exp.Slice)
|
||||
KEY_VALUE_DEFINITIONS = (exp.Bracket, exp.EQ, exp.PropertyEQ, exp.Slice)
|
||||
|
||||
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
|
||||
|
||||
|
@ -775,7 +807,7 @@ class Generator:
|
|||
return self.sql(expression, "this")
|
||||
|
||||
def create_sql(self, expression: exp.Create) -> str:
|
||||
kind = self.sql(expression, "kind").upper()
|
||||
kind = self.sql(expression, "kind")
|
||||
properties = expression.args.get("properties")
|
||||
properties_locs = self.locate_properties(properties) if properties else defaultdict()
|
||||
|
||||
|
@ -868,7 +900,12 @@ class Generator:
|
|||
return f"{shallow}{keyword} {this}"
|
||||
|
||||
def describe_sql(self, expression: exp.Describe) -> str:
|
||||
return f"DESCRIBE {self.sql(expression, 'this')}"
|
||||
extended = " EXTENDED" if expression.args.get("extended") else ""
|
||||
return f"DESCRIBE{extended} {self.sql(expression, 'this')}"
|
||||
|
||||
def heredoc_sql(self, expression: exp.Heredoc) -> str:
|
||||
tag = self.sql(expression, "tag")
|
||||
return f"${tag}${self.sql(expression, 'this')}${tag}$"
|
||||
|
||||
def prepend_ctes(self, expression: exp.Expression, sql: str) -> str:
|
||||
with_ = self.sql(expression, "with")
|
||||
|
@ -895,6 +932,10 @@ class Generator:
|
|||
columns = self.expressions(expression, key="columns", flat=True)
|
||||
columns = f"({columns})" if columns else ""
|
||||
|
||||
if columns and not self.SUPPORTS_TABLE_ALIAS_COLUMNS:
|
||||
columns = ""
|
||||
self.unsupported("Named columns are not supported in table alias.")
|
||||
|
||||
if not alias and not self.dialect.UNNEST_COLUMN_ONLY:
|
||||
alias = "_t"
|
||||
|
||||
|
@ -1027,7 +1068,7 @@ class Generator:
|
|||
|
||||
def fetch_sql(self, expression: exp.Fetch) -> str:
|
||||
direction = expression.args.get("direction")
|
||||
direction = f" {direction.upper()}" if direction else ""
|
||||
direction = f" {direction}" if direction else ""
|
||||
count = expression.args.get("count")
|
||||
count = f" {count}" if count else ""
|
||||
if expression.args.get("percent"):
|
||||
|
@ -1318,7 +1359,7 @@ class Generator:
|
|||
if isinstance(expression.this, exp.Directory):
|
||||
this = " OVERWRITE" if overwrite else " INTO"
|
||||
else:
|
||||
this = " OVERWRITE TABLE" if overwrite else " INTO"
|
||||
this = self.INSERT_OVERWRITE if overwrite else " INTO"
|
||||
|
||||
alternative = expression.args.get("alternative")
|
||||
alternative = f" OR {alternative}" if alternative else ""
|
||||
|
@ -1365,10 +1406,10 @@ class Generator:
|
|||
return f"KILL{kind}{this}"
|
||||
|
||||
def pseudotype_sql(self, expression: exp.PseudoType) -> str:
|
||||
return expression.name.upper()
|
||||
return expression.name
|
||||
|
||||
def objectidentifier_sql(self, expression: exp.ObjectIdentifier) -> str:
|
||||
return expression.name.upper()
|
||||
return expression.name
|
||||
|
||||
def onconflict_sql(self, expression: exp.OnConflict) -> str:
|
||||
conflict = "ON DUPLICATE KEY" if expression.args.get("duplicate") else "ON CONFLICT"
|
||||
|
@ -1445,9 +1486,6 @@ class Generator:
|
|||
pattern = f", PATTERN => {pattern}" if pattern else ""
|
||||
file_format = f" (FILE_FORMAT => {file_format}{pattern})"
|
||||
|
||||
index = self.sql(expression, "index")
|
||||
index = f" AT {index}" if index else ""
|
||||
|
||||
ordinality = expression.args.get("ordinality") or ""
|
||||
if ordinality:
|
||||
ordinality = f" WITH ORDINALITY{alias}"
|
||||
|
@ -1457,10 +1495,13 @@ class Generator:
|
|||
if when:
|
||||
table = f"{table} {when}"
|
||||
|
||||
return f"{table}{version}{file_format}{alias}{index}{hints}{pivots}{joins}{laterals}{ordinality}"
|
||||
return f"{table}{version}{file_format}{alias}{hints}{pivots}{joins}{laterals}{ordinality}"
|
||||
|
||||
def tablesample_sql(
|
||||
self, expression: exp.TableSample, seed_prefix: str = "SEED", sep=" AS "
|
||||
self,
|
||||
expression: exp.TableSample,
|
||||
sep: str = " AS ",
|
||||
tablesample_keyword: t.Optional[str] = None,
|
||||
) -> str:
|
||||
if self.dialect.ALIAS_POST_TABLESAMPLE and expression.this and expression.this.alias:
|
||||
table = expression.this.copy()
|
||||
|
@ -1472,30 +1513,30 @@ class Generator:
|
|||
alias = ""
|
||||
|
||||
method = self.sql(expression, "method")
|
||||
method = f"{method.upper()} " if method and self.TABLESAMPLE_WITH_METHOD else ""
|
||||
method = f"{method} " if method and self.TABLESAMPLE_WITH_METHOD else ""
|
||||
numerator = self.sql(expression, "bucket_numerator")
|
||||
denominator = self.sql(expression, "bucket_denominator")
|
||||
field = self.sql(expression, "bucket_field")
|
||||
field = f" ON {field}" if field else ""
|
||||
bucket = f"BUCKET {numerator} OUT OF {denominator}{field}" if numerator else ""
|
||||
percent = self.sql(expression, "percent")
|
||||
percent = f"{percent} PERCENT" if percent else ""
|
||||
rows = self.sql(expression, "rows")
|
||||
rows = f"{rows} ROWS" if rows else ""
|
||||
seed = self.sql(expression, "seed")
|
||||
seed = f" {self.TABLESAMPLE_SEED_KEYWORD} ({seed})" if seed else ""
|
||||
|
||||
size = self.sql(expression, "size")
|
||||
if size and self.TABLESAMPLE_SIZE_IS_PERCENT:
|
||||
size = f"{size} PERCENT"
|
||||
if size and self.TABLESAMPLE_SIZE_IS_ROWS:
|
||||
size = f"{size} ROWS"
|
||||
|
||||
seed = self.sql(expression, "seed")
|
||||
seed = f" {seed_prefix} ({seed})" if seed else ""
|
||||
kind = expression.args.get("kind", "TABLESAMPLE")
|
||||
percent = self.sql(expression, "percent")
|
||||
if percent and not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
|
||||
percent = f"{percent} PERCENT"
|
||||
|
||||
expr = f"{bucket}{percent}{rows}{size}"
|
||||
expr = f"{bucket}{percent}{size}"
|
||||
if self.TABLESAMPLE_REQUIRES_PARENS:
|
||||
expr = f"({expr})"
|
||||
|
||||
return f"{this} {kind} {method}{expr}{seed}{alias}"
|
||||
return (
|
||||
f"{this} {tablesample_keyword or self.TABLESAMPLE_KEYWORDS} {method}{expr}{seed}{alias}"
|
||||
)
|
||||
|
||||
def pivot_sql(self, expression: exp.Pivot) -> str:
|
||||
expressions = self.expressions(expression, flat=True)
|
||||
|
@ -1513,8 +1554,7 @@ class Generator:
|
|||
|
||||
alias = self.sql(expression, "alias")
|
||||
alias = f" AS {alias}" if alias else ""
|
||||
unpivot = expression.args.get("unpivot")
|
||||
direction = "UNPIVOT" if unpivot else "PIVOT"
|
||||
direction = "UNPIVOT" if expression.unpivot else "PIVOT"
|
||||
field = self.sql(expression, "field")
|
||||
include_nulls = expression.args.get("include_nulls")
|
||||
if include_nulls is not None:
|
||||
|
@ -1675,7 +1715,8 @@ class Generator:
|
|||
if not on_sql and using:
|
||||
on_sql = csv(*(self.sql(column) for column in using))
|
||||
|
||||
this_sql = self.sql(expression, "this")
|
||||
this = expression.this
|
||||
this_sql = self.sql(this)
|
||||
|
||||
if on_sql:
|
||||
on_sql = self.indent(on_sql, skip_first=True)
|
||||
|
@ -1685,6 +1726,9 @@ class Generator:
|
|||
else:
|
||||
on_sql = f"{space}ON {on_sql}"
|
||||
elif not op_sql:
|
||||
if isinstance(this, exp.Lateral) and this.args.get("cross_apply") is not None:
|
||||
return f" {this_sql}"
|
||||
|
||||
return f", {this_sql}"
|
||||
|
||||
op_sql = f"{op_sql} JOIN" if op_sql else "JOIN"
|
||||
|
@ -1695,6 +1739,19 @@ class Generator:
|
|||
args = f"({args})" if len(args.split(",")) > 1 else args
|
||||
return f"{args} {arrow_sep} {self.sql(expression, 'this')}"
|
||||
|
||||
def lateral_op(self, expression: exp.Lateral) -> str:
|
||||
cross_apply = expression.args.get("cross_apply")
|
||||
|
||||
# https://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/
|
||||
if cross_apply is True:
|
||||
op = "INNER JOIN "
|
||||
elif cross_apply is False:
|
||||
op = "LEFT JOIN "
|
||||
else:
|
||||
op = ""
|
||||
|
||||
return f"{op}LATERAL"
|
||||
|
||||
def lateral_sql(self, expression: exp.Lateral) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
|
||||
|
@ -1708,7 +1765,7 @@ class Generator:
|
|||
|
||||
alias = self.sql(expression, "alias")
|
||||
alias = f" AS {alias}" if alias else ""
|
||||
return f"LATERAL {this}{alias}"
|
||||
return f"{self.lateral_op(expression)} {this}{alias}"
|
||||
|
||||
def limit_sql(self, expression: exp.Limit, top: bool = False) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
|
@ -1805,7 +1862,8 @@ class Generator:
|
|||
def order_sql(self, expression: exp.Order, flat: bool = False) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
this = f"{this} " if this else this
|
||||
order = self.op_expressions(f"{this}ORDER BY", expression, flat=this or flat) # type: ignore
|
||||
siblings = "SIBLINGS " if expression.args.get("siblings") else ""
|
||||
order = self.op_expressions(f"{this}ORDER {siblings}BY", expression, flat=this or flat) # type: ignore
|
||||
interpolated_values = [
|
||||
f"{self.sql(named_expression, 'alias')} AS {self.sql(named_expression, 'this')}"
|
||||
for named_expression in expression.args.get("interpolate") or []
|
||||
|
@ -1860,9 +1918,21 @@ class Generator:
|
|||
|
||||
# If the NULLS FIRST/LAST clause is unsupported, we add another sort key to simulate it
|
||||
if nulls_sort_change and not self.NULL_ORDERING_SUPPORTED:
|
||||
null_sort_order = " DESC" if nulls_sort_change == " NULLS FIRST" else ""
|
||||
this = f"CASE WHEN {this} IS NULL THEN 1 ELSE 0 END{null_sort_order}, {this}"
|
||||
nulls_sort_change = ""
|
||||
window = expression.find_ancestor(exp.Window, exp.Select)
|
||||
if isinstance(window, exp.Window) and window.args.get("spec"):
|
||||
self.unsupported(
|
||||
f"'{nulls_sort_change.strip()}' translation not supported in window functions"
|
||||
)
|
||||
nulls_sort_change = ""
|
||||
elif self.NULL_ORDERING_SUPPORTED is None:
|
||||
if expression.this.is_int:
|
||||
self.unsupported(
|
||||
f"'{nulls_sort_change.strip()}' translation not supported with positional ordering"
|
||||
)
|
||||
else:
|
||||
null_sort_order = " DESC" if nulls_sort_change == " NULLS FIRST" else ""
|
||||
this = f"CASE WHEN {this} IS NULL THEN 1 ELSE 0 END{null_sort_order}, {this}"
|
||||
nulls_sort_change = ""
|
||||
|
||||
with_fill = self.sql(expression, "with_fill")
|
||||
with_fill = f" {with_fill}" if with_fill else ""
|
||||
|
@ -1961,10 +2031,14 @@ class Generator:
|
|||
return [locks, self.sql(expression, "sample")]
|
||||
|
||||
def select_sql(self, expression: exp.Select) -> str:
|
||||
into = expression.args.get("into")
|
||||
if not self.SUPPORTS_SELECT_INTO and into:
|
||||
into.pop()
|
||||
|
||||
hint = self.sql(expression, "hint")
|
||||
distinct = self.sql(expression, "distinct")
|
||||
distinct = f" {distinct}" if distinct else ""
|
||||
kind = self.sql(expression, "kind").upper()
|
||||
kind = self.sql(expression, "kind")
|
||||
limit = expression.args.get("limit")
|
||||
top = (
|
||||
self.limit_sql(limit, top=True)
|
||||
|
@ -2005,7 +2079,19 @@ class Generator:
|
|||
self.sql(expression, "into", comment=False),
|
||||
self.sql(expression, "from", comment=False),
|
||||
)
|
||||
return self.prepend_ctes(expression, sql)
|
||||
|
||||
sql = self.prepend_ctes(expression, sql)
|
||||
|
||||
if not self.SUPPORTS_SELECT_INTO and into:
|
||||
if into.args.get("temporary"):
|
||||
table_kind = " TEMPORARY"
|
||||
elif self.SUPPORTS_UNLOGGED_TABLES and into.args.get("unlogged"):
|
||||
table_kind = " UNLOGGED"
|
||||
else:
|
||||
table_kind = ""
|
||||
sql = f"CREATE{table_kind} TABLE {self.sql(into.this)} AS {sql}"
|
||||
|
||||
return sql
|
||||
|
||||
def schema_sql(self, expression: exp.Schema) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
|
@ -2266,29 +2352,35 @@ class Generator:
|
|||
return f"{self.func('MATCH', *expression.expressions)} AGAINST({self.sql(expression, 'this')}{modifier})"
|
||||
|
||||
def jsonkeyvalue_sql(self, expression: exp.JSONKeyValue) -> str:
|
||||
return f"{self.sql(expression, 'this')}: {self.sql(expression, 'expression')}"
|
||||
return f"{self.sql(expression, 'this')}{self.JSON_KEY_VALUE_PAIR_SEP} {self.sql(expression, 'expression')}"
|
||||
|
||||
def formatjson_sql(self, expression: exp.FormatJson) -> str:
|
||||
return f"{self.sql(expression, 'this')} FORMAT JSON"
|
||||
|
||||
def jsonobject_sql(self, expression: exp.JSONObject) -> str:
|
||||
def jsonobject_sql(self, expression: exp.JSONObject | exp.JSONObjectAgg) -> str:
|
||||
null_handling = expression.args.get("null_handling")
|
||||
null_handling = f" {null_handling}" if null_handling else ""
|
||||
|
||||
unique_keys = expression.args.get("unique_keys")
|
||||
if unique_keys is not None:
|
||||
unique_keys = f" {'WITH' if unique_keys else 'WITHOUT'} UNIQUE KEYS"
|
||||
else:
|
||||
unique_keys = ""
|
||||
|
||||
return_type = self.sql(expression, "return_type")
|
||||
return_type = f" RETURNING {return_type}" if return_type else ""
|
||||
encoding = self.sql(expression, "encoding")
|
||||
encoding = f" ENCODING {encoding}" if encoding else ""
|
||||
|
||||
return self.func(
|
||||
"JSON_OBJECT",
|
||||
"JSON_OBJECT" if isinstance(expression, exp.JSONObject) else "JSON_OBJECTAGG",
|
||||
*expression.expressions,
|
||||
suffix=f"{null_handling}{unique_keys}{return_type}{encoding})",
|
||||
)
|
||||
|
||||
def jsonobjectagg_sql(self, expression: exp.JSONObjectAgg) -> str:
|
||||
return self.jsonobject_sql(expression)
|
||||
|
||||
def jsonarray_sql(self, expression: exp.JSONArray) -> str:
|
||||
null_handling = expression.args.get("null_handling")
|
||||
null_handling = f" {null_handling}" if null_handling else ""
|
||||
|
@ -2385,7 +2477,7 @@ class Generator:
|
|||
def interval_sql(self, expression: exp.Interval) -> str:
|
||||
unit = self.sql(expression, "unit")
|
||||
if not self.INTERVAL_ALLOWS_PLURAL_FORM:
|
||||
unit = self.TIME_PART_SINGULARS.get(unit.lower(), unit)
|
||||
unit = self.TIME_PART_SINGULARS.get(unit, unit)
|
||||
unit = f" {unit}" if unit else ""
|
||||
|
||||
if self.SINGLE_STRING_INTERVAL:
|
||||
|
@ -2436,9 +2528,25 @@ class Generator:
|
|||
alias = f" AS {alias}" if alias else ""
|
||||
return f"{self.sql(expression, 'this')}{alias}"
|
||||
|
||||
def pivotalias_sql(self, expression: exp.PivotAlias) -> str:
|
||||
alias = expression.args["alias"]
|
||||
identifier_alias = isinstance(alias, exp.Identifier)
|
||||
|
||||
if identifier_alias and not self.UNPIVOT_ALIASES_ARE_IDENTIFIERS:
|
||||
alias.replace(exp.Literal.string(alias.output_name))
|
||||
elif not identifier_alias and self.UNPIVOT_ALIASES_ARE_IDENTIFIERS:
|
||||
alias.replace(exp.to_identifier(alias.output_name))
|
||||
|
||||
return self.alias_sql(expression)
|
||||
|
||||
def aliases_sql(self, expression: exp.Aliases) -> str:
|
||||
return f"{self.sql(expression, 'this')} AS ({self.expressions(expression, flat=True)})"
|
||||
|
||||
def atindex_sql(self, expression: exp.AtTimeZone) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
index = self.sql(expression, "expression")
|
||||
return f"{this} AT {index}"
|
||||
|
||||
def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
zone = self.sql(expression, "zone")
|
||||
|
@ -2500,7 +2608,7 @@ class Generator:
|
|||
return self.binary(expression, "COLLATE")
|
||||
|
||||
def command_sql(self, expression: exp.Command) -> str:
|
||||
return f"{self.sql(expression, 'this').upper()} {expression.text('expression').strip()}"
|
||||
return f"{self.sql(expression, 'this')} {expression.text('expression').strip()}"
|
||||
|
||||
def comment_sql(self, expression: exp.Comment) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
|
@ -3102,6 +3210,47 @@ class Generator:
|
|||
cond_for_null = arg.is_(exp.null())
|
||||
return self.sql(exp.func("IF", cond_for_null, exp.null(), exp.Array(expressions=[arg])))
|
||||
|
||||
def tsordstotime_sql(self, expression: exp.TsOrDsToTime) -> str:
|
||||
this = expression.this
|
||||
if isinstance(this, exp.TsOrDsToTime) or this.is_type(exp.DataType.Type.TIME):
|
||||
return self.sql(this)
|
||||
|
||||
return self.sql(exp.cast(this, "time"))
|
||||
|
||||
def tsordstodate_sql(self, expression: exp.TsOrDsToDate) -> str:
|
||||
this = expression.this
|
||||
time_format = self.format_time(expression)
|
||||
|
||||
if time_format and time_format not in (self.dialect.TIME_FORMAT, self.dialect.DATE_FORMAT):
|
||||
return self.sql(
|
||||
exp.cast(exp.StrToTime(this=this, format=expression.args["format"]), "date")
|
||||
)
|
||||
|
||||
if isinstance(this, exp.TsOrDsToDate) or this.is_type(exp.DataType.Type.DATE):
|
||||
return self.sql(this)
|
||||
|
||||
return self.sql(exp.cast(this, "date"))
|
||||
|
||||
def unixdate_sql(self, expression: exp.UnixDate) -> str:
|
||||
return self.sql(
|
||||
exp.func(
|
||||
"DATEDIFF",
|
||||
expression.this,
|
||||
exp.cast(exp.Literal.string("1970-01-01"), "date"),
|
||||
"day",
|
||||
)
|
||||
)
|
||||
|
||||
def lastday_sql(self, expression: exp.LastDay) -> str:
|
||||
if self.LAST_DAY_SUPPORTS_DATE_PART:
|
||||
return self.function_fallback_sql(expression)
|
||||
|
||||
unit = expression.text("unit")
|
||||
if unit and unit != "MONTH":
|
||||
self.unsupported("Date parts are not supported in LAST_DAY.")
|
||||
|
||||
return self.func("LAST_DAY", expression.this)
|
||||
|
||||
def _simplify_unless_literal(self, expression: E) -> E:
|
||||
if not isinstance(expression, exp.Literal):
|
||||
from sqlglot.optimizer.simplify import simplify
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue