Adding upstream version 23.7.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f1aa09959c
commit
27c061b7af
187 changed files with 86502 additions and 71397 deletions
|
@ -46,9 +46,11 @@ class Generator(metaclass=_Generator):
|
|||
'safe': Only quote identifiers that are case insensitive.
|
||||
normalize: Whether to normalize identifiers to lowercase.
|
||||
Default: False.
|
||||
pad: The pad size in a formatted string.
|
||||
pad: The pad size in a formatted string. For example, this affects the indentation of
|
||||
a projection in a query, relative to its nesting level.
|
||||
Default: 2.
|
||||
indent: The indentation size in a formatted string.
|
||||
indent: The indentation size in a formatted string. For example, this affects the
|
||||
indentation of subqueries and filters under a `WHERE` clause.
|
||||
Default: 2.
|
||||
normalize_functions: How to normalize function names. Possible values are:
|
||||
"upper" or True (default): Convert names to uppercase.
|
||||
|
@ -73,6 +75,7 @@ class Generator(metaclass=_Generator):
|
|||
TRANSFORMS: t.Dict[t.Type[exp.Expression], t.Callable[..., str]] = {
|
||||
**JSON_PATH_PART_TRANSFORMS,
|
||||
exp.AutoRefreshProperty: lambda self, e: f"AUTO REFRESH {self.sql(e, 'this')}",
|
||||
exp.BackupProperty: lambda self, e: f"BACKUP {self.sql(e, 'this')}",
|
||||
exp.CaseSpecificColumnConstraint: lambda _,
|
||||
e: f"{'NOT ' if e.args.get('not_') else ''}CASESPECIFIC",
|
||||
exp.CharacterSetColumnConstraint: lambda self, e: f"CHARACTER SET {self.sql(e, 'this')}",
|
||||
|
@ -83,15 +86,15 @@ class Generator(metaclass=_Generator):
|
|||
exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}",
|
||||
exp.CommentColumnConstraint: lambda self, e: f"COMMENT {self.sql(e, 'this')}",
|
||||
exp.CopyGrantsProperty: lambda *_: "COPY GRANTS",
|
||||
exp.DateAdd: lambda self, e: self.func(
|
||||
"DATE_ADD", e.this, e.expression, exp.Literal.string(e.text("unit"))
|
||||
),
|
||||
exp.DateFormatColumnConstraint: lambda self, e: f"FORMAT {self.sql(e, 'this')}",
|
||||
exp.DefaultColumnConstraint: lambda self, e: f"DEFAULT {self.sql(e, 'this')}",
|
||||
exp.EncodeColumnConstraint: lambda self, e: f"ENCODE {self.sql(e, 'this')}",
|
||||
exp.ExcludeColumnConstraint: lambda self, e: f"EXCLUDE {self.sql(e, 'this').lstrip()}",
|
||||
exp.ExecuteAsProperty: lambda self, e: self.naked_property(e),
|
||||
exp.ExternalProperty: lambda *_: "EXTERNAL",
|
||||
exp.GlobalProperty: lambda *_: "GLOBAL",
|
||||
exp.HeapProperty: lambda *_: "HEAP",
|
||||
exp.IcebergProperty: lambda *_: "ICEBERG",
|
||||
exp.InheritsProperty: lambda self, e: f"INHERITS ({self.expressions(e, flat=True)})",
|
||||
exp.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}",
|
||||
exp.InputModelProperty: lambda self, e: f"INPUT{self.sql(e, 'this')}",
|
||||
|
@ -123,6 +126,7 @@ class Generator(metaclass=_Generator):
|
|||
exp.SetConfigProperty: lambda self, e: self.sql(e, "this"),
|
||||
exp.SetProperty: lambda _, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
|
||||
exp.SettingsProperty: lambda self, e: f"SETTINGS{self.seg('')}{(self.expressions(e))}",
|
||||
exp.SharingProperty: lambda self, e: f"SHARING={self.sql(e, 'this')}",
|
||||
exp.SqlReadWriteProperty: lambda _, e: e.name,
|
||||
exp.SqlSecurityProperty: lambda _,
|
||||
e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}",
|
||||
|
@ -130,13 +134,17 @@ class Generator(metaclass=_Generator):
|
|||
exp.TemporaryProperty: lambda *_: "TEMPORARY",
|
||||
exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}",
|
||||
exp.Timestamp: lambda self, e: self.func("TIMESTAMP", e.this, e.expression),
|
||||
exp.ToMap: lambda self, e: f"MAP {self.sql(e, 'this')}",
|
||||
exp.ToTableProperty: lambda self, e: f"TO {self.sql(e.this)}",
|
||||
exp.TransformModelProperty: lambda self, e: self.func("TRANSFORM", *e.expressions),
|
||||
exp.TransientProperty: lambda *_: "TRANSIENT",
|
||||
exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
|
||||
exp.UnloggedProperty: lambda *_: "UNLOGGED",
|
||||
exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]),
|
||||
exp.ViewAttributeProperty: lambda self, e: f"WITH {self.sql(e, 'this')}",
|
||||
exp.VolatileProperty: lambda *_: "VOLATILE",
|
||||
exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}",
|
||||
exp.WithOperator: lambda self, e: f"{self.sql(e, 'this')} WITH {self.sql(e, 'op')}",
|
||||
}
|
||||
|
||||
# Whether null ordering is supported in order by
|
||||
|
@ -321,6 +329,9 @@ class Generator(metaclass=_Generator):
|
|||
# Whether any(f(x) for x in array) can be implemented by this dialect
|
||||
CAN_IMPLEMENT_ARRAY_ANY = False
|
||||
|
||||
# Whether the function TO_NUMBER is supported
|
||||
SUPPORTS_TO_NUMBER = True
|
||||
|
||||
TYPE_MAPPING = {
|
||||
exp.DataType.Type.NCHAR: "CHAR",
|
||||
exp.DataType.Type.NVARCHAR: "VARCHAR",
|
||||
|
@ -350,6 +361,18 @@ class Generator(metaclass=_Generator):
|
|||
"YEARS": "YEAR",
|
||||
}
|
||||
|
||||
AFTER_HAVING_MODIFIER_TRANSFORMS = {
|
||||
"cluster": lambda self, e: self.sql(e, "cluster"),
|
||||
"distribute": lambda self, e: self.sql(e, "distribute"),
|
||||
"qualify": lambda self, e: self.sql(e, "qualify"),
|
||||
"sort": lambda self, e: self.sql(e, "sort"),
|
||||
"windows": lambda self, e: (
|
||||
self.seg("WINDOW ") + self.expressions(e, key="windows", flat=True)
|
||||
if e.args.get("windows")
|
||||
else ""
|
||||
),
|
||||
}
|
||||
|
||||
TOKEN_MAPPING: t.Dict[TokenType, str] = {}
|
||||
|
||||
STRUCT_DELIMITER = ("<", ">")
|
||||
|
@ -361,6 +384,7 @@ class Generator(metaclass=_Generator):
|
|||
exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.AutoIncrementProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.AutoRefreshProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.BackupProperty: 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,
|
||||
|
@ -380,8 +404,10 @@ class Generator(metaclass=_Generator):
|
|||
exp.FallbackProperty: exp.Properties.Location.POST_NAME,
|
||||
exp.FileFormatProperty: exp.Properties.Location.POST_WITH,
|
||||
exp.FreespaceProperty: exp.Properties.Location.POST_NAME,
|
||||
exp.GlobalProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.HeapProperty: exp.Properties.Location.POST_WITH,
|
||||
exp.InheritsProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.IcebergProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.InputModelProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.IsolatedLoadingProperty: exp.Properties.Location.POST_NAME,
|
||||
exp.JournalProperty: exp.Properties.Location.POST_NAME,
|
||||
|
@ -414,6 +440,8 @@ class Generator(metaclass=_Generator):
|
|||
exp.SettingsProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SetProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.SetConfigProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SharingProperty: exp.Properties.Location.POST_EXPRESSION,
|
||||
exp.SequenceProperties: exp.Properties.Location.POST_EXPRESSION,
|
||||
exp.SortKeyProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SqlReadWriteProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.SqlSecurityProperty: exp.Properties.Location.POST_CREATE,
|
||||
|
@ -423,6 +451,8 @@ class Generator(metaclass=_Generator):
|
|||
exp.TransientProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.TransformModelProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.MergeTreeTTL: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.UnloggedProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.ViewAttributeProperty: exp.Properties.Location.POST_SCHEMA,
|
||||
exp.VolatileProperty: exp.Properties.Location.POST_CREATE,
|
||||
exp.WithDataProperty: exp.Properties.Location.POST_EXPRESSION,
|
||||
exp.WithJournalTableProperty: exp.Properties.Location.POST_NAME,
|
||||
|
@ -441,6 +471,7 @@ class Generator(metaclass=_Generator):
|
|||
exp.Insert,
|
||||
exp.Join,
|
||||
exp.Select,
|
||||
exp.Union,
|
||||
exp.Update,
|
||||
exp.Where,
|
||||
exp.With,
|
||||
|
@ -626,7 +657,7 @@ class Generator(metaclass=_Generator):
|
|||
if isinstance(expression, self.WITH_SEPARATED_COMMENTS):
|
||||
return (
|
||||
f"{self.sep()}{comments_sql}{sql}"
|
||||
if sql[0].isspace()
|
||||
if not sql or sql[0].isspace()
|
||||
else f"{comments_sql}{self.sep()}{sql}"
|
||||
)
|
||||
|
||||
|
@ -869,7 +900,9 @@ class Generator(metaclass=_Generator):
|
|||
this = f" {this}" if this else ""
|
||||
index_type = expression.args.get("index_type")
|
||||
index_type = f" USING {index_type}" if index_type else ""
|
||||
return f"UNIQUE{this}{index_type}"
|
||||
on_conflict = self.sql(expression, "on_conflict")
|
||||
on_conflict = f" {on_conflict}" if on_conflict else ""
|
||||
return f"UNIQUE{this}{index_type}{on_conflict}"
|
||||
|
||||
def createable_sql(self, expression: exp.Create, locations: t.DefaultDict) -> str:
|
||||
return self.sql(expression, "this")
|
||||
|
@ -961,6 +994,31 @@ class Generator(metaclass=_Generator):
|
|||
expression_sql = f"CREATE{modifiers} {kind}{exists_sql} {this}{properties_sql}{expression_sql}{postexpression_props_sql}{index_sql}{no_schema_binding}{clone}"
|
||||
return self.prepend_ctes(expression, expression_sql)
|
||||
|
||||
def sequenceproperties_sql(self, expression: exp.SequenceProperties) -> str:
|
||||
start = self.sql(expression, "start")
|
||||
start = f"START WITH {start}" if start else ""
|
||||
increment = self.sql(expression, "increment")
|
||||
increment = f" INCREMENT BY {increment}" if increment else ""
|
||||
minvalue = self.sql(expression, "minvalue")
|
||||
minvalue = f" MINVALUE {minvalue}" if minvalue else ""
|
||||
maxvalue = self.sql(expression, "maxvalue")
|
||||
maxvalue = f" MAXVALUE {maxvalue}" if maxvalue else ""
|
||||
owned = self.sql(expression, "owned")
|
||||
owned = f" OWNED BY {owned}" if owned else ""
|
||||
|
||||
cache = expression.args.get("cache")
|
||||
if cache is None:
|
||||
cache_str = ""
|
||||
elif cache is True:
|
||||
cache_str = " CACHE"
|
||||
else:
|
||||
cache_str = f" CACHE {cache}"
|
||||
|
||||
options = self.expressions(expression, key="options", flat=True, sep=" ")
|
||||
options = f" {options}" if options else ""
|
||||
|
||||
return f"{start}{increment}{minvalue}{maxvalue}{cache_str}{options}{owned}".lstrip()
|
||||
|
||||
def clone_sql(self, expression: exp.Clone) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
shallow = "SHALLOW " if expression.args.get("shallow") else ""
|
||||
|
@ -968,8 +1026,9 @@ class Generator(metaclass=_Generator):
|
|||
return f"{shallow}{keyword} {this}"
|
||||
|
||||
def describe_sql(self, expression: exp.Describe) -> str:
|
||||
extended = " EXTENDED" if expression.args.get("extended") else ""
|
||||
return f"DESCRIBE{extended} {self.sql(expression, 'this')}"
|
||||
style = expression.args.get("style")
|
||||
style = f" {style}" if style else ""
|
||||
return f"DESCRIBE{style} {self.sql(expression, 'this')}"
|
||||
|
||||
def heredoc_sql(self, expression: exp.Heredoc) -> str:
|
||||
tag = self.sql(expression, "tag")
|
||||
|
@ -993,7 +1052,14 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
def cte_sql(self, expression: exp.CTE) -> str:
|
||||
alias = self.sql(expression, "alias")
|
||||
return f"{alias} AS {self.wrap(expression)}"
|
||||
|
||||
materialized = expression.args.get("materialized")
|
||||
if materialized is False:
|
||||
materialized = "NOT MATERIALIZED "
|
||||
elif materialized:
|
||||
materialized = "MATERIALIZED "
|
||||
|
||||
return f"{alias} AS {materialized or ''}{self.wrap(expression)}"
|
||||
|
||||
def tablealias_sql(self, expression: exp.TableAlias) -> str:
|
||||
alias = self.sql(expression, "this")
|
||||
|
@ -1044,7 +1110,7 @@ class Generator(metaclass=_Generator):
|
|||
return f"{self.dialect.QUOTE_START}{this}{self.dialect.QUOTE_END}"
|
||||
|
||||
def rawstring_sql(self, expression: exp.RawString) -> str:
|
||||
string = self.escape_str(expression.this.replace("\\", "\\\\"))
|
||||
string = self.escape_str(expression.this.replace("\\", "\\\\"), escape_backslash=False)
|
||||
return f"{self.dialect.QUOTE_START}{string}{self.dialect.QUOTE_END}"
|
||||
|
||||
def datatypeparam_sql(self, expression: exp.DataTypeParam) -> str:
|
||||
|
@ -1114,6 +1180,8 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
def drop_sql(self, expression: exp.Drop) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
expressions = self.expressions(expression, flat=True)
|
||||
expressions = f" ({expressions})" if expressions else ""
|
||||
kind = expression.args["kind"]
|
||||
exists_sql = " IF EXISTS " if expression.args.get("exists") else " "
|
||||
temporary = " TEMPORARY" if expression.args.get("temporary") else ""
|
||||
|
@ -1121,15 +1189,10 @@ class Generator(metaclass=_Generator):
|
|||
cascade = " CASCADE" if expression.args.get("cascade") else ""
|
||||
constraints = " CONSTRAINTS" if expression.args.get("constraints") else ""
|
||||
purge = " PURGE" if expression.args.get("purge") else ""
|
||||
return (
|
||||
f"DROP{temporary}{materialized} {kind}{exists_sql}{this}{cascade}{constraints}{purge}"
|
||||
)
|
||||
return f"DROP{temporary}{materialized} {kind}{exists_sql}{this}{expressions}{cascade}{constraints}{purge}"
|
||||
|
||||
def except_sql(self, expression: exp.Except) -> str:
|
||||
return self.prepend_ctes(
|
||||
expression,
|
||||
self.set_operation(expression, self.except_op(expression)),
|
||||
)
|
||||
return self.set_operations(expression)
|
||||
|
||||
def except_op(self, expression: exp.Except) -> str:
|
||||
return f"EXCEPT{'' if expression.args.get('distinct') else ' ALL'}"
|
||||
|
@ -1163,17 +1226,9 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
return f" /*+ {self.expressions(expression, sep=self.QUERY_HINT_SEP).strip()} */"
|
||||
|
||||
def index_sql(self, expression: exp.Index) -> str:
|
||||
unique = "UNIQUE " if expression.args.get("unique") else ""
|
||||
primary = "PRIMARY " if expression.args.get("primary") else ""
|
||||
amp = "AMP " if expression.args.get("amp") else ""
|
||||
name = self.sql(expression, "this")
|
||||
name = f"{name} " if name else ""
|
||||
table = self.sql(expression, "table")
|
||||
table = f"{self.INDEX_ON} {table}" if table else ""
|
||||
def indexparameters_sql(self, expression: exp.IndexParameters) -> str:
|
||||
using = self.sql(expression, "using")
|
||||
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)
|
||||
|
@ -1182,7 +1237,26 @@ class Generator(metaclass=_Generator):
|
|||
include = self.expressions(expression, key="include", flat=True)
|
||||
if include:
|
||||
include = f" INCLUDE ({include})"
|
||||
return f"{unique}{primary}{amp}{index}{name}{table}{using}{columns}{include}{partition_by}{where}"
|
||||
with_storage = self.expressions(expression, key="with_storage", flat=True)
|
||||
with_storage = f" WITH ({with_storage})" if with_storage else ""
|
||||
tablespace = self.sql(expression, "tablespace")
|
||||
tablespace = f" USING INDEX TABLESPACE {tablespace}" if tablespace else ""
|
||||
|
||||
return f"{using}{columns}{include}{with_storage}{tablespace}{partition_by}{where}"
|
||||
|
||||
def index_sql(self, expression: exp.Index) -> str:
|
||||
unique = "UNIQUE " if expression.args.get("unique") else ""
|
||||
primary = "PRIMARY " if expression.args.get("primary") else ""
|
||||
amp = "AMP " if expression.args.get("amp") else ""
|
||||
name = self.sql(expression, "this")
|
||||
name = f"{name} " if name else ""
|
||||
table = self.sql(expression, "table")
|
||||
table = f"{self.INDEX_ON} {table}" if table else ""
|
||||
|
||||
index = "INDEX " if not table else ""
|
||||
|
||||
params = self.sql(expression, "params")
|
||||
return f"{unique}{primary}{amp}{index}{name}{table}{params}"
|
||||
|
||||
def identifier_sql(self, expression: exp.Identifier) -> str:
|
||||
text = expression.name
|
||||
|
@ -1371,15 +1445,9 @@ class Generator(metaclass=_Generator):
|
|||
no = " NO" if no else ""
|
||||
concurrent = expression.args.get("concurrent")
|
||||
concurrent = " CONCURRENT" if concurrent else ""
|
||||
|
||||
for_ = ""
|
||||
if expression.args.get("for_all"):
|
||||
for_ = " FOR ALL"
|
||||
elif expression.args.get("for_insert"):
|
||||
for_ = " FOR INSERT"
|
||||
elif expression.args.get("for_none"):
|
||||
for_ = " FOR NONE"
|
||||
return f"WITH{no}{concurrent} ISOLATED LOADING{for_}"
|
||||
target = self.sql(expression, "target")
|
||||
target = f" {target}" if target else ""
|
||||
return f"WITH{no}{concurrent} ISOLATED LOADING{target}"
|
||||
|
||||
def partitionboundspec_sql(self, expression: exp.PartitionBoundSpec) -> str:
|
||||
if isinstance(expression.this, list):
|
||||
|
@ -1437,6 +1505,7 @@ class Generator(metaclass=_Generator):
|
|||
return f"{sql})"
|
||||
|
||||
def insert_sql(self, expression: exp.Insert) -> str:
|
||||
hint = self.sql(expression, "hint")
|
||||
overwrite = expression.args.get("overwrite")
|
||||
|
||||
if isinstance(expression.this, exp.Directory):
|
||||
|
@ -1447,7 +1516,9 @@ class Generator(metaclass=_Generator):
|
|||
alternative = expression.args.get("alternative")
|
||||
alternative = f" OR {alternative}" if alternative else ""
|
||||
ignore = " IGNORE" if expression.args.get("ignore") else ""
|
||||
|
||||
is_function = expression.args.get("is_function")
|
||||
if is_function:
|
||||
this = f"{this} FUNCTION"
|
||||
this = f"{this} {self.sql(expression, 'this')}"
|
||||
|
||||
exists = " IF EXISTS" if expression.args.get("exists") else ""
|
||||
|
@ -1457,23 +1528,21 @@ class Generator(metaclass=_Generator):
|
|||
where = self.sql(expression, "where")
|
||||
where = f"{self.sep()}REPLACE WHERE {where}" if where else ""
|
||||
expression_sql = f"{self.sep()}{self.sql(expression, 'expression')}"
|
||||
conflict = self.sql(expression, "conflict")
|
||||
on_conflict = self.sql(expression, "conflict")
|
||||
on_conflict = f" {on_conflict}" if on_conflict else ""
|
||||
by_name = " BY NAME" if expression.args.get("by_name") else ""
|
||||
returning = self.sql(expression, "returning")
|
||||
|
||||
if self.RETURNING_END:
|
||||
expression_sql = f"{expression_sql}{conflict}{returning}"
|
||||
expression_sql = f"{expression_sql}{on_conflict}{returning}"
|
||||
else:
|
||||
expression_sql = f"{returning}{expression_sql}{conflict}"
|
||||
expression_sql = f"{returning}{expression_sql}{on_conflict}"
|
||||
|
||||
sql = f"INSERT{alternative}{ignore}{this}{by_name}{exists}{partition_sql}{where}{expression_sql}"
|
||||
sql = f"INSERT{hint}{alternative}{ignore}{this}{by_name}{exists}{partition_sql}{where}{expression_sql}"
|
||||
return self.prepend_ctes(expression, sql)
|
||||
|
||||
def intersect_sql(self, expression: exp.Intersect) -> str:
|
||||
return self.prepend_ctes(
|
||||
expression,
|
||||
self.set_operation(expression, self.intersect_op(expression)),
|
||||
)
|
||||
return self.set_operations(expression)
|
||||
|
||||
def intersect_op(self, expression: exp.Intersect) -> str:
|
||||
return f"INTERSECT{'' if expression.args.get('distinct') else ' ALL'}"
|
||||
|
@ -1496,33 +1565,36 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
def onconflict_sql(self, expression: exp.OnConflict) -> str:
|
||||
conflict = "ON DUPLICATE KEY" if expression.args.get("duplicate") else "ON CONFLICT"
|
||||
|
||||
constraint = self.sql(expression, "constraint")
|
||||
if constraint:
|
||||
constraint = f"ON CONSTRAINT {constraint}"
|
||||
key = self.expressions(expression, key="key", flat=True)
|
||||
do = "" if expression.args.get("duplicate") else " DO "
|
||||
nothing = "NOTHING" if expression.args.get("nothing") else ""
|
||||
constraint = f" ON CONSTRAINT {constraint}" if constraint else ""
|
||||
|
||||
conflict_keys = self.expressions(expression, key="conflict_keys", flat=True)
|
||||
conflict_keys = f"({conflict_keys}) " if conflict_keys else " "
|
||||
action = self.sql(expression, "action")
|
||||
|
||||
expressions = self.expressions(expression, flat=True)
|
||||
set_keyword = "SET " if self.DUPLICATE_KEY_UPDATE_WITH_SET else ""
|
||||
if expressions:
|
||||
expressions = f"UPDATE {set_keyword}{expressions}"
|
||||
return f"{self.seg(conflict)} {constraint}{key}{do}{nothing}{expressions}"
|
||||
set_keyword = "SET " if self.DUPLICATE_KEY_UPDATE_WITH_SET else ""
|
||||
expressions = f" {set_keyword}{expressions}"
|
||||
|
||||
return f"{conflict}{constraint}{conflict_keys}{action}{expressions}"
|
||||
|
||||
def returning_sql(self, expression: exp.Returning) -> str:
|
||||
return f"{self.seg('RETURNING')} {self.expressions(expression, flat=True)}"
|
||||
|
||||
def rowformatdelimitedproperty_sql(self, expression: exp.RowFormatDelimitedProperty) -> str:
|
||||
fields = expression.args.get("fields")
|
||||
fields = self.sql(expression, "fields")
|
||||
fields = f" FIELDS TERMINATED BY {fields}" if fields else ""
|
||||
escaped = expression.args.get("escaped")
|
||||
escaped = self.sql(expression, "escaped")
|
||||
escaped = f" ESCAPED BY {escaped}" if escaped else ""
|
||||
items = expression.args.get("collection_items")
|
||||
items = self.sql(expression, "collection_items")
|
||||
items = f" COLLECTION ITEMS TERMINATED BY {items}" if items else ""
|
||||
keys = expression.args.get("map_keys")
|
||||
keys = self.sql(expression, "map_keys")
|
||||
keys = f" MAP KEYS TERMINATED BY {keys}" if keys else ""
|
||||
lines = expression.args.get("lines")
|
||||
lines = self.sql(expression, "lines")
|
||||
lines = f" LINES TERMINATED BY {lines}" if lines else ""
|
||||
null = expression.args.get("null")
|
||||
null = self.sql(expression, "null")
|
||||
null = f" NULL DEFINED AS {null}" if null else ""
|
||||
return f"ROW FORMAT DELIMITED{fields}{escaped}{items}{keys}{lines}{null}"
|
||||
|
||||
|
@ -1563,7 +1635,9 @@ class Generator(metaclass=_Generator):
|
|||
hints = f" {hints}" if hints and self.TABLE_HINTS else ""
|
||||
pivots = self.expressions(expression, key="pivots", sep=" ", flat=True)
|
||||
pivots = f" {pivots}" if pivots else ""
|
||||
joins = self.expressions(expression, key="joins", sep="", skip_first=True)
|
||||
joins = self.indent(
|
||||
self.expressions(expression, key="joins", sep="", flat=True), skip_first=True
|
||||
)
|
||||
laterals = self.expressions(expression, key="laterals", sep="")
|
||||
|
||||
file_format = self.sql(expression, "format")
|
||||
|
@ -1673,9 +1747,11 @@ class Generator(metaclass=_Generator):
|
|||
sql = f"UPDATE {this} SET {set_sql}{expression_sql}{order}{limit}"
|
||||
return self.prepend_ctes(expression, sql)
|
||||
|
||||
def values_sql(self, expression: exp.Values) -> str:
|
||||
def values_sql(self, expression: exp.Values, values_as_table: bool = True) -> str:
|
||||
values_as_table = values_as_table and self.VALUES_AS_TABLE
|
||||
|
||||
# The VALUES clause is still valid in an `INSERT INTO ..` statement, for example
|
||||
if self.VALUES_AS_TABLE or not expression.find_ancestor(exp.From, exp.Join):
|
||||
if values_as_table or not expression.find_ancestor(exp.From, exp.Join):
|
||||
args = self.expressions(expression)
|
||||
alias = self.sql(expression, "alias")
|
||||
values = f"VALUES{self.seg('')}{args}"
|
||||
|
@ -1769,8 +1845,9 @@ class Generator(metaclass=_Generator):
|
|||
def connect_sql(self, expression: exp.Connect) -> str:
|
||||
start = self.sql(expression, "start")
|
||||
start = self.seg(f"START WITH {start}") if start else ""
|
||||
nocycle = " NOCYCLE" if expression.args.get("nocycle") else ""
|
||||
connect = self.sql(expression, "connect")
|
||||
connect = self.seg(f"CONNECT BY {connect}")
|
||||
connect = self.seg(f"CONNECT BY{nocycle} {connect}")
|
||||
return start + connect
|
||||
|
||||
def prior_sql(self, expression: exp.Prior) -> str:
|
||||
|
@ -1793,6 +1870,8 @@ class Generator(metaclass=_Generator):
|
|||
)
|
||||
if op
|
||||
)
|
||||
match_cond = self.sql(expression, "match_condition")
|
||||
match_cond = f" MATCH_CONDITION ({match_cond})" if match_cond else ""
|
||||
on_sql = self.sql(expression, "on")
|
||||
using = expression.args.get("using")
|
||||
|
||||
|
@ -1816,7 +1895,7 @@ class Generator(metaclass=_Generator):
|
|||
return f", {this_sql}"
|
||||
|
||||
op_sql = f"{op_sql} JOIN" if op_sql else "JOIN"
|
||||
return f"{self.seg(op_sql)} {this_sql}{on_sql}"
|
||||
return f"{self.seg(op_sql)} {this_sql}{match_cond}{on_sql}"
|
||||
|
||||
def lambda_sql(self, expression: exp.Lambda, arrow_sep: str = "->") -> str:
|
||||
args = self.expressions(expression, flat=True)
|
||||
|
@ -1919,13 +1998,17 @@ class Generator(metaclass=_Generator):
|
|||
text = f"{self.dialect.QUOTE_START}{self.escape_str(text)}{self.dialect.QUOTE_END}"
|
||||
return text
|
||||
|
||||
def escape_str(self, text: str) -> str:
|
||||
text = text.replace(self.dialect.QUOTE_END, self._escaped_quote_end)
|
||||
if self.dialect.INVERSE_ESCAPE_SEQUENCES:
|
||||
text = "".join(self.dialect.INVERSE_ESCAPE_SEQUENCES.get(ch, ch) for ch in text)
|
||||
elif self.pretty:
|
||||
def escape_str(self, text: str, escape_backslash: bool = True) -> str:
|
||||
if self.dialect.ESCAPED_SEQUENCES:
|
||||
to_escaped = self.dialect.ESCAPED_SEQUENCES
|
||||
text = "".join(
|
||||
to_escaped.get(ch, ch) if escape_backslash or ch != "\\" else ch for ch in text
|
||||
)
|
||||
|
||||
if self.pretty:
|
||||
text = text.replace("\n", self.SENTINEL_LINE_BREAK)
|
||||
return text
|
||||
|
||||
return text.replace(self.dialect.QUOTE_END, self._escaped_quote_end)
|
||||
|
||||
def loaddata_sql(self, expression: exp.LoadData) -> str:
|
||||
local = " LOCAL" if expression.args.get("local") else ""
|
||||
|
@ -2016,7 +2099,7 @@ class Generator(metaclass=_Generator):
|
|||
self.unsupported(
|
||||
f"'{nulls_sort_change.strip()}' translation not supported with positional ordering"
|
||||
)
|
||||
else:
|
||||
elif not isinstance(expression.this, exp.Rand):
|
||||
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 = ""
|
||||
|
@ -2059,24 +2142,13 @@ class Generator(metaclass=_Generator):
|
|||
return f"{self.seg('MATCH_RECOGNIZE')} {self.wrap(body)}{alias}"
|
||||
|
||||
def query_modifiers(self, expression: exp.Expression, *sqls: str) -> str:
|
||||
limit: t.Optional[exp.Fetch | exp.Limit] = expression.args.get("limit")
|
||||
|
||||
# If the limit is generated as TOP, we need to ensure it's not generated twice
|
||||
with_offset_limit_modifiers = not isinstance(limit, exp.Limit) or not self.LIMIT_IS_TOP
|
||||
limit = expression.args.get("limit")
|
||||
|
||||
if self.LIMIT_FETCH == "LIMIT" and isinstance(limit, exp.Fetch):
|
||||
limit = exp.Limit(expression=exp.maybe_copy(limit.args.get("count")))
|
||||
elif self.LIMIT_FETCH == "FETCH" and isinstance(limit, exp.Limit):
|
||||
limit = exp.Fetch(direction="FIRST", count=exp.maybe_copy(limit.expression))
|
||||
|
||||
fetch = isinstance(limit, exp.Fetch)
|
||||
|
||||
offset_limit_modifiers = (
|
||||
self.offset_limit_modifiers(expression, fetch, limit)
|
||||
if with_offset_limit_modifiers
|
||||
else []
|
||||
)
|
||||
|
||||
options = self.expressions(expression, key="options")
|
||||
if options:
|
||||
options = f" OPTION{self.wrap(options)}"
|
||||
|
@ -2091,9 +2163,9 @@ class Generator(metaclass=_Generator):
|
|||
self.sql(expression, "where"),
|
||||
self.sql(expression, "group"),
|
||||
self.sql(expression, "having"),
|
||||
*self.after_having_modifiers(expression),
|
||||
*[gen(self, expression) for gen in self.AFTER_HAVING_MODIFIER_TRANSFORMS.values()],
|
||||
self.sql(expression, "order"),
|
||||
*offset_limit_modifiers,
|
||||
*self.offset_limit_modifiers(expression, isinstance(limit, exp.Fetch), limit),
|
||||
*self.after_limit_modifiers(expression),
|
||||
options,
|
||||
sep="",
|
||||
|
@ -2110,19 +2182,6 @@ class Generator(metaclass=_Generator):
|
|||
self.sql(limit) if fetch else self.sql(expression, "offset"),
|
||||
]
|
||||
|
||||
def after_having_modifiers(self, expression: exp.Expression) -> t.List[str]:
|
||||
return [
|
||||
self.sql(expression, "qualify"),
|
||||
(
|
||||
self.seg("WINDOW ") + self.expressions(expression, key="windows", flat=True)
|
||||
if expression.args.get("windows")
|
||||
else ""
|
||||
),
|
||||
self.sql(expression, "distribute"),
|
||||
self.sql(expression, "sort"),
|
||||
self.sql(expression, "cluster"),
|
||||
]
|
||||
|
||||
def after_limit_modifiers(self, expression: exp.Expression) -> t.List[str]:
|
||||
locks = self.expressions(expression, key="locks", sep=" ")
|
||||
locks = f" {locks}" if locks else ""
|
||||
|
@ -2137,12 +2196,13 @@ class Generator(metaclass=_Generator):
|
|||
distinct = self.sql(expression, "distinct")
|
||||
distinct = f" {distinct}" if distinct else ""
|
||||
kind = self.sql(expression, "kind")
|
||||
|
||||
limit = expression.args.get("limit")
|
||||
top = (
|
||||
self.limit_sql(limit, top=True)
|
||||
if isinstance(limit, exp.Limit) and self.LIMIT_IS_TOP
|
||||
else ""
|
||||
)
|
||||
if isinstance(limit, exp.Limit) and self.LIMIT_IS_TOP:
|
||||
top = self.limit_sql(limit, top=True)
|
||||
limit.pop()
|
||||
else:
|
||||
top = ""
|
||||
|
||||
expressions = self.expressions(expression)
|
||||
|
||||
|
@ -2220,7 +2280,7 @@ class Generator(metaclass=_Generator):
|
|||
return f"@@{kind}{this}"
|
||||
|
||||
def placeholder_sql(self, expression: exp.Placeholder) -> str:
|
||||
return f"{self.NAMED_PLACEHOLDER_TOKEN}{expression.name}" if expression.name else "?"
|
||||
return f"{self.NAMED_PLACEHOLDER_TOKEN}{expression.name}" if expression.this else "?"
|
||||
|
||||
def subquery_sql(self, expression: exp.Subquery, sep: str = " AS ") -> str:
|
||||
alias = self.sql(expression, "alias")
|
||||
|
@ -2236,11 +2296,32 @@ class Generator(metaclass=_Generator):
|
|||
this = self.indent(self.sql(expression, "this"))
|
||||
return f"{self.seg('QUALIFY')}{self.sep()}{this}"
|
||||
|
||||
def set_operations(self, expression: exp.Union) -> str:
|
||||
sqls: t.List[str] = []
|
||||
stack: t.List[t.Union[str, exp.Expression]] = [expression]
|
||||
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
|
||||
if isinstance(node, exp.Union):
|
||||
stack.append(node.expression)
|
||||
stack.append(
|
||||
self.maybe_comment(
|
||||
getattr(self, f"{node.key}_op")(node),
|
||||
expression=node.this,
|
||||
comments=node.comments,
|
||||
)
|
||||
)
|
||||
stack.append(node.this)
|
||||
else:
|
||||
sqls.append(self.sql(node))
|
||||
|
||||
this = self.sep().join(sqls)
|
||||
this = self.query_modifiers(expression, this)
|
||||
return self.prepend_ctes(expression, this)
|
||||
|
||||
def union_sql(self, expression: exp.Union) -> str:
|
||||
return self.prepend_ctes(
|
||||
expression,
|
||||
self.set_operation(expression, self.union_op(expression)),
|
||||
)
|
||||
return self.set_operations(expression)
|
||||
|
||||
def union_op(self, expression: exp.Union) -> str:
|
||||
kind = " DISTINCT" if self.EXPLICIT_UNION else ""
|
||||
|
@ -2345,8 +2426,10 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
def any_sql(self, expression: exp.Any) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
if isinstance(expression.this, exp.UNWRAPPED_QUERIES):
|
||||
this = self.wrap(this)
|
||||
if isinstance(expression.this, (*exp.UNWRAPPED_QUERIES, exp.Paren)):
|
||||
if isinstance(expression.this, exp.UNWRAPPED_QUERIES):
|
||||
this = self.wrap(this)
|
||||
return f"ANY{this}"
|
||||
return f"ANY {this}"
|
||||
|
||||
def exists_sql(self, expression: exp.Exists) -> str:
|
||||
|
@ -2632,13 +2715,8 @@ class Generator(metaclass=_Generator):
|
|||
return self.func(self.sql(expression, "this"), *expression.expressions)
|
||||
|
||||
def paren_sql(self, expression: exp.Paren) -> str:
|
||||
if isinstance(expression.unnest(), exp.Select):
|
||||
sql = self.wrap(expression)
|
||||
else:
|
||||
sql = self.seg(self.indent(self.sql(expression, "this")), sep="")
|
||||
sql = f"({sql}{self.seg(')', sep='')}"
|
||||
|
||||
return self.prepend_ctes(expression, sql)
|
||||
sql = self.seg(self.indent(self.sql(expression, "this")), sep="")
|
||||
return f"({sql}{self.seg(')', sep='')}"
|
||||
|
||||
def neg_sql(self, expression: exp.Neg) -> str:
|
||||
# This makes sure we don't convert "- - 5" to "--5", which is a comment
|
||||
|
@ -2686,23 +2764,55 @@ class Generator(metaclass=_Generator):
|
|||
def add_sql(self, expression: exp.Add) -> str:
|
||||
return self.binary(expression, "+")
|
||||
|
||||
def and_sql(self, expression: exp.And) -> str:
|
||||
return self.connector_sql(expression, "AND")
|
||||
def and_sql(
|
||||
self, expression: exp.And, stack: t.Optional[t.List[str | exp.Expression]] = None
|
||||
) -> str:
|
||||
return self.connector_sql(expression, "AND", stack)
|
||||
|
||||
def xor_sql(self, expression: exp.Xor) -> str:
|
||||
return self.connector_sql(expression, "XOR")
|
||||
def or_sql(
|
||||
self, expression: exp.Or, stack: t.Optional[t.List[str | exp.Expression]] = None
|
||||
) -> str:
|
||||
return self.connector_sql(expression, "OR", stack)
|
||||
|
||||
def connector_sql(self, expression: exp.Connector, op: str) -> str:
|
||||
if not self.pretty:
|
||||
return self.binary(expression, op)
|
||||
def xor_sql(
|
||||
self, expression: exp.Xor, stack: t.Optional[t.List[str | exp.Expression]] = None
|
||||
) -> str:
|
||||
return self.connector_sql(expression, "XOR", stack)
|
||||
|
||||
sqls = tuple(
|
||||
self.maybe_comment(self.sql(e), e, e.parent.comments or []) if i != 1 else self.sql(e)
|
||||
for i, e in enumerate(expression.flatten(unnest=False))
|
||||
)
|
||||
def connector_sql(
|
||||
self,
|
||||
expression: exp.Connector,
|
||||
op: str,
|
||||
stack: t.Optional[t.List[str | exp.Expression]] = None,
|
||||
) -> str:
|
||||
if stack is not None:
|
||||
if expression.expressions:
|
||||
stack.append(self.expressions(expression, sep=f" {op} "))
|
||||
else:
|
||||
stack.append(expression.right)
|
||||
if expression.comments:
|
||||
for comment in expression.comments:
|
||||
op += f" /*{self.pad_comment(comment)}*/"
|
||||
stack.extend((op, expression.left))
|
||||
return op
|
||||
|
||||
sep = "\n" if self.text_width(sqls) > self.max_text_width else " "
|
||||
return f"{sep}{op} ".join(sqls)
|
||||
stack = [expression]
|
||||
sqls: t.List[str] = []
|
||||
ops = set()
|
||||
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
if isinstance(node, exp.Connector):
|
||||
ops.add(getattr(self, f"{node.key}_sql")(node, stack))
|
||||
else:
|
||||
sql = self.sql(node)
|
||||
if sqls and sqls[-1] in ops:
|
||||
sqls[-1] += f" {sql}"
|
||||
else:
|
||||
sqls.append(sql)
|
||||
|
||||
sep = "\n" if self.pretty and self.text_width(sqls) > self.max_text_width else " "
|
||||
return sep.join(sqls)
|
||||
|
||||
def bitwiseand_sql(self, expression: exp.BitwiseAnd) -> str:
|
||||
return self.binary(expression, "&")
|
||||
|
@ -2727,7 +2837,9 @@ class Generator(metaclass=_Generator):
|
|||
format_sql = f" FORMAT {format_sql}" if format_sql else ""
|
||||
to_sql = self.sql(expression, "to")
|
||||
to_sql = f" {to_sql}" if to_sql else ""
|
||||
return f"{safe_prefix or ''}CAST({self.sql(expression, 'this')} AS{to_sql}{format_sql})"
|
||||
action = self.sql(expression, "action")
|
||||
action = f" {action}" if action else ""
|
||||
return f"{safe_prefix or ''}CAST({self.sql(expression, 'this')} AS{to_sql}{format_sql}{action})"
|
||||
|
||||
def currentdate_sql(self, expression: exp.CurrentDate) -> str:
|
||||
zone = self.sql(expression, "this")
|
||||
|
@ -2817,7 +2929,7 @@ class Generator(metaclass=_Generator):
|
|||
# Remove db from tables
|
||||
expression = expression.transform(
|
||||
lambda n: exp.table_(n.this) if isinstance(n, exp.Table) else n
|
||||
)
|
||||
).assert_is(exp.RenameTable)
|
||||
this = self.sql(expression, "this")
|
||||
return f"RENAME TO {this}"
|
||||
|
||||
|
@ -2889,30 +3001,6 @@ class Generator(metaclass=_Generator):
|
|||
kind = "MAX" if expression.args.get("max") else "MIN"
|
||||
return f"{this_sql} HAVING {kind} {expression_sql}"
|
||||
|
||||
def _embed_ignore_nulls(self, expression: exp.IgnoreNulls | exp.RespectNulls, text: str) -> str:
|
||||
if self.IGNORE_NULLS_IN_FUNC and not expression.meta.get("inline"):
|
||||
# The first modifier here will be the one closest to the AggFunc's arg
|
||||
mods = sorted(
|
||||
expression.find_all(exp.HavingMax, exp.Order, exp.Limit),
|
||||
key=lambda x: 0
|
||||
if isinstance(x, exp.HavingMax)
|
||||
else (1 if isinstance(x, exp.Order) else 2),
|
||||
)
|
||||
|
||||
if mods:
|
||||
mod = mods[0]
|
||||
this = expression.__class__(this=mod.this.copy())
|
||||
this.meta["inline"] = True
|
||||
mod.this.replace(this)
|
||||
return self.sql(expression.this)
|
||||
|
||||
agg_func = expression.find(exp.AggFunc)
|
||||
|
||||
if agg_func:
|
||||
return self.sql(agg_func)[:-1] + f" {text})"
|
||||
|
||||
return f"{self.sql(expression, 'this')} {text}"
|
||||
|
||||
def intdiv_sql(self, expression: exp.IntDiv) -> str:
|
||||
return self.sql(
|
||||
exp.Cast(
|
||||
|
@ -2933,9 +3021,7 @@ class Generator(metaclass=_Generator):
|
|||
r.replace(exp.Nullif(this=r.copy(), expression=exp.Literal.number(0)))
|
||||
|
||||
if self.dialect.TYPED_DIVISION and not expression.args.get("typed"):
|
||||
if not l.is_type(*exp.DataType.FLOAT_TYPES) and not r.is_type(
|
||||
*exp.DataType.FLOAT_TYPES
|
||||
):
|
||||
if not l.is_type(*exp.DataType.REAL_TYPES) and not r.is_type(*exp.DataType.REAL_TYPES):
|
||||
l.replace(exp.cast(l.copy(), to=exp.DataType.Type.DOUBLE))
|
||||
|
||||
elif not self.dialect.TYPED_DIVISION and expression.args.get("typed"):
|
||||
|
@ -3019,9 +3105,6 @@ class Generator(metaclass=_Generator):
|
|||
def nullsafeneq_sql(self, expression: exp.NullSafeNEQ) -> str:
|
||||
return self.binary(expression, "IS DISTINCT FROM")
|
||||
|
||||
def or_sql(self, expression: exp.Or) -> str:
|
||||
return self.connector_sql(expression, "OR")
|
||||
|
||||
def slice_sql(self, expression: exp.Slice) -> str:
|
||||
return self.binary(expression, ":")
|
||||
|
||||
|
@ -3035,8 +3118,13 @@ class Generator(metaclass=_Generator):
|
|||
this = expression.this
|
||||
expr = expression.expression
|
||||
|
||||
if not self.dialect.LOG_BASE_FIRST:
|
||||
if self.dialect.LOG_BASE_FIRST is False:
|
||||
this, expr = expr, this
|
||||
elif self.dialect.LOG_BASE_FIRST is None and expr:
|
||||
if this.name in ("2", "10"):
|
||||
return self.func(f"LOG{this.name}", expr)
|
||||
|
||||
self.unsupported(f"Unsupported logarithm with base {self.sql(this)}")
|
||||
|
||||
return self.func("LOG", this, expr)
|
||||
|
||||
|
@ -3088,11 +3176,16 @@ class Generator(metaclass=_Generator):
|
|||
def text_width(self, args: t.Iterable) -> int:
|
||||
return sum(len(arg) for arg in args)
|
||||
|
||||
def format_time(self, expression: exp.Expression) -> t.Optional[str]:
|
||||
def format_time(
|
||||
self,
|
||||
expression: exp.Expression,
|
||||
inverse_time_mapping: t.Optional[t.Dict[str, str]] = None,
|
||||
inverse_time_trie: t.Optional[t.Dict] = None,
|
||||
) -> t.Optional[str]:
|
||||
return format_time(
|
||||
self.sql(expression, "format"),
|
||||
self.dialect.INVERSE_TIME_MAPPING,
|
||||
self.dialect.INVERSE_TIME_TRIE,
|
||||
inverse_time_mapping or self.dialect.INVERSE_TIME_MAPPING,
|
||||
inverse_time_trie or self.dialect.INVERSE_TIME_TRIE,
|
||||
)
|
||||
|
||||
def expressions(
|
||||
|
@ -3117,8 +3210,11 @@ class Generator(metaclass=_Generator):
|
|||
num_sqls = len(expressions)
|
||||
|
||||
# These are calculated once in case we have the leading_comma / pretty option set, correspondingly
|
||||
pad = " " * self.pad
|
||||
stripped_sep = sep.strip()
|
||||
if self.pretty:
|
||||
if self.leading_comma:
|
||||
pad = " " * len(sep)
|
||||
else:
|
||||
stripped_sep = sep.strip()
|
||||
|
||||
result_sqls = []
|
||||
for i, e in enumerate(expressions):
|
||||
|
@ -3154,13 +3250,6 @@ class Generator(metaclass=_Generator):
|
|||
self.unsupported(f"Unsupported property {expression.__class__.__name__}")
|
||||
return f"{property_name} {self.sql(expression, 'this')}"
|
||||
|
||||
def set_operation(self, expression: exp.Union, op: str) -> str:
|
||||
this = self.maybe_comment(self.sql(expression, "this"), comments=expression.comments)
|
||||
op = self.seg(op)
|
||||
return self.query_modifiers(
|
||||
expression, f"{this}{op}{self.sep()}{self.sql(expression, 'expression')}"
|
||||
)
|
||||
|
||||
def tag_sql(self, expression: exp.Tag) -> str:
|
||||
return f"{expression.args.get('prefix')}{self.sql(expression.this)}{expression.args.get('postfix')}"
|
||||
|
||||
|
@ -3227,6 +3316,18 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
return self.sql(exp.cast(expression.this, "text"))
|
||||
|
||||
def tonumber_sql(self, expression: exp.ToNumber) -> str:
|
||||
if not self.SUPPORTS_TO_NUMBER:
|
||||
self.unsupported("Unsupported TO_NUMBER function")
|
||||
return self.sql(exp.cast(expression.this, "double"))
|
||||
|
||||
fmt = expression.args.get("format")
|
||||
if not fmt:
|
||||
self.unsupported("Conversion format is required for TO_NUMBER")
|
||||
return self.sql(exp.cast(expression.this, "double"))
|
||||
|
||||
return self.func("TO_NUMBER", expression.this, fmt)
|
||||
|
||||
def dictproperty_sql(self, expression: exp.DictProperty) -> str:
|
||||
this = self.sql(expression, "this")
|
||||
kind = self.sql(expression, "kind")
|
||||
|
@ -3320,11 +3421,11 @@ class Generator(metaclass=_Generator):
|
|||
this = f" {this}" if this else ""
|
||||
index_type = self.sql(expression, "index_type")
|
||||
index_type = f" USING {index_type}" if index_type else ""
|
||||
schema = self.sql(expression, "schema")
|
||||
schema = f" {schema}" if schema else ""
|
||||
expressions = self.expressions(expression, flat=True)
|
||||
expressions = f" ({expressions})" if expressions else ""
|
||||
options = self.expressions(expression, key="options", sep=" ")
|
||||
options = f" {options}" if options else ""
|
||||
return f"{kind}{this}{index_type}{schema}{options}"
|
||||
return f"{kind}{this}{index_type}{expressions}{options}"
|
||||
|
||||
def nvl2_sql(self, expression: exp.Nvl2) -> str:
|
||||
if self.NVL2_SUPPORTED:
|
||||
|
@ -3396,6 +3497,13 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
return self.sql(exp.cast(this, "time"))
|
||||
|
||||
def tsordstotimestamp_sql(self, expression: exp.TsOrDsToTimestamp) -> str:
|
||||
this = expression.this
|
||||
if isinstance(this, exp.TsOrDsToTimestamp) or this.is_type(exp.DataType.Type.TIMESTAMP):
|
||||
return self.sql(this)
|
||||
|
||||
return self.sql(exp.cast(this, "timestamp"))
|
||||
|
||||
def tsordstodate_sql(self, expression: exp.TsOrDsToDate) -> str:
|
||||
this = expression.this
|
||||
time_format = self.format_time(expression)
|
||||
|
@ -3430,6 +3538,13 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
return self.func("LAST_DAY", expression.this)
|
||||
|
||||
def dateadd_sql(self, expression: exp.DateAdd) -> str:
|
||||
from sqlglot.dialects.dialect import unit_to_str
|
||||
|
||||
return self.func(
|
||||
"DATE_ADD", expression.this, expression.expression, unit_to_str(expression)
|
||||
)
|
||||
|
||||
def arrayany_sql(self, expression: exp.ArrayAny) -> str:
|
||||
if self.CAN_IMPLEMENT_ARRAY_ANY:
|
||||
filtered = exp.ArrayFilter(this=expression.this, expression=expression.expression)
|
||||
|
@ -3445,30 +3560,6 @@ class Generator(metaclass=_Generator):
|
|||
|
||||
return self.function_fallback_sql(expression)
|
||||
|
||||
def _jsonpathkey_sql(self, expression: exp.JSONPathKey) -> str:
|
||||
this = expression.this
|
||||
if isinstance(this, exp.JSONPathWildcard):
|
||||
this = self.json_path_part(this)
|
||||
return f".{this}" if this else ""
|
||||
|
||||
if exp.SAFE_IDENTIFIER_RE.match(this):
|
||||
return f".{this}"
|
||||
|
||||
this = self.json_path_part(this)
|
||||
return f"[{this}]" if self.JSON_PATH_BRACKETED_KEY_SUPPORTED else f".{this}"
|
||||
|
||||
def _jsonpathsubscript_sql(self, expression: exp.JSONPathSubscript) -> str:
|
||||
this = self.json_path_part(expression.this)
|
||||
return f"[{this}]" if this else ""
|
||||
|
||||
def _simplify_unless_literal(self, expression: E) -> E:
|
||||
if not isinstance(expression, exp.Literal):
|
||||
from sqlglot.optimizer.simplify import simplify
|
||||
|
||||
expression = simplify(expression, dialect=self.dialect)
|
||||
|
||||
return expression
|
||||
|
||||
def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
|
||||
expression.set("is_end_exclusive", None)
|
||||
return self.function_fallback_sql(expression)
|
||||
|
@ -3477,7 +3568,9 @@ class Generator(metaclass=_Generator):
|
|||
expression.set(
|
||||
"expressions",
|
||||
[
|
||||
exp.alias_(e.expression, e.this) if isinstance(e, exp.PropertyEQ) else e
|
||||
exp.alias_(e.expression, e.name if e.this.is_string else e.this)
|
||||
if isinstance(e, exp.PropertyEQ)
|
||||
else e
|
||||
for e in expression.expressions
|
||||
],
|
||||
)
|
||||
|
@ -3553,3 +3646,51 @@ class Generator(metaclass=_Generator):
|
|||
transformed = cast(this=value, to=to, safe=safe)
|
||||
|
||||
return self.sql(transformed)
|
||||
|
||||
def _jsonpathkey_sql(self, expression: exp.JSONPathKey) -> str:
|
||||
this = expression.this
|
||||
if isinstance(this, exp.JSONPathWildcard):
|
||||
this = self.json_path_part(this)
|
||||
return f".{this}" if this else ""
|
||||
|
||||
if exp.SAFE_IDENTIFIER_RE.match(this):
|
||||
return f".{this}"
|
||||
|
||||
this = self.json_path_part(this)
|
||||
return f"[{this}]" if self.JSON_PATH_BRACKETED_KEY_SUPPORTED else f".{this}"
|
||||
|
||||
def _jsonpathsubscript_sql(self, expression: exp.JSONPathSubscript) -> str:
|
||||
this = self.json_path_part(expression.this)
|
||||
return f"[{this}]" if this else ""
|
||||
|
||||
def _simplify_unless_literal(self, expression: E) -> E:
|
||||
if not isinstance(expression, exp.Literal):
|
||||
from sqlglot.optimizer.simplify import simplify
|
||||
|
||||
expression = simplify(expression, dialect=self.dialect)
|
||||
|
||||
return expression
|
||||
|
||||
def _embed_ignore_nulls(self, expression: exp.IgnoreNulls | exp.RespectNulls, text: str) -> str:
|
||||
if self.IGNORE_NULLS_IN_FUNC and not expression.meta.get("inline"):
|
||||
# The first modifier here will be the one closest to the AggFunc's arg
|
||||
mods = sorted(
|
||||
expression.find_all(exp.HavingMax, exp.Order, exp.Limit),
|
||||
key=lambda x: 0
|
||||
if isinstance(x, exp.HavingMax)
|
||||
else (1 if isinstance(x, exp.Order) else 2),
|
||||
)
|
||||
|
||||
if mods:
|
||||
mod = mods[0]
|
||||
this = expression.__class__(this=mod.this.copy())
|
||||
this.meta["inline"] = True
|
||||
mod.this.replace(this)
|
||||
return self.sql(expression.this)
|
||||
|
||||
agg_func = expression.find(exp.AggFunc)
|
||||
|
||||
if agg_func:
|
||||
return self.sql(agg_func)[:-1] + f" {text})"
|
||||
|
||||
return f"{self.sql(expression, 'this')} {text}"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue