sqlglotc 30.8.0__tar.gz → 30.9.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.8.0/sqlglotc.egg-info → sqlglotc-30.9.0}/PKG-INFO +2 -2
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/pyproject.toml +2 -2
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/aggregate.py +1 -1
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/core.py +33 -12
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/datatypes.py +17 -5
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/ddl.py +8 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/dml.py +1 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/functions.py +5 -1
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/query.py +8 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/string.py +1 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generator.py +158 -13
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/clickhouse.py +1 -1
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/duckdb.py +34 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/exasol.py +6 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/mysql.py +37 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/oracle.py +10 -2
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/sqlite.py +39 -10
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/tsql.py +18 -7
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/annotate_types.py +10 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/simplify.py +31 -3
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parser.py +121 -14
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/bigquery.py +22 -2
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/clickhouse.py +8 -3
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/duckdb.py +1 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/oracle.py +21 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/snowflake.py +14 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/spark2.py +1 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/tsql.py +72 -10
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/serde.py +1 -1
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/tokenizer_core.py +1 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0/sqlglotc.egg-info}/PKG-INFO +2 -2
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglotc.egg-info/requires.txt +1 -1
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/MANIFEST.in +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/setup.cfg +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/setup.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/array.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/builders.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/constraints.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/bigquery.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/databricks.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/doris.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/hive.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/postgres.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/presto.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/python.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/redshift.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/singlestore.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/snowflake.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/spark2.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/starrocks.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/generators/trino.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/lineage.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/qualify.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/qualify_columns.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/resolver.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/optimizer/scope.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/doris.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/dremio.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/drill.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/hive.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/mysql.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/postgres.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/presto.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/prql.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/redshift.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/singlestore.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/sqlite.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/starrocks.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/teradata.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/parsers/trino.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/schema.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.8.0 → sqlglotc-30.9.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
3
|
+
Version: 30.9.0
|
|
4
4
|
Summary: mypyc-compiled extensions for sqlglot
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,4 +10,4 @@ Requires-Python: >=3.10
|
|
|
10
10
|
Provides-Extra: dev
|
|
11
11
|
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
12
12
|
Requires-Dist: setuptools_scm; extra == "dev"
|
|
13
|
-
Requires-Dist: sqlglot-mypy>=1.
|
|
13
|
+
Requires-Dist: sqlglot-mypy>=2.1.0.post2; extra == "dev"
|
|
@@ -7,7 +7,7 @@ license = "MIT"
|
|
|
7
7
|
requires-python = ">= 3.10"
|
|
8
8
|
|
|
9
9
|
[project.optional-dependencies]
|
|
10
|
-
dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 1.
|
|
10
|
+
dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 2.1.0.post2"]
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
13
13
|
Homepage = "https://sqlglot.com/"
|
|
@@ -17,7 +17,7 @@ Repository = "https://github.com/tobymao/sqlglot"
|
|
|
17
17
|
requires = [
|
|
18
18
|
"setuptools >= 61.0",
|
|
19
19
|
"setuptools_scm",
|
|
20
|
-
"sqlglot-mypy >= 1.
|
|
20
|
+
"sqlglot-mypy >= 2.1.0.post2",
|
|
21
21
|
"types-python-dateutil",
|
|
22
22
|
"sqlglot",
|
|
23
23
|
]
|
|
@@ -88,6 +88,7 @@ class Expr:
|
|
|
88
88
|
_hash_raw_args: t.ClassVar[bool] = False
|
|
89
89
|
is_subquery: t.ClassVar[bool] = False
|
|
90
90
|
is_cast: t.ClassVar[bool] = False
|
|
91
|
+
is_data_type: t.ClassVar[bool] = False
|
|
91
92
|
|
|
92
93
|
args: dict[str, t.Any]
|
|
93
94
|
parent: Expr | None
|
|
@@ -837,26 +838,35 @@ class Expression(Expr):
|
|
|
837
838
|
def __hash__(self) -> int:
|
|
838
839
|
if self._hash is None:
|
|
839
840
|
nodes: list[Expr] = []
|
|
840
|
-
|
|
841
|
-
queue.append(self)
|
|
841
|
+
stack: list[Expr] = [self]
|
|
842
842
|
|
|
843
|
-
|
|
844
|
-
|
|
843
|
+
# Collect nodes, finding child expressions inline instead of via the
|
|
844
|
+
# iter_expressions generator (whose per-node generator object dominates the
|
|
845
|
+
# hash's cost). reversed(nodes) is a valid post-order regardless of DFS/BFS.
|
|
846
|
+
while stack:
|
|
847
|
+
node = stack.pop()
|
|
845
848
|
nodes.append(node)
|
|
846
849
|
|
|
847
|
-
for
|
|
848
|
-
if
|
|
849
|
-
|
|
850
|
+
for v in node.args.values():
|
|
851
|
+
if isinstance(v, Expr):
|
|
852
|
+
if v._hash is None:
|
|
853
|
+
stack.append(v)
|
|
854
|
+
elif type(v) is list:
|
|
855
|
+
for x in v:
|
|
856
|
+
if isinstance(x, Expr) and x._hash is None:
|
|
857
|
+
stack.append(x)
|
|
850
858
|
|
|
851
859
|
for node in reversed(nodes):
|
|
852
860
|
hash_ = hash(node.key)
|
|
853
861
|
|
|
854
862
|
if node._hash_raw_args:
|
|
855
|
-
for k
|
|
863
|
+
for k in sorted(node.args):
|
|
864
|
+
v = node.args[k]
|
|
856
865
|
if v:
|
|
857
866
|
hash_ = hash((hash_, k, v))
|
|
858
867
|
else:
|
|
859
|
-
for k
|
|
868
|
+
for k in sorted(node.args):
|
|
869
|
+
v = node.args[k]
|
|
860
870
|
vt = type(v)
|
|
861
871
|
|
|
862
872
|
if vt is list:
|
|
@@ -953,6 +963,8 @@ class Expression(Expr):
|
|
|
953
963
|
|
|
954
964
|
@property
|
|
955
965
|
def type(self) -> DataType | None:
|
|
966
|
+
if self.is_data_type:
|
|
967
|
+
return self # type: ignore[return-value]
|
|
956
968
|
if self.is_cast:
|
|
957
969
|
return self._type or self.to # type: ignore[attr-defined]
|
|
958
970
|
return self._type
|
|
@@ -1039,6 +1051,11 @@ class Expression(Expr):
|
|
|
1039
1051
|
return comments
|
|
1040
1052
|
|
|
1041
1053
|
def append(self, arg_key: str, value: t.Any) -> None:
|
|
1054
|
+
node: Expr | None = self
|
|
1055
|
+
while node and node._hash is not None:
|
|
1056
|
+
node._hash = None
|
|
1057
|
+
node = node.parent
|
|
1058
|
+
|
|
1042
1059
|
if type(self.args.get(arg_key)) is not list:
|
|
1043
1060
|
self.args[arg_key] = []
|
|
1044
1061
|
self._set_parent(arg_key, value)
|
|
@@ -2118,6 +2135,10 @@ class Distance(Expression, Binary):
|
|
|
2118
2135
|
pass
|
|
2119
2136
|
|
|
2120
2137
|
|
|
2138
|
+
class DistanceNd(Expression, Binary):
|
|
2139
|
+
pass
|
|
2140
|
+
|
|
2141
|
+
|
|
2121
2142
|
class Escape(Expression, Binary):
|
|
2122
2143
|
pass
|
|
2123
2144
|
|
|
@@ -2269,8 +2290,7 @@ class Or(Expression, Connector, Func):
|
|
|
2269
2290
|
|
|
2270
2291
|
|
|
2271
2292
|
class Xor(Expression, Connector, Func):
|
|
2272
|
-
arg_types = {"this":
|
|
2273
|
-
is_var_len_args = True
|
|
2293
|
+
arg_types = {"this": True, "expression": True, "round_input": False}
|
|
2274
2294
|
|
|
2275
2295
|
|
|
2276
2296
|
class Pow(Expression, Binary, Func):
|
|
@@ -2428,6 +2448,7 @@ QUERY_MODIFIERS = {
|
|
|
2428
2448
|
"settings": False,
|
|
2429
2449
|
"format": False,
|
|
2430
2450
|
"options": False,
|
|
2451
|
+
"for_": False,
|
|
2431
2452
|
}
|
|
2432
2453
|
|
|
2433
2454
|
|
|
@@ -2534,7 +2555,7 @@ def _to_s(node: t.Any, verbose: bool = False, level: int = 0, repr_str: bool = F
|
|
|
2534
2555
|
if isinstance(node, Expr):
|
|
2535
2556
|
args = {k: v for k, v in node.args.items() if (v is not None and v != []) or verbose}
|
|
2536
2557
|
|
|
2537
|
-
if (node.type or verbose) and
|
|
2558
|
+
if (node.type or verbose) and not node.is_data_type:
|
|
2538
2559
|
args["_type"] = node.type
|
|
2539
2560
|
if node.comments or verbose:
|
|
2540
2561
|
args["_comments"] = node.comments
|
|
@@ -8,6 +8,7 @@ from enum import auto
|
|
|
8
8
|
from sqlglot.helper import AutoName
|
|
9
9
|
from sqlglot.errors import ErrorLevel, ParseError
|
|
10
10
|
from sqlglot.expressions.core import (
|
|
11
|
+
Expr,
|
|
11
12
|
Expression,
|
|
12
13
|
_TimeUnit,
|
|
13
14
|
Identifier,
|
|
@@ -17,13 +18,18 @@ from sqlglot.expressions.core import (
|
|
|
17
18
|
from builtins import type as Type
|
|
18
19
|
|
|
19
20
|
if t.TYPE_CHECKING:
|
|
21
|
+
from sqlglot._typing import DataTypeArgs
|
|
20
22
|
from sqlglot.dialects.dialect import DialectType
|
|
21
|
-
from typing_extensions import Self
|
|
23
|
+
from typing_extensions import Self, Unpack
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class DataTypeParam(Expression):
|
|
25
27
|
arg_types = {"this": True, "expression": False}
|
|
26
28
|
|
|
29
|
+
@property
|
|
30
|
+
def this(self) -> Expr:
|
|
31
|
+
return self.args["this"]
|
|
32
|
+
|
|
27
33
|
@property
|
|
28
34
|
def name(self) -> str:
|
|
29
35
|
return self.this.name
|
|
@@ -181,6 +187,8 @@ class DataType(Expression):
|
|
|
181
187
|
"collate": False,
|
|
182
188
|
}
|
|
183
189
|
|
|
190
|
+
is_data_type: t.ClassVar[bool] = True
|
|
191
|
+
|
|
184
192
|
Type: t.ClassVar[Type[DType]] = DType
|
|
185
193
|
|
|
186
194
|
STRUCT_TYPES: t.ClassVar[set[DType]] = {
|
|
@@ -331,7 +339,7 @@ class DataType(Expression):
|
|
|
331
339
|
dialect: DialectType = None,
|
|
332
340
|
udt: bool = False,
|
|
333
341
|
copy: bool = True,
|
|
334
|
-
**kwargs:
|
|
342
|
+
**kwargs: Unpack[DataTypeArgs],
|
|
335
343
|
) -> Self:
|
|
336
344
|
"""
|
|
337
345
|
Constructs a DataType object.
|
|
@@ -364,7 +372,11 @@ class DataType(Expression):
|
|
|
364
372
|
|
|
365
373
|
@classmethod
|
|
366
374
|
def from_str(
|
|
367
|
-
cls,
|
|
375
|
+
cls,
|
|
376
|
+
dtype: str,
|
|
377
|
+
dialect: DialectType = None,
|
|
378
|
+
udt: bool = False,
|
|
379
|
+
**kwargs: Unpack[DataTypeArgs],
|
|
368
380
|
) -> Self:
|
|
369
381
|
"""
|
|
370
382
|
Constructs a `DataType` object from a `str` representation.
|
|
@@ -405,10 +417,10 @@ class DataType(Expression):
|
|
|
405
417
|
Returns:
|
|
406
418
|
True, if and only if there is a type in `dtypes` which is equal to this DataType.
|
|
407
419
|
"""
|
|
408
|
-
self_is_nullable = self.args.get("nullable")
|
|
420
|
+
self_is_nullable: bool | None = self.args.get("nullable")
|
|
409
421
|
for dtype in dtypes:
|
|
410
422
|
other_type = DataType.build(dtype, copy=False, udt=True)
|
|
411
|
-
other_is_nullable = other_type.args.get("nullable")
|
|
423
|
+
other_is_nullable: bool | None = other_type.args.get("nullable")
|
|
412
424
|
if (
|
|
413
425
|
other_type.expressions
|
|
414
426
|
or (check_nullable and (self_is_nullable or other_is_nullable))
|
|
@@ -226,6 +226,14 @@ class UserDefinedFunction(Expression):
|
|
|
226
226
|
arg_types = {"this": True, "expressions": False, "wrapped": False}
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
class MacroOverloads(Expression):
|
|
230
|
+
arg_types = {"expressions": True}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class MacroOverload(Expression):
|
|
234
|
+
arg_types = {"this": True, "expressions": False, "is_table": False}
|
|
235
|
+
|
|
236
|
+
|
|
229
237
|
class CharacterSet(Expression):
|
|
230
238
|
arg_types = {"this": True, "default": False}
|
|
231
239
|
|
|
@@ -70,7 +70,7 @@ class Cast(Expression, Func):
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
class TryCast(Cast):
|
|
73
|
-
arg_types = {**Cast.arg_types, "requires_string": False}
|
|
73
|
+
arg_types = {**Cast.arg_types, "requires_string": False, "null_on_text_overflow": False}
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
class JSONCast(Cast):
|
|
@@ -436,6 +436,10 @@ class XMLElement(Expression, Func):
|
|
|
436
436
|
arg_types = {"this": True, "expressions": False, "evalname": False}
|
|
437
437
|
|
|
438
438
|
|
|
439
|
+
class GetIgnoreCase(Expression, Func):
|
|
440
|
+
arg_types = {"this": True, "expression": True}
|
|
441
|
+
|
|
442
|
+
|
|
439
443
|
class XMLGet(Expression, Func):
|
|
440
444
|
_sql_names = ["XMLGET"]
|
|
441
445
|
arg_types = {"this": True, "expression": True, "instance": False}
|
|
@@ -915,6 +915,11 @@ class QueryOption(Expression):
|
|
|
915
915
|
arg_types = {"this": True, "expression": False}
|
|
916
916
|
|
|
917
917
|
|
|
918
|
+
# FOR { XML | JSON } query modifier; `kind` is the discriminant ("XML" or "JSON").
|
|
919
|
+
class ForClause(Expression):
|
|
920
|
+
arg_types = {"kind": True, "expressions": False}
|
|
921
|
+
|
|
922
|
+
|
|
918
923
|
class WithTableHint(Expression):
|
|
919
924
|
arg_types = {"expressions": True}
|
|
920
925
|
|
|
@@ -1753,6 +1758,9 @@ class Pivot(Expression):
|
|
|
1753
1758
|
"default_on_null": False,
|
|
1754
1759
|
"into": False,
|
|
1755
1760
|
"with_": False,
|
|
1761
|
+
"identify_pivot_strings": False,
|
|
1762
|
+
"prefixed_pivot_columns": False,
|
|
1763
|
+
"pivot_column_naming": False,
|
|
1756
1764
|
}
|
|
1757
1765
|
|
|
1758
1766
|
@property
|
|
@@ -1328,7 +1328,9 @@ class Generator:
|
|
|
1328
1328
|
if expression_sql:
|
|
1329
1329
|
expression_sql = f"{begin}{self.sep()}{expression_sql}"
|
|
1330
1330
|
|
|
1331
|
-
if
|
|
1331
|
+
if not isinstance(expression.expression, exp.MacroOverloads) and (
|
|
1332
|
+
self.CREATE_FUNCTION_RETURN_AS or not isinstance(expression.expression, exp.Return)
|
|
1333
|
+
):
|
|
1332
1334
|
postalias_props_sql = ""
|
|
1333
1335
|
if properties_locs.get(exp.Properties.Location.POST_ALIAS):
|
|
1334
1336
|
postalias_props_sql = self.properties(
|
|
@@ -1605,7 +1607,12 @@ class Generator:
|
|
|
1605
1607
|
)
|
|
1606
1608
|
|
|
1607
1609
|
return delimited_byte_string
|
|
1608
|
-
|
|
1610
|
+
|
|
1611
|
+
if "\\" in self.dialect.tokenizer_class.STRING_ESCAPES:
|
|
1612
|
+
return self.sql(exp.Literal.string(this))
|
|
1613
|
+
|
|
1614
|
+
self.unsupported(f"Byte strings are not supported for {self.dialect.__class__.__name__}")
|
|
1615
|
+
return ""
|
|
1609
1616
|
|
|
1610
1617
|
def unicodestring_sql(self, expression: exp.UnicodeString) -> str:
|
|
1611
1618
|
this = self.sql(expression, "this")
|
|
@@ -2454,6 +2461,81 @@ class Generator:
|
|
|
2454
2461
|
|
|
2455
2462
|
return f" {tablesample_keyword or self.TABLESAMPLE_KEYWORDS} {method}{expr}{seed}"
|
|
2456
2463
|
|
|
2464
|
+
def _pivot_in_value_aliases(self, expression: exp.Pivot) -> list[exp.Expression] | None:
|
|
2465
|
+
# Returns the rewritten field.expressions list with PivotAlias wrappers injected where
|
|
2466
|
+
# the stored column name differs from the target dialect's natural output.
|
|
2467
|
+
columns = expression.args.get("columns")
|
|
2468
|
+
if not columns or len(expression.fields) != 1:
|
|
2469
|
+
return None
|
|
2470
|
+
|
|
2471
|
+
args = expression.args
|
|
2472
|
+
parser_cls = self.dialect.parser_class
|
|
2473
|
+
|
|
2474
|
+
tgt_identify_pivot_strings = parser_cls.IDENTIFY_PIVOT_STRINGS
|
|
2475
|
+
tgt_prefixed_pivot_columns = parser_cls.PREFIXED_PIVOT_COLUMNS
|
|
2476
|
+
tgt_pivot_column_naming = parser_cls.PIVOT_COLUMN_NAMING
|
|
2477
|
+
|
|
2478
|
+
src_identify_pivot_strings = args.get("identify_pivot_strings", tgt_identify_pivot_strings)
|
|
2479
|
+
src_prefixed_pivot_columns = args.get("prefixed_pivot_columns", tgt_prefixed_pivot_columns)
|
|
2480
|
+
src_pivot_column_naming = args.get("pivot_column_naming", tgt_pivot_column_naming)
|
|
2481
|
+
|
|
2482
|
+
if (
|
|
2483
|
+
src_identify_pivot_strings == tgt_identify_pivot_strings
|
|
2484
|
+
and src_prefixed_pivot_columns == tgt_prefixed_pivot_columns
|
|
2485
|
+
and src_pivot_column_naming == tgt_pivot_column_naming
|
|
2486
|
+
):
|
|
2487
|
+
return None
|
|
2488
|
+
|
|
2489
|
+
in_exprs = expression.fields[0].expressions
|
|
2490
|
+
step = len(columns) // len(in_exprs)
|
|
2491
|
+
|
|
2492
|
+
# Derive the per-value suffix from the first stored column vs the first IN-list value.
|
|
2493
|
+
# This correctly handles dialects (e.g. Spark single-agg) that ignore agg aliases.
|
|
2494
|
+
first_base = in_exprs[0].sql() if src_identify_pivot_strings else in_exprs[0].alias_or_name
|
|
2495
|
+
first_stored = columns[0].name
|
|
2496
|
+
|
|
2497
|
+
# exit if only suffix matches, not prefix. (e.g. BigQuery, which cannot be fixed)
|
|
2498
|
+
if not first_stored.startswith(first_base):
|
|
2499
|
+
return None
|
|
2500
|
+
|
|
2501
|
+
suffix = first_stored[len(first_base) :]
|
|
2502
|
+
|
|
2503
|
+
# Whether the target dialect would append an agg-name suffix for this pivot.
|
|
2504
|
+
# Spark single-agg uniquely drops the agg alias entirely.
|
|
2505
|
+
target_has_suffix = (
|
|
2506
|
+
len(expression.expressions) > 1 or tgt_pivot_column_naming != "agg_name_if_multiple"
|
|
2507
|
+
) and any(a.alias for a in expression.expressions)
|
|
2508
|
+
source_has_suffix = suffix != ""
|
|
2509
|
+
|
|
2510
|
+
new_exprs: list[exp.Expression] = []
|
|
2511
|
+
modified = False
|
|
2512
|
+
for val_idx, e in enumerate(in_exprs):
|
|
2513
|
+
if isinstance(e, exp.PivotAlias):
|
|
2514
|
+
new_exprs.append(e)
|
|
2515
|
+
continue
|
|
2516
|
+
|
|
2517
|
+
i = val_idx * step
|
|
2518
|
+
stored_full = columns[i].name
|
|
2519
|
+
stored_value = stored_full[: -len(suffix)] if suffix else stored_full
|
|
2520
|
+
target_value = e.sql() if tgt_identify_pivot_strings else e.alias_or_name
|
|
2521
|
+
|
|
2522
|
+
# Source had a suffix, but target won't apply one
|
|
2523
|
+
if source_has_suffix and not target_has_suffix:
|
|
2524
|
+
new_exprs.append(
|
|
2525
|
+
exp.PivotAlias(this=e, alias=exp.to_identifier(stored_full, quoted=True))
|
|
2526
|
+
)
|
|
2527
|
+
modified = True
|
|
2528
|
+
# Value-part mismatch (e.g. Snowflake's literal-style values vs others).
|
|
2529
|
+
elif stored_value != target_value:
|
|
2530
|
+
new_exprs.append(
|
|
2531
|
+
exp.PivotAlias(this=e, alias=exp.to_identifier(stored_value, quoted=True))
|
|
2532
|
+
)
|
|
2533
|
+
modified = True
|
|
2534
|
+
else:
|
|
2535
|
+
new_exprs.append(e)
|
|
2536
|
+
|
|
2537
|
+
return new_exprs if modified else None
|
|
2538
|
+
|
|
2457
2539
|
def pivot_sql(self, expression: exp.Pivot) -> str:
|
|
2458
2540
|
expressions = self.expressions(expression, flat=True)
|
|
2459
2541
|
direction = "UNPIVOT" if expression.unpivot else "PIVOT"
|
|
@@ -2473,6 +2555,12 @@ class Generator:
|
|
|
2473
2555
|
sql = f"{direction} {this}{on}{into}{using}{group}"
|
|
2474
2556
|
return self.prepend_ctes(expression, sql)
|
|
2475
2557
|
|
|
2558
|
+
if not expression.unpivot:
|
|
2559
|
+
# Wrap IN-list values with explicit aliases where the target dialect would differ
|
|
2560
|
+
new_field_exprs = self._pivot_in_value_aliases(expression)
|
|
2561
|
+
if new_field_exprs is not None:
|
|
2562
|
+
expression.fields[0].set("expressions", new_field_exprs)
|
|
2563
|
+
|
|
2476
2564
|
alias = self.sql(expression, "alias")
|
|
2477
2565
|
alias = f" AS {alias}" if alias else ""
|
|
2478
2566
|
|
|
@@ -2896,7 +2984,12 @@ class Generator:
|
|
|
2896
2984
|
if files:
|
|
2897
2985
|
files_sql = self.expressions(files, flat=True)
|
|
2898
2986
|
files_sql = f"FILES{self.wrap(files_sql)}"
|
|
2899
|
-
|
|
2987
|
+
if is_overwrite:
|
|
2988
|
+
this = f" {this}"
|
|
2989
|
+
elif expression.args.get("temp"):
|
|
2990
|
+
this = f" INTO TEMP TABLE {this}"
|
|
2991
|
+
else:
|
|
2992
|
+
this = f" INTO TABLE {this}"
|
|
2900
2993
|
return f"LOAD DATA{overwrite}{this} FROM {files_sql}"
|
|
2901
2994
|
|
|
2902
2995
|
local = " LOCAL" if expression.args.get("local") else ""
|
|
@@ -2955,6 +3048,40 @@ class Generator:
|
|
|
2955
3048
|
def sort_sql(self, expression: exp.Sort) -> str:
|
|
2956
3049
|
return self.op_expressions("SORT BY", expression)
|
|
2957
3050
|
|
|
3051
|
+
def _resolve_ordered_for_null_ordering_simulation(
|
|
3052
|
+
self, expression: exp.Ordered
|
|
3053
|
+
) -> exp.Expr | None:
|
|
3054
|
+
"""Resolve a bare ORDER BY name against the enclosing SELECT projection.
|
|
3055
|
+
|
|
3056
|
+
Returns the underlying expression of the uniquely-matching projection
|
|
3057
|
+
(Alias-stripped) for substitution into the NULLS FIRST/LAST CASE
|
|
3058
|
+
simulation, since the CASE is evaluated in FROM-clause scope rather
|
|
3059
|
+
than alias scope (MySQL error 1052). Returns None if no safe
|
|
3060
|
+
substitution applies, leaving the original behaviour unchanged.
|
|
3061
|
+
"""
|
|
3062
|
+
this = expression.this
|
|
3063
|
+
if not (isinstance(this, exp.Column) and not this.table):
|
|
3064
|
+
return None
|
|
3065
|
+
|
|
3066
|
+
ancestor = expression.find_ancestor(exp.Select, exp.Window)
|
|
3067
|
+
if not isinstance(ancestor, exp.Select):
|
|
3068
|
+
return None
|
|
3069
|
+
|
|
3070
|
+
column_name = this.name
|
|
3071
|
+
matched: list[exp.Expr] = [
|
|
3072
|
+
p.this if isinstance(p, exp.Alias) else p
|
|
3073
|
+
for p in ancestor.selects
|
|
3074
|
+
if p.output_name == column_name
|
|
3075
|
+
]
|
|
3076
|
+
match = matched[0] if len(matched) == 1 else None
|
|
3077
|
+
|
|
3078
|
+
# Skip the substitution when it would be identical to the existing
|
|
3079
|
+
# reference (e.g. ``SELECT col FROM t ORDER BY col``).
|
|
3080
|
+
if isinstance(match, exp.Column) and not match.table and match.name == column_name:
|
|
3081
|
+
return None
|
|
3082
|
+
|
|
3083
|
+
return match
|
|
3084
|
+
|
|
2958
3085
|
def ordered_sql(self, expression: exp.Ordered) -> str:
|
|
2959
3086
|
desc = expression.args.get("desc")
|
|
2960
3087
|
asc = not desc
|
|
@@ -3025,10 +3152,10 @@ class Generator:
|
|
|
3025
3152
|
f"'{nulls_sort_change.strip()}' translation not supported with positional ordering"
|
|
3026
3153
|
)
|
|
3027
3154
|
elif not isinstance(expression.this, exp.Rand):
|
|
3155
|
+
resolved = self._resolve_ordered_for_null_ordering_simulation(expression)
|
|
3156
|
+
target = self.sql(resolved) if resolved is not None else this
|
|
3028
3157
|
null_sort_order = " DESC" if nulls_sort_change == " NULLS FIRST" else ""
|
|
3029
|
-
this =
|
|
3030
|
-
f"CASE WHEN {this} IS NULL THEN 1 ELSE 0 END{null_sort_order}, {this}"
|
|
3031
|
-
)
|
|
3158
|
+
this = f"CASE WHEN {target} IS NULL THEN 1 ELSE 0 END{null_sort_order}, {target}"
|
|
3032
3159
|
nulls_sort_change = ""
|
|
3033
3160
|
|
|
3034
3161
|
with_fill = self.sql(expression, "with_fill")
|
|
@@ -3099,7 +3226,7 @@ class Generator:
|
|
|
3099
3226
|
*self.offset_limit_modifiers(expression, isinstance(limit, exp.Fetch), limit),
|
|
3100
3227
|
*self.after_limit_modifiers(expression),
|
|
3101
3228
|
self.options_modifier(expression),
|
|
3102
|
-
self.
|
|
3229
|
+
self.sql(expression, "for_"),
|
|
3103
3230
|
sep="",
|
|
3104
3231
|
)
|
|
3105
3232
|
|
|
@@ -3107,9 +3234,16 @@ class Generator:
|
|
|
3107
3234
|
options = self.expressions(expression, key="options")
|
|
3108
3235
|
return f" {options}" if options else ""
|
|
3109
3236
|
|
|
3110
|
-
def
|
|
3111
|
-
|
|
3112
|
-
|
|
3237
|
+
def forclause_sql(self, expression: exp.ForClause) -> str:
|
|
3238
|
+
kind = expression.args["kind"]
|
|
3239
|
+
if kind == "BROWSE":
|
|
3240
|
+
return f"{self.sep()}FOR BROWSE"
|
|
3241
|
+
# FOR XML/JSON always carry at least AUTO/PATH. An empty rendering means
|
|
3242
|
+
# the target dialect doesn't support QueryOption, so we drop the clause.
|
|
3243
|
+
options = self.expressions(expression, key="expressions")
|
|
3244
|
+
if not options:
|
|
3245
|
+
return ""
|
|
3246
|
+
return f"{self.sep()}FOR {kind}{self.seg(options)}"
|
|
3113
3247
|
|
|
3114
3248
|
def queryoption_sql(self, expression: exp.QueryOption) -> str:
|
|
3115
3249
|
self.unsupported("Unsupported query option.")
|
|
@@ -3857,9 +3991,7 @@ class Generator:
|
|
|
3857
3991
|
else:
|
|
3858
3992
|
stack.append(expression.right)
|
|
3859
3993
|
if expression.comments and self.comments:
|
|
3860
|
-
|
|
3861
|
-
if comment:
|
|
3862
|
-
op += f" /*{self.sanitize_comment(comment)}*/"
|
|
3994
|
+
op = self.maybe_comment(op, comments=expression.comments)
|
|
3863
3995
|
stack.extend((op, expression.left))
|
|
3864
3996
|
return op
|
|
3865
3997
|
|
|
@@ -4215,6 +4347,9 @@ class Generator:
|
|
|
4215
4347
|
def distance_sql(self, expression: exp.Distance) -> str:
|
|
4216
4348
|
return self.binary(expression, "<->")
|
|
4217
4349
|
|
|
4350
|
+
def distancend_sql(self, expression: exp.DistanceNd) -> str:
|
|
4351
|
+
return self.binary(expression, "<<->>")
|
|
4352
|
+
|
|
4218
4353
|
def dot_sql(self, expression: exp.Dot) -> str:
|
|
4219
4354
|
return f"{self.sql(expression, 'this')}.{self.sql(expression, 'expression')}"
|
|
4220
4355
|
|
|
@@ -4536,6 +4671,15 @@ class Generator:
|
|
|
4536
4671
|
)
|
|
4537
4672
|
return f"{this}{expressions}" if expressions.strip() != "" else this
|
|
4538
4673
|
|
|
4674
|
+
def macrooverloads_sql(self, expression: exp.MacroOverloads) -> str:
|
|
4675
|
+
return self.expressions(expression, flat=True)
|
|
4676
|
+
|
|
4677
|
+
def macrooverload_sql(self, expression: exp.MacroOverload) -> str:
|
|
4678
|
+
params = self.no_identify(self.expressions, expression, flat=True)
|
|
4679
|
+
body = self.sql(expression, "this")
|
|
4680
|
+
prefix = "TABLE " if expression.args.get("is_table") else ""
|
|
4681
|
+
return f"({params}) AS {prefix}{body}"
|
|
4682
|
+
|
|
4539
4683
|
def joinhint_sql(self, expression: exp.JoinHint) -> str:
|
|
4540
4684
|
this = self.sql(expression, "this")
|
|
4541
4685
|
expressions = self.expressions(expression, flat=True)
|
|
@@ -4612,6 +4756,7 @@ class Generator:
|
|
|
4612
4756
|
def tochar_sql(self, expression: exp.ToChar) -> str:
|
|
4613
4757
|
return self.sql(exp.cast(expression.this, exp.DType.TEXT))
|
|
4614
4758
|
|
|
4759
|
+
@unsupported_args("default")
|
|
4615
4760
|
def tonumber_sql(self, expression: exp.ToNumber) -> str:
|
|
4616
4761
|
if not self.SUPPORTS_TO_NUMBER:
|
|
4617
4762
|
self.unsupported("Unsupported TO_NUMBER function")
|
|
@@ -349,7 +349,7 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
349
349
|
exp.TimestampSub: _datetime_delta_sql("TIMESTAMP_SUB"),
|
|
350
350
|
exp.Typeof: rename_func("toTypeName"),
|
|
351
351
|
exp.VarMap: _map_sql,
|
|
352
|
-
exp.Xor: lambda self, e: self.func("xor", e.this, e.expression
|
|
352
|
+
exp.Xor: lambda self, e: self.func("xor", e.this, e.expression),
|
|
353
353
|
exp.MD5Digest: rename_func("MD5"),
|
|
354
354
|
exp.MD5: lambda self, e: self.func("LOWER", self.func("HEX", self.func("MD5", e.this))),
|
|
355
355
|
exp.SHA: rename_func("SHA1"),
|
|
@@ -2285,6 +2285,10 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2285
2285
|
f"({self.sql(exp.replace_placeholders(self.BITMAP_CONSTRUCT_AGG_TEMPLATE, arg=arg))})"
|
|
2286
2286
|
)
|
|
2287
2287
|
|
|
2288
|
+
def getignorecase_sql(self, expression: exp.GetIgnoreCase) -> str:
|
|
2289
|
+
self.unsupported("DuckDB does not support the GET_IGNORE_CASE() function")
|
|
2290
|
+
return self.function_fallback_sql(expression)
|
|
2291
|
+
|
|
2288
2292
|
def compress_sql(self, expression: exp.Compress) -> str:
|
|
2289
2293
|
self.unsupported("DuckDB does not support the COMPRESS() function")
|
|
2290
2294
|
return self.function_fallback_sql(expression)
|
|
@@ -2647,6 +2651,15 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2647
2651
|
)
|
|
2648
2652
|
)
|
|
2649
2653
|
|
|
2654
|
+
def parsetime_sql(self, expression: exp.ParseTime) -> str:
|
|
2655
|
+
formatted_time = self.format_time(expression)
|
|
2656
|
+
return self.sql(
|
|
2657
|
+
exp.cast(
|
|
2658
|
+
self.func("STRPTIME", expression.this, formatted_time),
|
|
2659
|
+
exp.DataType(this=exp.DType.TIME),
|
|
2660
|
+
)
|
|
2661
|
+
)
|
|
2662
|
+
|
|
2650
2663
|
def tsordstotime_sql(self, expression: exp.TsOrDsToTime) -> str:
|
|
2651
2664
|
this = expression.this
|
|
2652
2665
|
time_format = self.format_time(expression)
|
|
@@ -4313,6 +4326,27 @@ class DuckDBGenerator(generator.Generator):
|
|
|
4313
4326
|
|
|
4314
4327
|
return self.func(func, this, decimals, truncate)
|
|
4315
4328
|
|
|
4329
|
+
def trycast_sql(self, expression: exp.TryCast) -> str:
|
|
4330
|
+
to = expression.to
|
|
4331
|
+
to_type = to.this
|
|
4332
|
+
|
|
4333
|
+
if (
|
|
4334
|
+
expression.args.get("null_on_text_overflow")
|
|
4335
|
+
and to_type in exp.DataType.TEXT_TYPES
|
|
4336
|
+
and to.expressions
|
|
4337
|
+
):
|
|
4338
|
+
src = expression.this
|
|
4339
|
+
return self.sql(
|
|
4340
|
+
exp.case()
|
|
4341
|
+
.when(
|
|
4342
|
+
exp.LTE(this=exp.func("LENGTH", src), expression=to.expressions[0].this),
|
|
4343
|
+
exp.cast(src, "TEXT"),
|
|
4344
|
+
)
|
|
4345
|
+
.else_(exp.Null())
|
|
4346
|
+
)
|
|
4347
|
+
|
|
4348
|
+
return super().trycast_sql(expression)
|
|
4349
|
+
|
|
4316
4350
|
def strtok_sql(self, expression: exp.Strtok) -> str:
|
|
4317
4351
|
string_arg = expression.this
|
|
4318
4352
|
delimiter_arg = expression.args.get("delimiter")
|
|
@@ -916,6 +916,12 @@ class ExasolGenerator(generator.Generator):
|
|
|
916
916
|
)
|
|
917
917
|
return self.sql(select)
|
|
918
918
|
|
|
919
|
+
if expression.name == "DATABASES":
|
|
920
|
+
select = exp.select(exp.column("SCHEMA_NAME")).from_(
|
|
921
|
+
exp.table_("EXA_SCHEMAS", db="SYS")
|
|
922
|
+
)
|
|
923
|
+
return self.sql(select)
|
|
924
|
+
|
|
919
925
|
return super().show_sql(expression)
|
|
920
926
|
|
|
921
927
|
def collate_sql(self, expression: exp.Collate) -> str:
|