sqlglotc 30.21.0__tar.gz → 30.22.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.21.0/sqlglotc.egg-info → sqlglotc-30.22.0}/PKG-INFO +3 -3
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/pyproject.toml +2 -2
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/setup.py +0 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/array.py +15 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/builders.py +1 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/ddl.py +1 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/properties.py +3 -5
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/query.py +28 -3
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/string.py +4 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generator.py +114 -33
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/bigquery.py +4 -2
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/clickhouse.py +20 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/doris.py +1 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/dremio.py +1 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/drill.py +7 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/duckdb.py +76 -9
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/hive.py +1 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/materialize.py +6 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/mysql.py +25 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/oracle.py +1 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/postgres.py +15 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/presto.py +9 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/redshift.py +8 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/risingwave.py +2 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/singlestore.py +5 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/snowflake.py +5 -48
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/sqlite.py +2 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/starrocks.py +8 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/trino.py +1 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/tsql.py +12 -4
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/lineage.py +19 -6
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/qualify.py +0 -3
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/qualify_columns.py +93 -22
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/qualify_tables.py +32 -8
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/resolver.py +29 -25
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/scope.py +31 -13
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/simplify.py +9 -2
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parser.py +243 -75
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/clickhouse.py +14 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/doris.py +3 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/duckdb.py +3 -2
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/mysql.py +30 -5
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/postgres.py +3 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/snowflake.py +11 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/spark.py +4 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/spark2.py +6 -1
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/starrocks.py +3 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/trino.py +25 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/tsql.py +72 -2
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/tokenizer_core.py +99 -20
- {sqlglotc-30.21.0 → sqlglotc-30.22.0/sqlglotc.egg-info}/PKG-INFO +3 -3
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglotc.egg-info/SOURCES.txt +0 -1
- sqlglotc-30.22.0/sqlglotc.egg-info/requires.txt +6 -0
- sqlglotc-30.22.0/sqlglotc.egg-info/scm_version.json +8 -0
- sqlglotc-30.21.0/sqlglot/schema.py +0 -813
- sqlglotc-30.21.0/sqlglotc.egg-info/requires.txt +0 -6
- sqlglotc-30.21.0/sqlglotc.egg-info/scm_version.json +0 -8
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/MANIFEST.in +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/setup.cfg +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/anonymize.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/constraints.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/core.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/datatypes.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/functions.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/databricks.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/dax.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/exasol.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/python.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/spark2.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/annotate_types.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/bigquery.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/dax.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/dremio.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/drill.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/hive.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/oracle.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/presto.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/prql.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/redshift.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/singlestore.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/sqlite.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/parsers/teradata.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/serde.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglotc.egg-info/scm_file_list.json +0 -0
- {sqlglotc-30.21.0 → sqlglotc-30.22.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
3
|
+
Version: 30.22.0
|
|
4
4
|
Summary: mypyc-compiled extensions for sqlglot
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://sqlglot.com/
|
|
8
8
|
Project-URL: Repository, https://github.com/tobymao/sqlglot
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
|
-
Requires-Dist: sqlglot==30.
|
|
10
|
+
Requires-Dist: sqlglot==30.22.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
13
13
|
Requires-Dist: setuptools_scm; extra == "dev"
|
|
14
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: mypy>=2.4.0; extra == "dev"
|
|
15
15
|
Dynamic: requires-dist
|
|
@@ -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", "
|
|
10
|
+
dev = ["setuptools >= 61.0", "setuptools_scm", "mypy >= 2.4.0"]
|
|
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
|
-
"
|
|
20
|
+
"mypy >= 2.4.0",
|
|
21
21
|
"types-python-dateutil",
|
|
22
22
|
"sqlglot",
|
|
23
23
|
]
|
|
@@ -23,6 +23,7 @@ class Array(Expression, Func):
|
|
|
23
23
|
"expressions": False,
|
|
24
24
|
"bracket_notation": False,
|
|
25
25
|
"struct_name_inheritance": False,
|
|
26
|
+
"value_constructor": False,
|
|
26
27
|
}
|
|
27
28
|
is_var_len_args = True
|
|
28
29
|
|
|
@@ -84,7 +85,16 @@ class ArrayReverse(Expression, Func):
|
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
class ArraySlice(Expression, Func):
|
|
87
|
-
|
|
88
|
+
"""Slice by end index, or by length when is_length is set."""
|
|
89
|
+
|
|
90
|
+
arg_types = {
|
|
91
|
+
"this": True,
|
|
92
|
+
"start": True,
|
|
93
|
+
"end": False,
|
|
94
|
+
"step": False,
|
|
95
|
+
"zero_based": False,
|
|
96
|
+
"is_length": False,
|
|
97
|
+
}
|
|
88
98
|
|
|
89
99
|
|
|
90
100
|
class ArraySort(Expression, Func):
|
|
@@ -244,6 +254,10 @@ class Inline(Expression, Func, UDTF):
|
|
|
244
254
|
pass
|
|
245
255
|
|
|
246
256
|
|
|
257
|
+
class SplitToTable(Expression, Func, UDTF):
|
|
258
|
+
arg_types = {"this": True, "expression": True}
|
|
259
|
+
|
|
260
|
+
|
|
247
261
|
class Stack(Expression, Func, UDTF):
|
|
248
262
|
arg_types = {"this": True, "expressions": True}
|
|
249
263
|
is_var_len_args = True
|
|
@@ -624,7 +624,9 @@ class Properties(Expression):
|
|
|
624
624
|
"INCLUDE": IncludeProperty,
|
|
625
625
|
}
|
|
626
626
|
|
|
627
|
-
PROPERTY_TO_NAME: t.ClassVar[dict[type[Property], str]] = {
|
|
627
|
+
PROPERTY_TO_NAME: t.ClassVar[dict[type[Property], str]] = {
|
|
628
|
+
v: k for k, v in NAME_TO_PROPERTY.items()
|
|
629
|
+
}
|
|
628
630
|
|
|
629
631
|
# CREATE property locations
|
|
630
632
|
# Form: schema specified
|
|
@@ -652,7 +654,3 @@ class Properties(Expression):
|
|
|
652
654
|
expressions.append(Property(this=Literal.string(key), value=convert(value)))
|
|
653
655
|
|
|
654
656
|
return cls(expressions=expressions)
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
# TODO (mypyc)
|
|
658
|
-
Properties.PROPERTY_TO_NAME = {v: k for k, v in Properties.NAME_TO_PROPERTY.items()}
|
|
@@ -19,6 +19,7 @@ from sqlglot.expressions.core import (
|
|
|
19
19
|
Hint,
|
|
20
20
|
Identifier,
|
|
21
21
|
In,
|
|
22
|
+
Var,
|
|
22
23
|
_apply_builder,
|
|
23
24
|
_apply_child_list_builder,
|
|
24
25
|
_apply_list_builder,
|
|
@@ -441,11 +442,24 @@ class QueryBand(Expression):
|
|
|
441
442
|
|
|
442
443
|
|
|
443
444
|
class RecursiveWithSearch(Expression):
|
|
444
|
-
arg_types = {
|
|
445
|
+
arg_types = {
|
|
446
|
+
"kind": True,
|
|
447
|
+
"this": True,
|
|
448
|
+
"expression": True,
|
|
449
|
+
"to": False,
|
|
450
|
+
"default": False,
|
|
451
|
+
"using": False,
|
|
452
|
+
}
|
|
445
453
|
|
|
446
454
|
|
|
447
455
|
class With(Expression):
|
|
448
|
-
arg_types = {
|
|
456
|
+
arg_types = {
|
|
457
|
+
"expressions": False,
|
|
458
|
+
"recursive": False,
|
|
459
|
+
"search": False,
|
|
460
|
+
"cycle": False,
|
|
461
|
+
"udfs": False,
|
|
462
|
+
}
|
|
449
463
|
|
|
450
464
|
@property
|
|
451
465
|
def recursive(self) -> bool:
|
|
@@ -572,7 +586,7 @@ class ConditionalInsert(Expression):
|
|
|
572
586
|
|
|
573
587
|
|
|
574
588
|
class MultitableInserts(Expression):
|
|
575
|
-
arg_types = {"expressions": True, "kind":
|
|
589
|
+
arg_types = {"with_": False, "expressions": True, "kind": False, "source": True}
|
|
576
590
|
|
|
577
591
|
|
|
578
592
|
class OnCondition(Expression):
|
|
@@ -657,6 +671,11 @@ class Limit(Expression):
|
|
|
657
671
|
"expressions": False,
|
|
658
672
|
}
|
|
659
673
|
|
|
674
|
+
@property
|
|
675
|
+
def is_limit_all(self) -> bool:
|
|
676
|
+
limit_expression = self.args.get("expression")
|
|
677
|
+
return isinstance(limit_expression, Var) and limit_expression.name.upper() == "ALL"
|
|
678
|
+
|
|
660
679
|
|
|
661
680
|
class LimitOptions(Expression):
|
|
662
681
|
arg_types = {
|
|
@@ -954,6 +973,12 @@ class Get(Expression):
|
|
|
954
973
|
arg_types = {"this": True, "target": True, "properties": False}
|
|
955
974
|
|
|
956
975
|
|
|
976
|
+
class ListStage(Expression):
|
|
977
|
+
"""Lists files in a Snowflake stage or Git repository clone."""
|
|
978
|
+
|
|
979
|
+
arg_types = {"this": True, "pattern": False}
|
|
980
|
+
|
|
981
|
+
|
|
957
982
|
class Table(Expression, Selectable):
|
|
958
983
|
arg_types = {
|
|
959
984
|
"this": False,
|
|
@@ -25,6 +25,8 @@ if t.TYPE_CHECKING:
|
|
|
25
25
|
|
|
26
26
|
logger = logging.getLogger("sqlglot")
|
|
27
27
|
|
|
28
|
+
_HIGH_BYTE_RE = re.compile(r"[\x80-\xff]")
|
|
29
|
+
|
|
28
30
|
ESCAPED_UNICODE_RE = re.compile(r"\\(\d+)")
|
|
29
31
|
UNSUPPORTED_TEMPLATE = "Argument '{}' is not supported for expression '{}' when targeting {}."
|
|
30
32
|
|
|
@@ -380,6 +382,12 @@ class Generator:
|
|
|
380
382
|
# Whether comparing against booleans (e.g. x IS TRUE) is supported
|
|
381
383
|
IS_BOOL_ALLOWED = True
|
|
382
384
|
|
|
385
|
+
# Whether casting a fractional number to an integer rounds it instead of truncating it
|
|
386
|
+
CAST_TO_INT_ROUNDS = False
|
|
387
|
+
|
|
388
|
+
# Whether the native integer division operator returns NULL for a zero divisor instead of raising
|
|
389
|
+
SAFE_INT_DIVISION = False
|
|
390
|
+
|
|
383
391
|
# Whether to include the "SET" keyword in the "INSERT ... ON DUPLICATE KEY UPDATE" statement
|
|
384
392
|
DUPLICATE_KEY_UPDATE_WITH_SET = True
|
|
385
393
|
|
|
@@ -565,6 +573,9 @@ class Generator:
|
|
|
565
573
|
# The HEX function name
|
|
566
574
|
HEX_FUNC = "HEX"
|
|
567
575
|
|
|
576
|
+
# Function that constructs a binary value from a hex-encoded byte string.
|
|
577
|
+
BYTE_STRING_FUNCTION = ""
|
|
578
|
+
|
|
568
579
|
# The keywords to use when prefixing & separating WITH based properties
|
|
569
580
|
WITH_PROPERTIES_PREFIX = "WITH"
|
|
570
581
|
|
|
@@ -871,6 +882,10 @@ class Generator:
|
|
|
871
882
|
exp.Mod,
|
|
872
883
|
)
|
|
873
884
|
|
|
885
|
+
# ALTER options that follow the others without a comma, e.g. MySQL's
|
|
886
|
+
# ENGINE=InnoDB PARTITION BY LIST (...) or StarRocks' PARTITION BY ... DISTRIBUTED BY ...
|
|
887
|
+
ALTER_PARTITION_OPTIONS: t.ClassVar[tuple[type[exp.Expr], ...]] = ()
|
|
888
|
+
|
|
874
889
|
SAFE_JSON_PATH_KEY_RE: t.ClassVar = exp.SAFE_IDENTIFIER_RE
|
|
875
890
|
|
|
876
891
|
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
|
|
@@ -892,6 +907,7 @@ class Generator:
|
|
|
892
907
|
"_escaped_quote_end",
|
|
893
908
|
"_escaped_byte_quote_end",
|
|
894
909
|
"_escaped_identifier_end",
|
|
910
|
+
"_identifier_escaped_sequences",
|
|
895
911
|
"_next_name",
|
|
896
912
|
"_identifier_start",
|
|
897
913
|
"_identifier_end",
|
|
@@ -944,6 +960,7 @@ class Generator:
|
|
|
944
960
|
else ""
|
|
945
961
|
)
|
|
946
962
|
self._escaped_identifier_end = self.dialect.IDENTIFIER_END * 2
|
|
963
|
+
self._identifier_escaped_sequences = self.dialect.IDENTIFIER_ESCAPED_SEQUENCES
|
|
947
964
|
|
|
948
965
|
self._next_name = name_sequence("_t")
|
|
949
966
|
|
|
@@ -1569,8 +1586,10 @@ class Generator:
|
|
|
1569
1586
|
)
|
|
1570
1587
|
search = self.sql(expression, "search")
|
|
1571
1588
|
search = f" {search}" if search else ""
|
|
1589
|
+
cycle = self.sql(expression, "cycle")
|
|
1590
|
+
cycle = f" {cycle}" if cycle else ""
|
|
1572
1591
|
|
|
1573
|
-
sql = f"WITH {recursive}{sql}{search}" if sql else ""
|
|
1592
|
+
sql = f"WITH {recursive}{sql}{search}{cycle}" if sql else ""
|
|
1574
1593
|
return f"{udfs} {sql}" if udfs and sql else f"{udfs}{sql}"
|
|
1575
1594
|
|
|
1576
1595
|
def cte_sql(self, expression: exp.CTE) -> str:
|
|
@@ -1642,15 +1661,23 @@ class Generator:
|
|
|
1642
1661
|
|
|
1643
1662
|
def bytestring_sql(self, expression: exp.ByteString) -> str:
|
|
1644
1663
|
this = self.sql(expression, "this")
|
|
1664
|
+
is_bytes = bool(expression.args.get("is_bytes"))
|
|
1665
|
+
if is_bytes and self.BYTE_STRING_FUNCTION:
|
|
1666
|
+
# Hex digits can be quoted directly without escaping.
|
|
1667
|
+
return self.func(self.BYTE_STRING_FUNCTION, f"'{this.encode('latin-1').hex()}'")
|
|
1668
|
+
|
|
1645
1669
|
if self.dialect.BYTE_START:
|
|
1646
1670
|
escaped_byte_string = self.escape_str(
|
|
1647
1671
|
this,
|
|
1648
|
-
escape_backslash=
|
|
1672
|
+
escape_backslash=bool(
|
|
1673
|
+
self.dialect.tokenizer_class.NUMERIC_ESCAPES
|
|
1674
|
+
or self.dialect.tokenizer_class.DROP_UNKNOWN_ESCAPES
|
|
1675
|
+
),
|
|
1649
1676
|
delimiter=self.dialect.BYTE_END,
|
|
1650
1677
|
escaped_delimiter=self._escaped_byte_quote_end,
|
|
1651
1678
|
is_byte_string=True,
|
|
1679
|
+
is_bytes=is_bytes,
|
|
1652
1680
|
)
|
|
1653
|
-
is_bytes = expression.args.get("is_bytes", False)
|
|
1654
1681
|
delimited_byte_string = (
|
|
1655
1682
|
f"{self.dialect.BYTE_START}{escaped_byte_string}{self.dialect.BYTE_END}"
|
|
1656
1683
|
)
|
|
@@ -1787,7 +1814,8 @@ class Generator:
|
|
|
1787
1814
|
if type_value == exp.DType.USERDEFINED and expression.args.get("kind"):
|
|
1788
1815
|
type_sql = self.sql(expression, "kind")
|
|
1789
1816
|
elif type_value == exp.DType.CHARACTER_SET:
|
|
1790
|
-
|
|
1817
|
+
char = f"CHAR({interior})" if interior else "CHAR"
|
|
1818
|
+
return f"{char} CHARACTER SET {self.sql(expression, 'kind')}"
|
|
1791
1819
|
else:
|
|
1792
1820
|
type_sql = (
|
|
1793
1821
|
self.TYPE_MAPPING.get(type_value, type_value.value)
|
|
@@ -2031,6 +2059,9 @@ class Generator:
|
|
|
2031
2059
|
lower = text.lower()
|
|
2032
2060
|
quoted = expression.quoted
|
|
2033
2061
|
text = lower if self.normalize and not quoted else text
|
|
2062
|
+
if self._identifier_escaped_sequences:
|
|
2063
|
+
for char, escaped in self._identifier_escaped_sequences.items():
|
|
2064
|
+
text = text.replace(char, escaped)
|
|
2034
2065
|
text = text.replace(self._identifier_end, self._escaped_identifier_end)
|
|
2035
2066
|
if (
|
|
2036
2067
|
quoted
|
|
@@ -2985,6 +3016,9 @@ class Generator:
|
|
|
2985
3016
|
def limit_sql(self, expression: exp.Limit, top: bool = False) -> str:
|
|
2986
3017
|
this = self.sql(expression, "this")
|
|
2987
3018
|
|
|
3019
|
+
if expression.is_limit_all and not self.dialect.SUPPORTS_LIMIT_ALL:
|
|
3020
|
+
return this
|
|
3021
|
+
|
|
2988
3022
|
args = [
|
|
2989
3023
|
self._simplify_unless_literal(e) if self.LIMIT_ONLY_LITERALS else e
|
|
2990
3024
|
for e in (expression.args.get(k) for k in ("offset", "expression"))
|
|
@@ -3072,6 +3106,7 @@ class Generator:
|
|
|
3072
3106
|
delimiter: str | None = None,
|
|
3073
3107
|
escaped_delimiter: str | None = None,
|
|
3074
3108
|
is_byte_string: bool = False,
|
|
3109
|
+
is_bytes: bool = False,
|
|
3075
3110
|
) -> str:
|
|
3076
3111
|
if is_byte_string:
|
|
3077
3112
|
supports_escape_sequences = self.dialect.BYTE_STRINGS_SUPPORT_ESCAPED_SEQUENCES
|
|
@@ -3084,6 +3119,10 @@ class Generator:
|
|
|
3084
3119
|
for ch in text
|
|
3085
3120
|
)
|
|
3086
3121
|
|
|
3122
|
+
if is_bytes and "x" in self.dialect.tokenizer_class.NUMERIC_ESCAPES:
|
|
3123
|
+
# Escape high bytes so they aren't re-encoded as UTF-8 characters.
|
|
3124
|
+
text = _HIGH_BYTE_RE.sub(lambda m: f"\\x{ord(m.group()):02x}", text)
|
|
3125
|
+
|
|
3087
3126
|
delimiter = delimiter or self.dialect.QUOTE_END
|
|
3088
3127
|
escaped_delimiter = escaped_delimiter or self._escaped_quote_end
|
|
3089
3128
|
|
|
@@ -3184,7 +3223,9 @@ class Generator:
|
|
|
3184
3223
|
if not (isinstance(this, exp.Column) and not this.table):
|
|
3185
3224
|
return None
|
|
3186
3225
|
|
|
3187
|
-
|
|
3226
|
+
# Only a query's own ORDER BY can reference its projection aliases
|
|
3227
|
+
order = expression.parent
|
|
3228
|
+
ancestor = order.parent if isinstance(order, exp.Order) else None
|
|
3188
3229
|
if not isinstance(ancestor, exp.Select):
|
|
3189
3230
|
return None
|
|
3190
3231
|
|
|
@@ -3334,7 +3375,9 @@ class Generator:
|
|
|
3334
3375
|
limit = exp.Limit(
|
|
3335
3376
|
expression=exp.maybe_copy(count) if count is not None else exp.Literal.number(1)
|
|
3336
3377
|
)
|
|
3337
|
-
elif
|
|
3378
|
+
elif (
|
|
3379
|
+
self.LIMIT_FETCH == "FETCH" and isinstance(limit, exp.Limit) and not limit.is_limit_all
|
|
3380
|
+
):
|
|
3338
3381
|
limit = exp.Fetch(direction="FIRST", count=exp.maybe_copy(limit.expression))
|
|
3339
3382
|
|
|
3340
3383
|
return csv(
|
|
@@ -4384,10 +4427,12 @@ class Generator:
|
|
|
4384
4427
|
return f"SET {exprs}"
|
|
4385
4428
|
|
|
4386
4429
|
def alter_sql(self, expression: exp.Alter) -> str:
|
|
4387
|
-
actions = expression.
|
|
4430
|
+
actions = expression.actions
|
|
4388
4431
|
|
|
4389
|
-
if
|
|
4390
|
-
|
|
4432
|
+
if (
|
|
4433
|
+
not self.dialect.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN
|
|
4434
|
+
and actions
|
|
4435
|
+
and isinstance(actions[0], exp.ColumnDef)
|
|
4391
4436
|
):
|
|
4392
4437
|
actions_sql = self.expressions(expression, key="actions", flat=True)
|
|
4393
4438
|
actions_sql = f"ADD {actions_sql}"
|
|
@@ -4414,8 +4459,18 @@ class Generator:
|
|
|
4414
4459
|
on_cluster = self.sql(expression, "cluster")
|
|
4415
4460
|
on_cluster = f" {on_cluster}" if on_cluster else ""
|
|
4416
4461
|
only = " ONLY" if expression.args.get("only") else ""
|
|
4417
|
-
options =
|
|
4418
|
-
|
|
4462
|
+
options = expression.args.get("options") or []
|
|
4463
|
+
options_sql = self.expressions(
|
|
4464
|
+
sqls=[o for o in options if not isinstance(o, self.ALTER_PARTITION_OPTIONS)]
|
|
4465
|
+
)
|
|
4466
|
+
options_sql = f", {options_sql}" if options_sql and actions_sql else options_sql
|
|
4467
|
+
partitions_sql = self.expressions(
|
|
4468
|
+
sqls=[o for o in options if isinstance(o, self.ALTER_PARTITION_OPTIONS)],
|
|
4469
|
+
sep=" ",
|
|
4470
|
+
flat=True,
|
|
4471
|
+
)
|
|
4472
|
+
if partitions_sql and (actions_sql or options_sql):
|
|
4473
|
+
partitions_sql = f" {partitions_sql}"
|
|
4419
4474
|
kind = self.sql(expression, "kind")
|
|
4420
4475
|
not_valid = " NOT VALID" if expression.args.get("not_valid") else ""
|
|
4421
4476
|
check = " WITH CHECK" if expression.args.get("check") else ""
|
|
@@ -4427,7 +4482,7 @@ class Generator:
|
|
|
4427
4482
|
this = self.sql(expression, "this")
|
|
4428
4483
|
this = f" {this}" if this else ""
|
|
4429
4484
|
|
|
4430
|
-
return f"ALTER {iceberg}{kind}{exists}{only}{this}{on_cluster}{check}{self.sep()}{actions_sql}{not_valid}{
|
|
4485
|
+
return f"ALTER {iceberg}{kind}{exists}{only}{this}{on_cluster}{check}{self.sep()}{actions_sql}{not_valid}{options_sql}{partitions_sql}{cascade}"
|
|
4431
4486
|
|
|
4432
4487
|
def altersession_sql(self, expression: exp.AlterSession) -> str:
|
|
4433
4488
|
items_sql = self.expressions(expression, flat=True)
|
|
@@ -4490,12 +4545,14 @@ class Generator:
|
|
|
4490
4545
|
return f"{this_sql} HAVING {kind} {expression_sql}"
|
|
4491
4546
|
|
|
4492
4547
|
def intdiv_sql(self, expression: exp.IntDiv) -> str:
|
|
4493
|
-
return self.
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4548
|
+
return self._truncated_div_sql(expression.this, expression.expression)
|
|
4549
|
+
|
|
4550
|
+
def _truncated_div_sql(self, this: exp.Expr, divisor: exp.Expr) -> str:
|
|
4551
|
+
div: exp.Expr = exp.Div(this=this, expression=divisor)
|
|
4552
|
+
if self.CAST_TO_INT_ROUNDS:
|
|
4553
|
+
div = exp.Trunc(this=div)
|
|
4554
|
+
|
|
4555
|
+
return self.sql(exp.Cast(this=div, to=exp.DataType(this=exp.DType.BIGINT)))
|
|
4499
4556
|
|
|
4500
4557
|
def dpipe_sql(self, expression: exp.DPipe) -> str:
|
|
4501
4558
|
if self.dialect.STRICT_STRING_CONCAT and expression.args.get("safe"):
|
|
@@ -4514,12 +4571,14 @@ class Generator:
|
|
|
4514
4571
|
|
|
4515
4572
|
elif not self.dialect.TYPED_DIVISION and expression.args.get("typed"):
|
|
4516
4573
|
if l.is_type(*exp.DataType.INTEGER_TYPES) and r.is_type(*exp.DataType.INTEGER_TYPES):
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
)
|
|
4522
|
-
)
|
|
4574
|
+
# Native integer division depends on the target's operand types, which may differ
|
|
4575
|
+
# from the source's (e.g. FLOOR(int) is DOUBLE in DuckDB), unless the operands are
|
|
4576
|
+
# integer literals or casts
|
|
4577
|
+
if all(e.is_int or isinstance(e, exp.Cast) for e in (l, r)) and (
|
|
4578
|
+
expression.args.get("safe") or not self.SAFE_INT_DIVISION
|
|
4579
|
+
):
|
|
4580
|
+
return self.sql(exp.IntDiv(this=l, expression=r))
|
|
4581
|
+
return self._truncated_div_sql(l, r)
|
|
4523
4582
|
|
|
4524
4583
|
return self.binary(expression, "/")
|
|
4525
4584
|
|
|
@@ -4740,12 +4799,11 @@ class Generator:
|
|
|
4740
4799
|
elif arg_value is not None:
|
|
4741
4800
|
args.append(arg_value)
|
|
4742
4801
|
|
|
4743
|
-
|
|
4744
|
-
name = expression.meta_get("name") or expression.sql_name()
|
|
4745
|
-
else:
|
|
4746
|
-
name = expression.sql_name()
|
|
4802
|
+
return self.func(self.function_name(expression), *args)
|
|
4747
4803
|
|
|
4748
|
-
|
|
4804
|
+
def function_name(self, expression: exp.Func) -> str:
|
|
4805
|
+
name_key = self.dialect.ORIGINAL_NAME_META_KEY
|
|
4806
|
+
return (expression.meta_get(name_key) if name_key else None) or expression.sql_name()
|
|
4749
4807
|
|
|
4750
4808
|
def func(
|
|
4751
4809
|
self,
|
|
@@ -5745,9 +5803,18 @@ class Generator:
|
|
|
5745
5803
|
|
|
5746
5804
|
def multitableinserts_sql(self, expression: exp.MultitableInserts) -> str:
|
|
5747
5805
|
kind = self.sql(expression, "kind")
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5806
|
+
source = self.sql(expression, "source")
|
|
5807
|
+
|
|
5808
|
+
if kind:
|
|
5809
|
+
expressions = self.seg(self.expressions(expression, sep=" "))
|
|
5810
|
+
sql = f"INSERT {kind}{expressions}{self.seg(source)}"
|
|
5811
|
+
else:
|
|
5812
|
+
# If kind isn't present, we have Hive's FROM-first form:
|
|
5813
|
+
# FROM x INSERT ... SELECT ... [INSERT ... SELECT ...]
|
|
5814
|
+
inserts = self.sep().join(self.sql(e) for e in expression.expressions)
|
|
5815
|
+
sql = f"FROM {source}{self.seg(inserts)}"
|
|
5816
|
+
|
|
5817
|
+
return self.prepend_ctes(expression, sql)
|
|
5751
5818
|
|
|
5752
5819
|
def oncondition_sql(self, expression: exp.OnCondition) -> str:
|
|
5753
5820
|
# Static options like "NULL ON ERROR" are stored as strings, in contrast to "DEFAULT <expr> ON ERROR"
|
|
@@ -6183,12 +6250,16 @@ class Generator:
|
|
|
6183
6250
|
kind = self.sql(expression, "kind")
|
|
6184
6251
|
this = self.sql(expression, "this")
|
|
6185
6252
|
set = self.sql(expression, "expression")
|
|
6253
|
+
to = self.sql(expression, "to")
|
|
6254
|
+
to = f" TO {to}" if to else ""
|
|
6255
|
+
default = self.sql(expression, "default")
|
|
6256
|
+
default = f" DEFAULT {default}" if default else ""
|
|
6186
6257
|
using = self.sql(expression, "using")
|
|
6187
6258
|
using = f" USING {using}" if using else ""
|
|
6188
6259
|
|
|
6189
6260
|
kind_sql = kind if kind == "CYCLE" else f"SEARCH {kind} FIRST BY"
|
|
6190
6261
|
|
|
6191
|
-
return f"{kind_sql} {this} SET {set}{using}"
|
|
6262
|
+
return f"{kind_sql} {this} SET {set}{to}{default}{using}"
|
|
6192
6263
|
|
|
6193
6264
|
def parameterizedagg_sql(self, expression: exp.ParameterizedAgg) -> str:
|
|
6194
6265
|
params = self.expressions(expression, key="params", flat=True)
|
|
@@ -6211,6 +6282,11 @@ class Generator:
|
|
|
6211
6282
|
self.unsupported("Unsupported INSTALL statement")
|
|
6212
6283
|
return ""
|
|
6213
6284
|
|
|
6285
|
+
def liststage_sql(self, expression: exp.ListStage) -> str:
|
|
6286
|
+
pattern = self.sql(expression, "pattern")
|
|
6287
|
+
pattern = f" PATTERN = {pattern}" if pattern else ""
|
|
6288
|
+
return f"LIST {self.sql(expression, 'this')}{pattern}"
|
|
6289
|
+
|
|
6214
6290
|
def get_put_sql(self, expression: exp.Put | exp.Get) -> str:
|
|
6215
6291
|
# Snowflake GET/PUT statements:
|
|
6216
6292
|
# PUT <file> <internalStage> <properties>
|
|
@@ -6389,6 +6465,11 @@ class Generator:
|
|
|
6389
6465
|
using = f" USING {charset}" if charset else ""
|
|
6390
6466
|
return self.func(name, this + using)
|
|
6391
6467
|
|
|
6468
|
+
def weightstring_sql(self, expression: exp.WeightString) -> str:
|
|
6469
|
+
to = self.sql(expression, "to")
|
|
6470
|
+
to = f" AS {to}" if to else ""
|
|
6471
|
+
return self.func("WEIGHT_STRING", f"{self.sql(expression, 'this')}{to}")
|
|
6472
|
+
|
|
6392
6473
|
def block_sql(self, expression: exp.Block) -> str:
|
|
6393
6474
|
expressions = self.expressions(expression, sep="; ", flat=True)
|
|
6394
6475
|
begin = "BEGIN " if expression.args.get("begin") else ""
|
|
@@ -15,6 +15,7 @@ from sqlglot.dialects.dialect import (
|
|
|
15
15
|
inline_array_unless_query,
|
|
16
16
|
max_or_greatest,
|
|
17
17
|
min_or_least,
|
|
18
|
+
no_filter_sql,
|
|
18
19
|
no_ilike_sql,
|
|
19
20
|
regexp_replace_sql,
|
|
20
21
|
rename_func,
|
|
@@ -229,8 +230,7 @@ def _levenshtein_sql(self: BigQueryGenerator, expression: exp.Levenshtein) -> st
|
|
|
229
230
|
|
|
230
231
|
|
|
231
232
|
def _json_extract_sql(self: BigQueryGenerator, expression: JSON_EXTRACT_TYPE) -> str:
|
|
232
|
-
|
|
233
|
-
upper = name.upper()
|
|
233
|
+
upper = self.function_name(expression).upper()
|
|
234
234
|
|
|
235
235
|
dquote_escaping = upper in DQUOTES_ESCAPING_JSON_FUNCTIONS
|
|
236
236
|
|
|
@@ -257,6 +257,7 @@ class BigQueryGenerator(generator.Generator):
|
|
|
257
257
|
RENAME_TABLE_WITH_DB = False
|
|
258
258
|
NVL2_SUPPORTED = False
|
|
259
259
|
UNNEST_WITH_ORDINALITY = False
|
|
260
|
+
CAST_TO_INT_ROUNDS = True
|
|
260
261
|
COLLATE_IS_FUNC = True
|
|
261
262
|
LIMIT_ONLY_LITERALS = True
|
|
262
263
|
SUPPORTS_TABLE_ALIAS_COLUMNS = False
|
|
@@ -335,6 +336,7 @@ class BigQueryGenerator(generator.Generator):
|
|
|
335
336
|
exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
|
|
336
337
|
exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
|
|
337
338
|
exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"),
|
|
339
|
+
exp.Filter: no_filter_sql,
|
|
338
340
|
exp.FromTimeZone: lambda self, e: self.func(
|
|
339
341
|
"DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
|
|
340
342
|
),
|
|
@@ -164,6 +164,7 @@ def _json_cast_sql(self: ClickHouseGenerator, expression: exp.JSONCast) -> str:
|
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
class ClickHouseGenerator(generator.Generator):
|
|
167
|
+
BYTE_STRING_FUNCTION = "unhex"
|
|
167
168
|
SELECT_KINDS: tuple[str, ...] = ()
|
|
168
169
|
TRY_SUPPORTED = False
|
|
169
170
|
SUPPORTS_UESCAPE = False
|
|
@@ -294,6 +295,9 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
294
295
|
exp.ArgMax: arg_max_or_min_no_count("argMax"),
|
|
295
296
|
exp.ArgMin: arg_max_or_min_no_count("argMin"),
|
|
296
297
|
exp.Array: inline_array_sql,
|
|
298
|
+
exp.BitwiseAndAgg: rename_func("groupBitAnd"),
|
|
299
|
+
exp.BitwiseOrAgg: rename_func("groupBitOr"),
|
|
300
|
+
exp.BitwiseXorAgg: rename_func("groupBitXor"),
|
|
297
301
|
exp.CityHash64: rename_func("cityHash64"),
|
|
298
302
|
exp.CastToStrType: rename_func("CAST"),
|
|
299
303
|
exp.CurrentDatabase: rename_func("CURRENT_DATABASE"),
|
|
@@ -312,9 +316,13 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
312
316
|
exp.DateDiff: _datetime_delta_sql("DATE_DIFF"),
|
|
313
317
|
exp.DateStrToDate: rename_func("toDate"),
|
|
314
318
|
exp.DateSub: _datetime_delta_sql("DATE_SUB"),
|
|
319
|
+
exp.DayOfMonth: rename_func("toDayOfMonth"),
|
|
320
|
+
exp.DayOfWeekIso: rename_func("toDayOfWeek"),
|
|
321
|
+
exp.DayOfYear: rename_func("toDayOfYear"),
|
|
315
322
|
exp.Explode: rename_func("arrayJoin"),
|
|
316
323
|
exp.FarmFingerprint: rename_func("farmFingerprint64"),
|
|
317
324
|
exp.Final: lambda self, e: f"{self.sql(e, 'this')} FINAL",
|
|
325
|
+
exp.IsInf: rename_func("isInfinite"),
|
|
318
326
|
exp.IsNan: rename_func("isNaN"),
|
|
319
327
|
exp.JarowinklerSimilarity: jarowinkler_similarity("jaroWinklerSimilarity"),
|
|
320
328
|
exp.JSONCast: _json_cast_sql,
|
|
@@ -371,6 +379,8 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
371
379
|
exp.Trim: lambda self, e: trim_sql(self, e, default_trim_type="BOTH"),
|
|
372
380
|
exp.Variance: rename_func("varSamp"),
|
|
373
381
|
exp.VariancePop: rename_func("varPop"),
|
|
382
|
+
exp.WeekOfYear: rename_func("toISOWeek"),
|
|
383
|
+
exp.YearOfWeekIso: rename_func("toISOYear"),
|
|
374
384
|
exp.SchemaCommentProperty: lambda self, e: self.naked_property(e),
|
|
375
385
|
exp.Stddev: rename_func("stddevSamp"),
|
|
376
386
|
exp.Chr: rename_func("CHAR"),
|
|
@@ -421,6 +431,16 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
421
431
|
exp.DType.MULTIPOLYGON,
|
|
422
432
|
}
|
|
423
433
|
|
|
434
|
+
@unsupported_args("json_scope")
|
|
435
|
+
def contains_sql(self, expression: exp.Contains) -> str:
|
|
436
|
+
# ClickHouse has no CONTAINS; the comparison needs parentheses inside another operator
|
|
437
|
+
result = exp.StrPosition(this=expression.this, substr=expression.expression) > 0
|
|
438
|
+
if isinstance(expression.parent, exp.Binary) and not isinstance(
|
|
439
|
+
expression.parent, exp.Connector
|
|
440
|
+
):
|
|
441
|
+
return self.sql(exp.paren(result, copy=False))
|
|
442
|
+
return self.sql(result)
|
|
443
|
+
|
|
424
444
|
def groupconcat_sql(self, expression: exp.GroupConcat) -> str:
|
|
425
445
|
this = expression.this
|
|
426
446
|
separator = expression.args.get("separator")
|
|
@@ -42,6 +42,7 @@ class DorisGenerator(MySQLGenerator):
|
|
|
42
42
|
exp.UniqueKeyProperty: exp.Properties.Location.POST_SCHEMA,
|
|
43
43
|
exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
|
|
44
44
|
exp.BuildProperty: exp.Properties.Location.POST_SCHEMA,
|
|
45
|
+
exp.Property: exp.Properties.Location.POST_WITH,
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
CAST_MAPPING: t.ClassVar[dict[exp.DType, str]] = {}
|
|
@@ -25,10 +25,12 @@ def _str_to_date(self: DrillGenerator, expression: exp.StrToDate) -> str:
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class DrillGenerator(generator.Generator):
|
|
28
|
+
BYTE_STRING_FUNCTION = "UNHEX"
|
|
28
29
|
SELECT_KINDS: tuple[str, ...] = ()
|
|
29
30
|
TRY_SUPPORTED = False
|
|
30
31
|
SUPPORTS_UESCAPE = False
|
|
31
32
|
SUPPORTS_DECODE_CASE = False
|
|
33
|
+
CAST_TO_INT_ROUNDS = True
|
|
32
34
|
SUPPORTS_LIKE_QUANTIFIERS = False
|
|
33
35
|
|
|
34
36
|
AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS
|
|
@@ -104,6 +106,11 @@ class DrillGenerator(generator.Generator):
|
|
|
104
106
|
),
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
def bytestring_sql(self, expression: exp.ByteString) -> str:
|
|
110
|
+
if expression.args.get("is_bytes"):
|
|
111
|
+
return super().bytestring_sql(expression)
|
|
112
|
+
return self.sql(exp.Literal.string(expression.this))
|
|
113
|
+
|
|
107
114
|
def ilike_sql(self, expression: exp.ILike) -> str:
|
|
108
115
|
if isinstance(expression.expression, (exp.All, exp.Any)):
|
|
109
116
|
return super().ilike_sql(expression)
|