sqlglotc 30.7.0__tar.gz → 30.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlglotc-30.7.0/sqlglotc.egg-info → sqlglotc-30.8.0}/PKG-INFO +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/array.py +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/core.py +2 -2
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/datatypes.py +1 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/ddl.py +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/functions.py +8 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/query.py +21 -6
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/string.py +1 -5
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generator.py +81 -4
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/bigquery.py +1 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/duckdb.py +12 -7
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/exasol.py +21 -18
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/hive.py +5 -4
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/mysql.py +1 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/postgres.py +3 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/redshift.py +30 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/singlestore.py +6 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/snowflake.py +1 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/spark.py +8 -2
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/tsql.py +1 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/annotate_types.py +111 -39
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/qualify.py +3 -2
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/qualify_columns.py +3 -3
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/scope.py +13 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parser.py +86 -10
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/bigquery.py +15 -14
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/clickhouse.py +12 -5
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/databricks.py +1 -3
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/dremio.py +2 -2
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/drill.py +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/duckdb.py +8 -3
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/exasol.py +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/hive.py +26 -17
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/mysql.py +13 -3
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/oracle.py +5 -4
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/postgres.py +7 -4
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/presto.py +8 -4
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/redshift.py +26 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/singlestore.py +3 -3
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/snowflake.py +7 -5
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/spark2.py +2 -2
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/schema.py +19 -13
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/serde.py +10 -6
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/time.py +6 -5
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/tokenizer_core.py +2 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0/sqlglotc.egg-info}/PKG-INFO +1 -1
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/MANIFEST.in +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/pyproject.toml +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/setup.cfg +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/setup.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/builders.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/constraints.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/clickhouse.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/databricks.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/doris.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/oracle.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/presto.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/python.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/spark2.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/sqlite.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/starrocks.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/generators/trino.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/lineage.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/resolver.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/optimizer/simplify.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/doris.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/prql.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/sqlite.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/starrocks.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/teradata.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/trino.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/parsers/tsql.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglotc.egg-info/requires.txt +0 -0
- {sqlglotc-30.7.0 → sqlglotc-30.8.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -365,5 +365,5 @@ class StDistance(Expression, Func):
|
|
|
365
365
|
|
|
366
366
|
|
|
367
367
|
class StPoint(Expression, Func):
|
|
368
|
-
arg_types = {"this": True, "expression": True, "
|
|
368
|
+
arg_types = {"this": True, "expression": True, "z": False, "m": False}
|
|
369
369
|
_sql_names = ["ST_POINT", "ST_MAKEPOINT"]
|
|
@@ -2135,7 +2135,7 @@ class GTE(Expression, Binary, Predicate):
|
|
|
2135
2135
|
|
|
2136
2136
|
|
|
2137
2137
|
class ILike(Expression, Binary, Predicate):
|
|
2138
|
-
|
|
2138
|
+
arg_types = {"this": True, "expression": True, "negate": False}
|
|
2139
2139
|
|
|
2140
2140
|
|
|
2141
2141
|
class IntDiv(Expression, Binary):
|
|
@@ -2147,7 +2147,7 @@ class Is(Expression, Binary, Predicate):
|
|
|
2147
2147
|
|
|
2148
2148
|
|
|
2149
2149
|
class Like(Expression, Binary, Predicate):
|
|
2150
|
-
|
|
2150
|
+
arg_types = {"this": True, "expression": True, "negate": False}
|
|
2151
2151
|
|
|
2152
2152
|
|
|
2153
2153
|
class Match(Expression, Binary, Predicate):
|
|
@@ -148,6 +148,10 @@ class Nullif(Expression, Func):
|
|
|
148
148
|
arg_types = {"this": True, "expression": True}
|
|
149
149
|
|
|
150
150
|
|
|
151
|
+
class ObjectTransform(Expression, Func):
|
|
152
|
+
arg_types = {"this": True, "keep": False, "set_": False}
|
|
153
|
+
|
|
154
|
+
|
|
151
155
|
class Nvl2(Expression, Func):
|
|
152
156
|
arg_types = {"this": True, "true": True, "false": False}
|
|
153
157
|
|
|
@@ -301,6 +305,10 @@ class CurrentUser(Expression, Func):
|
|
|
301
305
|
arg_types = {"this": False}
|
|
302
306
|
|
|
303
307
|
|
|
308
|
+
class CurrentUserId(Expression, Func):
|
|
309
|
+
arg_types = {}
|
|
310
|
+
|
|
311
|
+
|
|
304
312
|
class CurrentVersion(Expression, Func):
|
|
305
313
|
arg_types = {}
|
|
306
314
|
|
|
@@ -1763,14 +1763,15 @@ class Pivot(Expression):
|
|
|
1763
1763
|
def fields(self) -> list[Expr]:
|
|
1764
1764
|
return self.args.get("fields", [])
|
|
1765
1765
|
|
|
1766
|
-
def output_columns(self, pre_pivot_columns: t.Iterable[str]) ->
|
|
1766
|
+
def output_columns(self, pre_pivot_columns: t.Iterable[str]) -> dict[str, str]:
|
|
1767
1767
|
"""
|
|
1768
|
-
Returns
|
|
1768
|
+
Returns an ordered map of post-rename output column name -> pre-rename
|
|
1769
|
+
source-side name, in the order the (UN)PIVOT produces them.
|
|
1769
1770
|
|
|
1770
|
-
|
|
1771
|
+
For callers that just want the names, iterate the dict (or call .keys()):
|
|
1771
1772
|
>>> from sqlglot import parse_one, exp
|
|
1772
1773
|
>>> piv = parse_one("SELECT * FROM t UNPIVOT(val FOR name IN (a, b))").find(exp.Pivot)
|
|
1773
|
-
>>> piv.output_columns(["a", "b", "c"])
|
|
1774
|
+
>>> list(piv.output_columns(["a", "b", "c"]))
|
|
1774
1775
|
['c', 'name', 'val']
|
|
1775
1776
|
|
|
1776
1777
|
AST shape:
|
|
@@ -1813,9 +1814,23 @@ class Pivot(Expression):
|
|
|
1813
1814
|
outputs = [c.alias_or_name for c in self.expressions]
|
|
1814
1815
|
|
|
1815
1816
|
if not excluded or not outputs:
|
|
1816
|
-
return
|
|
1817
|
+
return {}
|
|
1818
|
+
|
|
1819
|
+
pre_rename = [c for c in pre_pivot_columns if c not in excluded] + outputs
|
|
1820
|
+
|
|
1821
|
+
alias = self.args.get("alias")
|
|
1822
|
+
renames = alias.args.get("columns") if alias else None
|
|
1823
|
+
|
|
1824
|
+
# `PIVOT(...) AS alias(c1, c2, ...)` renames the operator's output columns
|
|
1825
|
+
# positionally from the front (DuckDB, Snowflake): the user's names cover
|
|
1826
|
+
# the leading N output columns, remaining columns keep their auto names.
|
|
1827
|
+
if renames:
|
|
1828
|
+
rename_names = [r.name for r in renames]
|
|
1829
|
+
post_rename = rename_names + pre_rename[len(rename_names) :]
|
|
1830
|
+
else:
|
|
1831
|
+
post_rename = pre_rename
|
|
1817
1832
|
|
|
1818
|
-
return
|
|
1833
|
+
return dict(zip(post_rename, pre_rename))
|
|
1819
1834
|
|
|
1820
1835
|
|
|
1821
1836
|
class UnpivotColumns(Expression):
|
|
@@ -303,17 +303,13 @@ class FromBase64(Expression, Func):
|
|
|
303
303
|
|
|
304
304
|
|
|
305
305
|
class Hex(Expression, Func):
|
|
306
|
-
|
|
306
|
+
arg_types = {"this": True, "case": False}
|
|
307
307
|
|
|
308
308
|
|
|
309
309
|
class HexDecodeString(Expression, Func):
|
|
310
310
|
pass
|
|
311
311
|
|
|
312
312
|
|
|
313
|
-
class HexEncode(Expression, Func):
|
|
314
|
-
arg_types = {"this": True, "case": False}
|
|
315
|
-
|
|
316
|
-
|
|
317
313
|
class LowerHex(Hex):
|
|
318
314
|
pass
|
|
319
315
|
|
|
@@ -446,6 +446,9 @@ class Generator:
|
|
|
446
446
|
# Whether named columns are allowed in table aliases
|
|
447
447
|
SUPPORTS_TABLE_ALIAS_COLUMNS = True
|
|
448
448
|
|
|
449
|
+
# Whether named columns are allowed in CTE definitions
|
|
450
|
+
SUPPORTS_NAMED_CTE_COLUMNS = True
|
|
451
|
+
|
|
449
452
|
# Whether UNPIVOT aliases are Identifiers (False means they're Literals)
|
|
450
453
|
UNPIVOT_ALIASES_ARE_IDENTIFIERS = True
|
|
451
454
|
|
|
@@ -467,6 +470,9 @@ class Generator:
|
|
|
467
470
|
# Whether ALTER TABLE ... MODIFY COLUMN column-redefinition syntax is supported
|
|
468
471
|
SUPPORTS_MODIFY_COLUMN = False
|
|
469
472
|
|
|
473
|
+
# Whether ALTER TABLE ... CHANGE COLUMN column-rename-and-redefine syntax is supported
|
|
474
|
+
SUPPORTS_CHANGE_COLUMN = False
|
|
475
|
+
|
|
470
476
|
# Whether the LikeProperty needs to be specified inside of the schema clause
|
|
471
477
|
LIKE_PROPERTY_INSIDE_SCHEMA = False
|
|
472
478
|
|
|
@@ -620,6 +626,11 @@ class Generator:
|
|
|
620
626
|
|
|
621
627
|
UNSUPPORTED_TYPES: t.ClassVar[set[exp.DType]] = set()
|
|
622
628
|
|
|
629
|
+
# mapping of DType to its default parameters, bounds
|
|
630
|
+
TYPE_PARAM_SETTINGS: t.ClassVar[
|
|
631
|
+
dict[exp.DType, tuple[tuple[int, ...], tuple[int | None, ...]]]
|
|
632
|
+
] = {}
|
|
633
|
+
|
|
623
634
|
TIME_PART_SINGULARS: t.ClassVar = {
|
|
624
635
|
"MICROSECONDS": "MICROSECOND",
|
|
625
636
|
"SECONDS": "SECOND",
|
|
@@ -1526,7 +1537,11 @@ class Generator:
|
|
|
1526
1537
|
columns = self.expressions(expression, key="columns", flat=True)
|
|
1527
1538
|
columns = f"({columns})" if columns else ""
|
|
1528
1539
|
|
|
1529
|
-
if
|
|
1540
|
+
if (
|
|
1541
|
+
columns
|
|
1542
|
+
and not self.SUPPORTS_TABLE_ALIAS_COLUMNS
|
|
1543
|
+
and not (self.SUPPORTS_NAMED_CTE_COLUMNS and isinstance(expression.parent, exp.CTE))
|
|
1544
|
+
):
|
|
1530
1545
|
columns = ""
|
|
1531
1546
|
self.unsupported("Named columns are not supported in table alias.")
|
|
1532
1547
|
|
|
@@ -1629,11 +1644,59 @@ class Generator:
|
|
|
1629
1644
|
specifier = f" {specifier}" if specifier and self.DATA_TYPE_SPECIFIERS_ALLOWED else ""
|
|
1630
1645
|
return f"{this}{specifier}"
|
|
1631
1646
|
|
|
1647
|
+
def datatype_param_bound_limiter(
|
|
1648
|
+
self,
|
|
1649
|
+
expression: exp.DataType,
|
|
1650
|
+
type_value: exp.DType,
|
|
1651
|
+
defaults: tuple[int, ...],
|
|
1652
|
+
bounds: tuple[int | None, ...],
|
|
1653
|
+
) -> exp.DataType:
|
|
1654
|
+
params = expression.expressions
|
|
1655
|
+
|
|
1656
|
+
if not params:
|
|
1657
|
+
if defaults:
|
|
1658
|
+
expression.set(
|
|
1659
|
+
"expressions",
|
|
1660
|
+
[exp.DataTypeParam(this=exp.Literal.number(d)) for d in defaults],
|
|
1661
|
+
)
|
|
1662
|
+
return expression
|
|
1663
|
+
|
|
1664
|
+
if not bounds:
|
|
1665
|
+
return expression
|
|
1666
|
+
|
|
1667
|
+
for i, param in enumerate(params):
|
|
1668
|
+
bound = bounds[i] if i < len(bounds) else None
|
|
1669
|
+
if bound is None:
|
|
1670
|
+
continue
|
|
1671
|
+
|
|
1672
|
+
param_value = param.this if isinstance(param, exp.DataTypeParam) else param
|
|
1673
|
+
if (
|
|
1674
|
+
isinstance(param_value, exp.Literal)
|
|
1675
|
+
and param_value.is_number
|
|
1676
|
+
and int(param_value.to_py()) > bound
|
|
1677
|
+
):
|
|
1678
|
+
self.unsupported(
|
|
1679
|
+
f"{type_value.value} parameter {param_value.name} exceeds "
|
|
1680
|
+
f"{self.dialect.__class__.__name__}'s maximum of {bound}; capping"
|
|
1681
|
+
)
|
|
1682
|
+
params[i] = exp.DataTypeParam(this=exp.Literal.number(bound))
|
|
1683
|
+
|
|
1684
|
+
return expression
|
|
1685
|
+
|
|
1632
1686
|
def datatype_sql(self, expression: exp.DataType) -> str:
|
|
1633
1687
|
nested = ""
|
|
1634
1688
|
values = ""
|
|
1635
1689
|
|
|
1636
1690
|
expr_nested = expression.args.get("nested")
|
|
1691
|
+
type_value = expression.this
|
|
1692
|
+
|
|
1693
|
+
if (
|
|
1694
|
+
not expr_nested
|
|
1695
|
+
and isinstance(type_value, exp.DType)
|
|
1696
|
+
and (settings := self.TYPE_PARAM_SETTINGS.get(type_value))
|
|
1697
|
+
):
|
|
1698
|
+
expression = self.datatype_param_bound_limiter(expression, type_value, *settings)
|
|
1699
|
+
|
|
1637
1700
|
interior = (
|
|
1638
1701
|
self.expressions(
|
|
1639
1702
|
expression, dynamic=True, new_line=True, skip_first=True, skip_last=True
|
|
@@ -1642,7 +1705,6 @@ class Generator:
|
|
|
1642
1705
|
else self.expressions(expression, flat=True)
|
|
1643
1706
|
)
|
|
1644
1707
|
|
|
1645
|
-
type_value = expression.this
|
|
1646
1708
|
if type_value in self.UNSUPPORTED_TYPES:
|
|
1647
1709
|
self.unsupported(
|
|
1648
1710
|
f"Data type {type_value.value} is not supported when targeting {self.dialect.__class__.__name__}"
|
|
@@ -1679,6 +1741,10 @@ class Generator:
|
|
|
1679
1741
|
):
|
|
1680
1742
|
type_sql = f"{type_sql} WITH TIME ZONE"
|
|
1681
1743
|
|
|
1744
|
+
collate = self.sql(expression, "collate")
|
|
1745
|
+
if collate:
|
|
1746
|
+
type_sql = f"{type_sql} COLLATE {collate}"
|
|
1747
|
+
|
|
1682
1748
|
return type_sql
|
|
1683
1749
|
|
|
1684
1750
|
def directory_sql(self, expression: exp.Directory) -> str:
|
|
@@ -3944,9 +4010,15 @@ class Generator:
|
|
|
3944
4010
|
return f"ALTER COLUMN {this} DROP DEFAULT"
|
|
3945
4011
|
|
|
3946
4012
|
def modifycolumn_sql(self, expression: exp.ModifyColumn) -> str:
|
|
4013
|
+
this = self.sql(expression, "this")
|
|
4014
|
+
rename_from = self.sql(expression, "rename_from")
|
|
4015
|
+
if rename_from:
|
|
4016
|
+
if not self.SUPPORTS_CHANGE_COLUMN:
|
|
4017
|
+
self.unsupported("CHANGE COLUMN is not supported in this dialect")
|
|
4018
|
+
return f"CHANGE COLUMN {rename_from} {this}"
|
|
3947
4019
|
if not self.SUPPORTS_MODIFY_COLUMN:
|
|
3948
4020
|
self.unsupported("MODIFY COLUMN is not supported in this dialect")
|
|
3949
|
-
return f"MODIFY COLUMN {
|
|
4021
|
+
return f"MODIFY COLUMN {this}"
|
|
3950
4022
|
|
|
3951
4023
|
def alterindex_sql(self, expression: exp.AlterIndex) -> str:
|
|
3952
4024
|
this = self.sql(expression, "this")
|
|
@@ -4193,6 +4265,9 @@ class Generator:
|
|
|
4193
4265
|
exp_class = exp.ILike
|
|
4194
4266
|
op = "ILIKE"
|
|
4195
4267
|
|
|
4268
|
+
if expression.args.get("negate"):
|
|
4269
|
+
op = f"NOT {op}"
|
|
4270
|
+
|
|
4196
4271
|
if isinstance(rhs, (exp.All, exp.Any)) and not self.SUPPORTS_LIKE_QUANTIFIERS:
|
|
4197
4272
|
exprs = rhs.this.unnest()
|
|
4198
4273
|
|
|
@@ -4204,7 +4279,9 @@ class Generator:
|
|
|
4204
4279
|
connective = exp.or_ if isinstance(rhs, exp.Any) else exp.and_
|
|
4205
4280
|
|
|
4206
4281
|
def _make_like(expr: exp.Expression) -> exp.Expression:
|
|
4207
|
-
like: exp.Expression = exp_class(
|
|
4282
|
+
like: exp.Expression = exp_class(
|
|
4283
|
+
this=this, expression=expr, negate=expression.args.get("negate")
|
|
4284
|
+
)
|
|
4208
4285
|
if escape:
|
|
4209
4286
|
like = exp.Escape(this=like, expression=escape.expression.copy())
|
|
4210
4287
|
return like
|
|
@@ -232,6 +232,7 @@ class BigQueryGenerator(generator.Generator):
|
|
|
232
232
|
COLLATE_IS_FUNC = True
|
|
233
233
|
LIMIT_ONLY_LITERALS = True
|
|
234
234
|
SUPPORTS_TABLE_ALIAS_COLUMNS = False
|
|
235
|
+
SUPPORTS_NAMED_CTE_COLUMNS = False
|
|
235
236
|
UNPIVOT_ALIASES_ARE_IDENTIFIERS = False
|
|
236
237
|
JSON_KEY_VALUE_PAIR_SEP = ","
|
|
237
238
|
NULL_ORDERING_SUPPORTED: bool | None = False
|
|
@@ -1581,6 +1581,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1581
1581
|
f"CAST(STRFTIME({self.sql(e, 'this')}, {self.dialect.DATEINT_FORMAT}) AS INT)"
|
|
1582
1582
|
),
|
|
1583
1583
|
exp.Decode: lambda self, e: encode_decode_sql(self, e, "DECODE", replace=False),
|
|
1584
|
+
exp.HexDecodeString: lambda self, e: self.sql(exp.Decode(this=exp.Unhex(this=e.this))),
|
|
1584
1585
|
exp.DiToDate: lambda self, e: (
|
|
1585
1586
|
f"CAST(STRPTIME(CAST({self.sql(e, 'this')} AS TEXT), {self.dialect.DATEINT_FORMAT}) AS DATE)"
|
|
1586
1587
|
),
|
|
@@ -1727,7 +1728,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1727
1728
|
exp.DType.BPCHAR: "TEXT",
|
|
1728
1729
|
exp.DType.CHAR: "TEXT",
|
|
1729
1730
|
exp.DType.DATETIME: "TIMESTAMP",
|
|
1730
|
-
exp.DType.DECFLOAT: "DECIMAL
|
|
1731
|
+
exp.DType.DECFLOAT: "DECIMAL",
|
|
1731
1732
|
exp.DType.FLOAT: "REAL",
|
|
1732
1733
|
exp.DType.JSONB: "JSON",
|
|
1733
1734
|
exp.DType.NCHAR: "TEXT",
|
|
@@ -1741,7 +1742,13 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1741
1742
|
exp.DType.TIMESTAMP_S: "TIMESTAMP_S",
|
|
1742
1743
|
exp.DType.TIMESTAMP_MS: "TIMESTAMP_MS",
|
|
1743
1744
|
exp.DType.TIMESTAMP_NS: "TIMESTAMP_NS",
|
|
1744
|
-
exp.DType.BIGDECIMAL: "DECIMAL
|
|
1745
|
+
exp.DType.BIGDECIMAL: "DECIMAL",
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
TYPE_PARAM_SETTINGS = {
|
|
1749
|
+
**generator.Generator.TYPE_PARAM_SETTINGS,
|
|
1750
|
+
exp.DType.BIGDECIMAL: ((38, 5), (38, 38)),
|
|
1751
|
+
exp.DType.DECFLOAT: ((38, 5), (38, 38)),
|
|
1745
1752
|
}
|
|
1746
1753
|
|
|
1747
1754
|
# https://github.com/duckdb/duckdb/blob/ff7f24fd8e3128d94371827523dae85ebaf58713/third_party/libpg_query/grammar/keywords/reserved_keywords.list#L1-L77
|
|
@@ -3607,15 +3614,13 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3607
3614
|
|
|
3608
3615
|
return self.sql(result)
|
|
3609
3616
|
|
|
3610
|
-
def
|
|
3611
|
-
arg = expression.this
|
|
3617
|
+
def hex_sql(self, expression: exp.Hex) -> str:
|
|
3612
3618
|
case = expression.args.get("case")
|
|
3613
|
-
hex_expr = exp.Hex(this=arg)
|
|
3614
3619
|
|
|
3615
3620
|
if not case:
|
|
3616
|
-
return self.
|
|
3621
|
+
return self.func("HEX", expression.this)
|
|
3617
3622
|
|
|
3618
|
-
|
|
3623
|
+
hex_expr = exp.Hex(this=expression.this)
|
|
3619
3624
|
return self.sql(
|
|
3620
3625
|
exp.case()
|
|
3621
3626
|
.when(case.is_(exp.null()), exp.null())
|
|
@@ -2,9 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
|
-
from sqlglot import exp, generator
|
|
5
|
+
from sqlglot import exp, generator
|
|
6
6
|
from sqlglot.dialects.dialect import (
|
|
7
7
|
DATE_ADD_OR_SUB,
|
|
8
|
+
Dialect,
|
|
8
9
|
groupconcat_sql,
|
|
9
10
|
no_last_day_sql,
|
|
10
11
|
rename_func,
|
|
@@ -35,10 +36,13 @@ def _date_diff_sql(self: ExasolGenerator, expression: exp.DateDiff | exp.TsOrDsD
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
# https://docs.exasol.com/db/latest/sql/select.htm#:~:text=If%20you%20have,local.x%3E10
|
|
38
|
-
def _add_local_prefix_for_aliases(expression: exp.Expr) -> exp.Expr:
|
|
39
|
+
def _add_local_prefix_for_aliases(expression: exp.Expr, dialect: Dialect) -> exp.Expr:
|
|
40
|
+
def _key(ident: exp.Identifier) -> str:
|
|
41
|
+
return dialect.normalize_identifier(ident.copy()).this
|
|
42
|
+
|
|
39
43
|
if isinstance(expression, exp.Select):
|
|
40
|
-
aliases: dict[str,
|
|
41
|
-
alias
|
|
44
|
+
aliases: dict[str, exp.Identifier] = {
|
|
45
|
+
_key(alias): alias
|
|
42
46
|
for sel in expression.selects
|
|
43
47
|
if isinstance(sel, exp.Alias) and (alias := sel.args.get("alias"))
|
|
44
48
|
}
|
|
@@ -53,11 +57,12 @@ def _add_local_prefix_for_aliases(expression: exp.Expr) -> exp.Expr:
|
|
|
53
57
|
):
|
|
54
58
|
table_ident.replace(exp.to_identifier(table_ident.name.upper(), quoted=True))
|
|
55
59
|
|
|
56
|
-
def prefix_local(node: exp.Expr, visible_aliases: dict[str,
|
|
60
|
+
def prefix_local(node: exp.Expr, visible_aliases: dict[str, exp.Identifier]) -> exp.Expr:
|
|
57
61
|
if isinstance(node, exp.Column) and not node.table:
|
|
58
|
-
|
|
62
|
+
alias = visible_aliases.get(_key(node.this))
|
|
63
|
+
if alias is not None:
|
|
59
64
|
return exp.Column(
|
|
60
|
-
this=
|
|
65
|
+
this=alias,
|
|
61
66
|
table=exp.to_identifier("LOCAL", quoted=False),
|
|
62
67
|
)
|
|
63
68
|
return node
|
|
@@ -66,16 +71,15 @@ def _add_local_prefix_for_aliases(expression: exp.Expr) -> exp.Expr:
|
|
|
66
71
|
if arg := expression.args.get(key):
|
|
67
72
|
expression.set(key, arg.transform(lambda node: prefix_local(node, aliases)))
|
|
68
73
|
|
|
69
|
-
seen_aliases: dict[str,
|
|
74
|
+
seen_aliases: dict[str, exp.Identifier] = {}
|
|
70
75
|
new_selects: list[exp.Expr] = []
|
|
71
76
|
for sel in expression.selects:
|
|
72
77
|
if isinstance(sel, exp.Alias):
|
|
73
78
|
inner = sel.this.transform(lambda node: prefix_local(node, seen_aliases))
|
|
74
79
|
sel.set("this", inner)
|
|
75
80
|
|
|
76
|
-
alias_node
|
|
77
|
-
|
|
78
|
-
seen_aliases[sel.alias] = bool(alias_node and getattr(alias_node, "quoted", False))
|
|
81
|
+
if alias_node := sel.args.get("alias"):
|
|
82
|
+
seen_aliases[_key(alias_node)] = alias_node
|
|
79
83
|
new_selects.append(sel)
|
|
80
84
|
else:
|
|
81
85
|
new_selects.append(sel.transform(lambda node: prefix_local(node, seen_aliases)))
|
|
@@ -303,6 +307,12 @@ class ExasolGenerator(generator.Generator):
|
|
|
303
307
|
exp.DType.TIMESTAMPNTZ: "TIMESTAMP",
|
|
304
308
|
}
|
|
305
309
|
|
|
310
|
+
def select_sql(self, expression: exp.Select) -> str:
|
|
311
|
+
processed = _qualify_unscoped_star(expression)
|
|
312
|
+
processed = _add_local_prefix_for_aliases(processed, self.dialect)
|
|
313
|
+
processed = _group_by_all(processed)
|
|
314
|
+
return super().select_sql(t.cast(exp.Select, processed))
|
|
315
|
+
|
|
306
316
|
def datatype_sql(self, expression: exp.DataType) -> str:
|
|
307
317
|
# Exasol supports a fixed default precision of 3 for TIMESTAMP WITH LOCAL TIME ZONE
|
|
308
318
|
# and does not allow specifying a different custom precision
|
|
@@ -390,13 +400,6 @@ class ExasolGenerator(generator.Generator):
|
|
|
390
400
|
exp.MD5Digest: rename_func("HASHTYPE_MD5"),
|
|
391
401
|
# https://docs.exasol.com/db/latest/sql/create_view.htm
|
|
392
402
|
exp.CommentColumnConstraint: lambda self, e: f"COMMENT IS {self.sql(e, 'this')}",
|
|
393
|
-
exp.Select: transforms.preprocess(
|
|
394
|
-
[
|
|
395
|
-
_qualify_unscoped_star,
|
|
396
|
-
_add_local_prefix_for_aliases,
|
|
397
|
-
_group_by_all,
|
|
398
|
-
]
|
|
399
|
-
),
|
|
400
403
|
exp.SubstringIndex: _substring_index_sql,
|
|
401
404
|
exp.WeekOfYear: rename_func("WEEK"),
|
|
402
405
|
# https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/to_date.htm
|
|
@@ -433,17 +433,18 @@ class HiveGenerator(generator.Generator):
|
|
|
433
433
|
if expression.this in self.PARAMETERIZABLE_TEXT_TYPES and (
|
|
434
434
|
not expression.expressions or expression.expressions[0].name == "MAX"
|
|
435
435
|
):
|
|
436
|
-
expression
|
|
436
|
+
expression.set("this", exp.DType.TEXT)
|
|
437
|
+
expression.set("expressions", None)
|
|
437
438
|
elif expression.is_type(exp.DType.TEXT) and expression.expressions:
|
|
438
439
|
expression.set("this", exp.DType.VARCHAR)
|
|
439
440
|
elif expression.this in exp.DataType.TEMPORAL_TYPES:
|
|
440
|
-
expression
|
|
441
|
+
expression.set("expressions", None)
|
|
441
442
|
elif expression.is_type("float"):
|
|
442
443
|
size_expression = expression.find(exp.DataTypeParam)
|
|
443
444
|
if size_expression:
|
|
444
445
|
size = int(size_expression.name)
|
|
445
|
-
|
|
446
|
-
expression
|
|
446
|
+
expression.set("this", exp.DType.FLOAT if size <= 32 else exp.DType.DOUBLE)
|
|
447
|
+
expression.set("expressions", None)
|
|
447
448
|
return super().datatype_sql(expression)
|
|
448
449
|
|
|
449
450
|
def version_sql(self, expression: exp.Version) -> str:
|
|
@@ -112,6 +112,7 @@ class MySQLGenerator(generator.Generator):
|
|
|
112
112
|
SUPPORTS_UESCAPE = False
|
|
113
113
|
SUPPORTS_DECODE_CASE = False
|
|
114
114
|
SUPPORTS_MODIFY_COLUMN = True
|
|
115
|
+
SUPPORTS_CHANGE_COLUMN = True
|
|
115
116
|
|
|
116
117
|
AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS
|
|
117
118
|
|
|
@@ -481,6 +481,9 @@ class PostgresGenerator(generator.Generator):
|
|
|
481
481
|
return f"{self.expressions(expression, flat=True)}[{values}]"
|
|
482
482
|
return "ARRAY"
|
|
483
483
|
|
|
484
|
+
if expression.is_type(exp.DType.ENUM):
|
|
485
|
+
return f"ENUM ({self.expressions(expression, flat=True)})"
|
|
486
|
+
|
|
484
487
|
if expression.is_type(exp.DType.DOUBLE, exp.DType.FLOAT) and expression.expressions:
|
|
485
488
|
# Postgres doesn't support precision for REAL and DOUBLE PRECISION types
|
|
486
489
|
return f"FLOAT({self.expressions(expression, flat=True)})"
|
|
@@ -67,6 +67,7 @@ class RedshiftGenerator(PostgresGenerator):
|
|
|
67
67
|
exp.SHA2,
|
|
68
68
|
exp.Getbit,
|
|
69
69
|
exp.Round,
|
|
70
|
+
exp.TryCast,
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
exp.ArrayConcat: array_concat_sql("ARRAY_CONCAT"),
|
|
@@ -74,6 +75,7 @@ class RedshiftGenerator(PostgresGenerator):
|
|
|
74
75
|
exp.ConcatWs: concat_ws_to_dpipe_sql,
|
|
75
76
|
exp.ApproxDistinct: lambda self, e: f"APPROXIMATE COUNT(DISTINCT {self.sql(e, 'this')})",
|
|
76
77
|
exp.CurrentTimestamp: lambda self, e: "SYSDATE" if e.args.get("sysdate") else "GETDATE()",
|
|
78
|
+
exp.CurrentUserId: lambda *_: "CURRENT_USER_ID",
|
|
77
79
|
exp.DateAdd: date_delta_sql("DATEADD"),
|
|
78
80
|
exp.DateDiff: date_delta_sql("DATEDIFF"),
|
|
79
81
|
exp.DistKeyProperty: lambda self, e: self.func("DISTKEY", e.this),
|
|
@@ -270,6 +272,34 @@ class RedshiftGenerator(PostgresGenerator):
|
|
|
270
272
|
"without",
|
|
271
273
|
}
|
|
272
274
|
|
|
275
|
+
def stpoint_sql(self, expression: exp.StPoint) -> str:
|
|
276
|
+
# ST_POINT only accepts 2 args in Redshift; use ST_MAKEPOINT for 3 or 4 args
|
|
277
|
+
if expression.args.get("z") or expression.args.get("m"):
|
|
278
|
+
return self.func(
|
|
279
|
+
"ST_MAKEPOINT",
|
|
280
|
+
expression.this,
|
|
281
|
+
expression.expression,
|
|
282
|
+
expression.args.get("z"),
|
|
283
|
+
expression.args.get("m"),
|
|
284
|
+
)
|
|
285
|
+
return self.func("ST_POINT", expression.this, expression.expression)
|
|
286
|
+
|
|
287
|
+
def arraycontains_sql(self, expression: exp.ArrayContains) -> str:
|
|
288
|
+
return self.func(
|
|
289
|
+
"ARRAY_CONTAINS",
|
|
290
|
+
expression.this,
|
|
291
|
+
expression.expression,
|
|
292
|
+
expression.args.get("check_null"),
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
def objecttransform_sql(self, expression: exp.ObjectTransform) -> str:
|
|
296
|
+
this = self.sql(expression, "this")
|
|
297
|
+
keep = self.expressions(expression, key="keep", flat=True)
|
|
298
|
+
set_ = self.expressions(expression, key="set_", flat=True)
|
|
299
|
+
keep_sql = " KEEP " + keep if keep else ""
|
|
300
|
+
set_sql = " SET " + set_ if set_ else ""
|
|
301
|
+
return f"OBJECT_TRANSFORM({this}{keep_sql}{set_sql})"
|
|
302
|
+
|
|
273
303
|
def approxquantile_sql(self, expression: exp.ApproxQuantile) -> str:
|
|
274
304
|
return "APPROXIMATE " + self.sql(
|
|
275
305
|
exp.WithinGroup(
|
|
@@ -361,7 +361,12 @@ class SingleStoreGenerator(MySQLGenerator):
|
|
|
361
361
|
exp.DType.JSONB: "BSON",
|
|
362
362
|
exp.DType.TIMESTAMP: "TIMESTAMP",
|
|
363
363
|
exp.DType.TIMESTAMP_S: "TIMESTAMP",
|
|
364
|
-
exp.DType.TIMESTAMP_MS: "TIMESTAMP
|
|
364
|
+
exp.DType.TIMESTAMP_MS: "TIMESTAMP",
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
TYPE_PARAM_SETTINGS = {
|
|
368
|
+
**MySQLGenerator.TYPE_PARAM_SETTINGS,
|
|
369
|
+
exp.DType.TIMESTAMP_MS: ((6,), ()),
|
|
365
370
|
}
|
|
366
371
|
|
|
367
372
|
# https://docs.singlestore.com/cloud/reference/sql-reference/restricted-keywords/list-of-restricted-keywords/
|
|
@@ -559,6 +559,7 @@ class SnowflakeGenerator(generator.Generator):
|
|
|
559
559
|
exp.MD5Digest: rename_func("MD5_BINARY"),
|
|
560
560
|
exp.MD5NumberLower64: rename_func("MD5_NUMBER_LOWER64"),
|
|
561
561
|
exp.MD5NumberUpper64: rename_func("MD5_NUMBER_UPPER64"),
|
|
562
|
+
exp.Hex: rename_func("HEX_ENCODE"),
|
|
562
563
|
exp.LowerHex: rename_func("TO_CHAR"),
|
|
563
564
|
exp.Skewness: rename_func("SKEW"),
|
|
564
565
|
exp.StarMap: rename_func("OBJECT_CONSTRUCT"),
|
|
@@ -76,13 +76,19 @@ class SparkGenerator(Spark2Generator):
|
|
|
76
76
|
|
|
77
77
|
TYPE_MAPPING = {
|
|
78
78
|
**Spark2Generator.TYPE_MAPPING,
|
|
79
|
-
exp.DType.MONEY: "DECIMAL
|
|
80
|
-
exp.DType.SMALLMONEY: "DECIMAL
|
|
79
|
+
exp.DType.MONEY: "DECIMAL",
|
|
80
|
+
exp.DType.SMALLMONEY: "DECIMAL",
|
|
81
81
|
exp.DType.UUID: "STRING",
|
|
82
82
|
exp.DType.TIMESTAMPLTZ: "TIMESTAMP_LTZ",
|
|
83
83
|
exp.DType.TIMESTAMPNTZ: "TIMESTAMP_NTZ",
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
TYPE_PARAM_SETTINGS = {
|
|
87
|
+
**Spark2Generator.TYPE_PARAM_SETTINGS,
|
|
88
|
+
exp.DType.MONEY: ((15, 4), ()),
|
|
89
|
+
exp.DType.SMALLMONEY: ((6, 4), ()),
|
|
90
|
+
}
|
|
91
|
+
|
|
86
92
|
TRANSFORMS = {
|
|
87
93
|
k: v
|
|
88
94
|
for k, v in {
|
|
@@ -234,6 +234,7 @@ class TSQLGenerator(generator.Generator):
|
|
|
234
234
|
exp.TemporaryProperty: lambda self, e: "",
|
|
235
235
|
exp.TimeStrToTime: _timestrtotime_sql,
|
|
236
236
|
exp.TimeToStr: _format_sql,
|
|
237
|
+
exp.TimestampAdd: date_delta_sql("DATEADD"),
|
|
237
238
|
exp.Trim: trim_sql,
|
|
238
239
|
exp.TsOrDsAdd: date_delta_sql("DATEADD", cast=True),
|
|
239
240
|
exp.TsOrDsDiff: date_delta_sql("DATEDIFF"),
|