sqlglot 27.20.0__py3-none-any.whl → 27.22.0__py3-none-any.whl
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.
Potentially problematic release.
This version of sqlglot might be problematic. Click here for more details.
- sqlglot/_version.py +2 -2
- sqlglot/dialects/bigquery.py +2 -0
- sqlglot/dialects/dialect.py +11 -2
- sqlglot/dialects/duckdb.py +3 -4
- sqlglot/dialects/hive.py +66 -1
- sqlglot/dialects/oracle.py +0 -1
- sqlglot/dialects/presto.py +0 -1
- sqlglot/dialects/risingwave.py +14 -0
- sqlglot/dialects/snowflake.py +85 -6
- sqlglot/dialects/spark.py +0 -1
- sqlglot/dialects/spark2.py +17 -0
- sqlglot/dialects/tsql.py +11 -0
- sqlglot/expressions.py +56 -4
- sqlglot/generator.py +12 -3
- sqlglot/optimizer/canonicalize.py +1 -1
- sqlglot/optimizer/merge_subqueries.py +2 -0
- sqlglot/optimizer/optimize_joins.py +38 -4
- sqlglot/parser.py +63 -48
- sqlglot/tokens.py +5 -1
- sqlglot/transforms.py +0 -33
- {sqlglot-27.20.0.dist-info → sqlglot-27.22.0.dist-info}/METADATA +2 -2
- {sqlglot-27.20.0.dist-info → sqlglot-27.22.0.dist-info}/RECORD +25 -25
- {sqlglot-27.20.0.dist-info → sqlglot-27.22.0.dist-info}/WHEEL +0 -0
- {sqlglot-27.20.0.dist-info → sqlglot-27.22.0.dist-info}/licenses/LICENSE +0 -0
- {sqlglot-27.20.0.dist-info → sqlglot-27.22.0.dist-info}/top_level.txt +0 -0
sqlglot/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '27.
|
|
32
|
-
__version_tuple__ = version_tuple = (27,
|
|
31
|
+
__version__ = version = '27.22.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (27, 22, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
sqlglot/dialects/bigquery.py
CHANGED
|
@@ -867,6 +867,8 @@ class BigQuery(Dialect):
|
|
|
867
867
|
"FROM_HEX": exp.Unhex.from_arg_list,
|
|
868
868
|
"WEEK": lambda args: exp.WeekStart(this=exp.var(seq_get(args, 0))),
|
|
869
869
|
}
|
|
870
|
+
# Remove SEARCH to avoid parameter routing issues - let it fall back to Anonymous function
|
|
871
|
+
FUNCTIONS.pop("SEARCH")
|
|
870
872
|
|
|
871
873
|
FUNCTION_PARSERS = {
|
|
872
874
|
**parser.Parser.FUNCTION_PARSERS,
|
sqlglot/dialects/dialect.py
CHANGED
|
@@ -525,6 +525,13 @@ class Dialect(metaclass=_Dialect):
|
|
|
525
525
|
equivalent of CREATE SCHEMA is CREATE DATABASE.
|
|
526
526
|
"""
|
|
527
527
|
|
|
528
|
+
ALTER_TABLE_SUPPORTS_CASCADE = False
|
|
529
|
+
"""
|
|
530
|
+
Hive by default does not update the schema of existing partitions when a column is changed.
|
|
531
|
+
the CASCADE clause is used to indicate that the change should be propagated to all existing partitions.
|
|
532
|
+
the Spark dialect, while derived from Hive, does not support the CASCADE clause.
|
|
533
|
+
"""
|
|
534
|
+
|
|
528
535
|
# Whether ADD is present for each column added by ALTER TABLE
|
|
529
536
|
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
|
|
530
537
|
|
|
@@ -1715,7 +1722,7 @@ def unit_to_str(expression: exp.Expression, default: str = "DAY") -> t.Optional[
|
|
|
1715
1722
|
def unit_to_var(expression: exp.Expression, default: str = "DAY") -> t.Optional[exp.Expression]:
|
|
1716
1723
|
unit = expression.args.get("unit")
|
|
1717
1724
|
|
|
1718
|
-
if isinstance(unit, (exp.Var, exp.Placeholder, exp.WeekStart)):
|
|
1725
|
+
if isinstance(unit, (exp.Var, exp.Placeholder, exp.WeekStart, exp.Column)):
|
|
1719
1726
|
return unit
|
|
1720
1727
|
|
|
1721
1728
|
value = unit.name if unit else default
|
|
@@ -1736,7 +1743,9 @@ def map_date_part(
|
|
|
1736
1743
|
|
|
1737
1744
|
def map_date_part(part, dialect: DialectType = Dialect):
|
|
1738
1745
|
mapped = (
|
|
1739
|
-
Dialect.get_or_raise(dialect).DATE_PART_MAPPING.get(part.name.upper())
|
|
1746
|
+
Dialect.get_or_raise(dialect).DATE_PART_MAPPING.get(part.name.upper())
|
|
1747
|
+
if part and not (isinstance(part, exp.Column) and len(part.parts) != 1)
|
|
1748
|
+
else None
|
|
1740
1749
|
)
|
|
1741
1750
|
if mapped:
|
|
1742
1751
|
return exp.Literal.string(mapped) if part.is_string else exp.var(mapped)
|
sqlglot/dialects/duckdb.py
CHANGED
|
@@ -311,6 +311,7 @@ class DuckDB(Dialect):
|
|
|
311
311
|
"PIVOT_WIDER": TokenType.PIVOT,
|
|
312
312
|
"POSITIONAL": TokenType.POSITIONAL,
|
|
313
313
|
"RESET": TokenType.COMMAND,
|
|
314
|
+
"ROW": TokenType.STRUCT,
|
|
314
315
|
"SIGNED": TokenType.INT,
|
|
315
316
|
"STRING": TokenType.TEXT,
|
|
316
317
|
"SUMMARIZE": TokenType.SUMMARIZE,
|
|
@@ -337,16 +338,14 @@ class DuckDB(Dialect):
|
|
|
337
338
|
class Parser(parser.Parser):
|
|
338
339
|
MAP_KEYS_ARE_ARBITRARY_EXPRESSIONS = True
|
|
339
340
|
|
|
340
|
-
BITWISE =
|
|
341
|
-
**parser.Parser.BITWISE,
|
|
342
|
-
TokenType.TILDA: exp.RegexpLike,
|
|
343
|
-
}
|
|
341
|
+
BITWISE = parser.Parser.BITWISE.copy()
|
|
344
342
|
BITWISE.pop(TokenType.CARET)
|
|
345
343
|
|
|
346
344
|
RANGE_PARSERS = {
|
|
347
345
|
**parser.Parser.RANGE_PARSERS,
|
|
348
346
|
TokenType.DAMP: binary_range_parser(exp.ArrayOverlaps),
|
|
349
347
|
TokenType.CARET_AT: binary_range_parser(exp.StartsWith),
|
|
348
|
+
TokenType.TILDA: binary_range_parser(exp.RegexpFullMatch),
|
|
350
349
|
}
|
|
351
350
|
|
|
352
351
|
EXPONENT = {
|
sqlglot/dialects/hive.py
CHANGED
|
@@ -211,6 +211,7 @@ class Hive(Dialect):
|
|
|
211
211
|
SAFE_DIVISION = True
|
|
212
212
|
ARRAY_AGG_INCLUDES_NULLS = None
|
|
213
213
|
REGEXP_EXTRACT_DEFAULT_GROUP = 1
|
|
214
|
+
ALTER_TABLE_SUPPORTS_CASCADE = True
|
|
214
215
|
|
|
215
216
|
# https://spark.apache.org/docs/latest/sql-ref-identifier.html#description
|
|
216
217
|
NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
|
|
@@ -310,6 +311,10 @@ class Hive(Dialect):
|
|
|
310
311
|
VALUES_FOLLOWED_BY_PAREN = False
|
|
311
312
|
JOINS_HAVE_EQUAL_PRECEDENCE = True
|
|
312
313
|
ADD_JOIN_ON_TRUE = True
|
|
314
|
+
ALTER_TABLE_PARTITIONS = True
|
|
315
|
+
|
|
316
|
+
CHANGE_COLUMN_ALTER_SYNTAX = False
|
|
317
|
+
# Whether the dialect supports using ALTER COLUMN syntax with CHANGE COLUMN.
|
|
313
318
|
|
|
314
319
|
FUNCTIONS = {
|
|
315
320
|
**parser.Parser.FUNCTIONS,
|
|
@@ -378,6 +383,11 @@ class Hive(Dialect):
|
|
|
378
383
|
),
|
|
379
384
|
}
|
|
380
385
|
|
|
386
|
+
ALTER_PARSERS = {
|
|
387
|
+
**parser.Parser.ALTER_PARSERS,
|
|
388
|
+
"CHANGE": lambda self: self._parse_alter_table_change(),
|
|
389
|
+
}
|
|
390
|
+
|
|
381
391
|
def _parse_transform(self) -> t.Optional[exp.Transform | exp.QueryTransform]:
|
|
382
392
|
if not self._match(TokenType.L_PAREN, advance=False):
|
|
383
393
|
self._retreat(self._index - 1)
|
|
@@ -451,6 +461,35 @@ class Hive(Dialect):
|
|
|
451
461
|
|
|
452
462
|
return this
|
|
453
463
|
|
|
464
|
+
def _parse_alter_table_change(self) -> t.Optional[exp.Expression]:
|
|
465
|
+
self._match(TokenType.COLUMN)
|
|
466
|
+
this = self._parse_field(any_token=True)
|
|
467
|
+
|
|
468
|
+
if self.CHANGE_COLUMN_ALTER_SYNTAX and self._match_text_seq("TYPE"):
|
|
469
|
+
return self.expression(
|
|
470
|
+
exp.AlterColumn,
|
|
471
|
+
this=this,
|
|
472
|
+
dtype=self._parse_types(schema=True),
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
column_new = self._parse_field(any_token=True)
|
|
476
|
+
dtype = self._parse_types(schema=True)
|
|
477
|
+
|
|
478
|
+
comment = self._match(TokenType.COMMENT) and self._parse_string()
|
|
479
|
+
|
|
480
|
+
if not this or not column_new or not dtype:
|
|
481
|
+
self.raise_error(
|
|
482
|
+
"Expected 'CHANGE COLUMN' to be followed by 'column_name' 'column_name' 'data_type'"
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
return self.expression(
|
|
486
|
+
exp.AlterColumn,
|
|
487
|
+
this=this,
|
|
488
|
+
rename_to=column_new,
|
|
489
|
+
dtype=dtype,
|
|
490
|
+
comment=comment,
|
|
491
|
+
)
|
|
492
|
+
|
|
454
493
|
def _parse_partition_and_order(
|
|
455
494
|
self,
|
|
456
495
|
) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
|
|
@@ -500,6 +539,7 @@ class Hive(Dialect):
|
|
|
500
539
|
PAD_FILL_PATTERN_IS_REQUIRED = True
|
|
501
540
|
SUPPORTS_MEDIAN = False
|
|
502
541
|
ARRAY_SIZE_NAME = "SIZE"
|
|
542
|
+
ALTER_SET_TYPE = ""
|
|
503
543
|
|
|
504
544
|
EXPRESSIONS_WITHOUT_NESTED_CTES = {
|
|
505
545
|
exp.Insert,
|
|
@@ -531,7 +571,6 @@ class Hive(Dialect):
|
|
|
531
571
|
|
|
532
572
|
TRANSFORMS = {
|
|
533
573
|
**generator.Generator.TRANSFORMS,
|
|
534
|
-
exp.Group: transforms.preprocess([transforms.unalias_group]),
|
|
535
574
|
exp.Property: property_sql,
|
|
536
575
|
exp.AnyValue: rename_func("FIRST"),
|
|
537
576
|
exp.ApproxDistinct: approx_count_distinct_sql,
|
|
@@ -758,6 +797,32 @@ class Hive(Dialect):
|
|
|
758
797
|
),
|
|
759
798
|
)
|
|
760
799
|
|
|
800
|
+
def altercolumn_sql(self, expression: exp.AlterColumn) -> str:
|
|
801
|
+
this = self.sql(expression, "this")
|
|
802
|
+
new_name = self.sql(expression, "rename_to") or this
|
|
803
|
+
dtype = self.sql(expression, "dtype")
|
|
804
|
+
comment = (
|
|
805
|
+
f" COMMENT {self.sql(expression, 'comment')}"
|
|
806
|
+
if self.sql(expression, "comment")
|
|
807
|
+
else ""
|
|
808
|
+
)
|
|
809
|
+
default = self.sql(expression, "default")
|
|
810
|
+
visible = expression.args.get("visible")
|
|
811
|
+
allow_null = expression.args.get("allow_null")
|
|
812
|
+
drop = expression.args.get("drop")
|
|
813
|
+
|
|
814
|
+
if any([default, drop, visible, allow_null, drop]):
|
|
815
|
+
self.unsupported("Unsupported CHANGE COLUMN syntax")
|
|
816
|
+
|
|
817
|
+
if not dtype:
|
|
818
|
+
self.unsupported("CHANGE COLUMN without a type is not supported")
|
|
819
|
+
|
|
820
|
+
return f"CHANGE COLUMN {this} {new_name} {dtype}{comment}"
|
|
821
|
+
|
|
822
|
+
def renamecolumn_sql(self, expression: exp.RenameColumn) -> str:
|
|
823
|
+
self.unsupported("Cannot rename columns without data type defined in Hive")
|
|
824
|
+
return ""
|
|
825
|
+
|
|
761
826
|
def alterset_sql(self, expression: exp.AlterSet) -> str:
|
|
762
827
|
exprs = self.expressions(expression, flat=True)
|
|
763
828
|
exprs = f" {exprs}" if exprs else ""
|
sqlglot/dialects/oracle.py
CHANGED
|
@@ -307,7 +307,6 @@ class Oracle(Dialect):
|
|
|
307
307
|
),
|
|
308
308
|
exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, e.unit),
|
|
309
309
|
exp.EuclideanDistance: rename_func("L2_DISTANCE"),
|
|
310
|
-
exp.Group: transforms.preprocess([transforms.unalias_group]),
|
|
311
310
|
exp.ILike: no_ilike_sql,
|
|
312
311
|
exp.LogicalOr: rename_func("MAX"),
|
|
313
312
|
exp.LogicalAnd: rename_func("MIN"),
|
sqlglot/dialects/presto.py
CHANGED
|
@@ -475,7 +475,6 @@ class Presto(Dialect):
|
|
|
475
475
|
e: f"WITH_TIMEZONE({self.sql(e, 'this')}, {self.sql(e, 'zone')}) AT TIME ZONE 'UTC'",
|
|
476
476
|
exp.GenerateSeries: sequence_sql,
|
|
477
477
|
exp.GenerateDateArray: sequence_sql,
|
|
478
|
-
exp.Group: transforms.preprocess([transforms.unalias_group]),
|
|
479
478
|
exp.If: if_sql(),
|
|
480
479
|
exp.ILike: no_ilike_sql,
|
|
481
480
|
exp.Initcap: _initcap_sql,
|
sqlglot/dialects/risingwave.py
CHANGED
|
@@ -25,6 +25,20 @@ class RisingWave(Postgres):
|
|
|
25
25
|
"KEY": lambda self: self._parse_encode_property(key=True),
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
CONSTRAINT_PARSERS = {
|
|
29
|
+
**Postgres.Parser.CONSTRAINT_PARSERS,
|
|
30
|
+
"WATERMARK": lambda self: self.expression(
|
|
31
|
+
exp.WatermarkColumnConstraint,
|
|
32
|
+
this=self._match(TokenType.FOR) and self._parse_column(),
|
|
33
|
+
expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
|
|
34
|
+
),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
SCHEMA_UNNAMED_CONSTRAINTS = {
|
|
38
|
+
*Postgres.Parser.SCHEMA_UNNAMED_CONSTRAINTS,
|
|
39
|
+
"WATERMARK",
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
|
|
29
43
|
# There is no hint in risingwave.
|
|
30
44
|
# Do nothing here to avoid WITH keywords conflict in CREATE SINK statement.
|
sqlglot/dialects/snowflake.py
CHANGED
|
@@ -41,7 +41,18 @@ if t.TYPE_CHECKING:
|
|
|
41
41
|
from sqlglot._typing import E, B
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
def _build_strtok(args: t.List) -> exp.SplitPart:
|
|
45
|
+
# Add default delimiter (space) if missing - per Snowflake docs
|
|
46
|
+
if len(args) == 1:
|
|
47
|
+
args.append(exp.Literal.string(" "))
|
|
48
|
+
|
|
49
|
+
# Add default part_index (1) if missing
|
|
50
|
+
if len(args) == 2:
|
|
51
|
+
args.append(exp.Literal.number(1))
|
|
52
|
+
|
|
53
|
+
return exp.SplitPart.from_arg_list(args)
|
|
54
|
+
|
|
55
|
+
|
|
45
56
|
def _build_datetime(
|
|
46
57
|
name: str, kind: exp.DataType.Type, safe: bool = False
|
|
47
58
|
) -> t.Callable[[t.List], exp.Func]:
|
|
@@ -137,12 +148,35 @@ def _build_if_from_div0(args: t.List) -> exp.If:
|
|
|
137
148
|
return exp.If(this=cond, true=true, false=false)
|
|
138
149
|
|
|
139
150
|
|
|
151
|
+
# https://docs.snowflake.com/en/sql-reference/functions/div0null
|
|
152
|
+
def _build_if_from_div0null(args: t.List) -> exp.If:
|
|
153
|
+
lhs = exp._wrap(seq_get(args, 0), exp.Binary)
|
|
154
|
+
rhs = exp._wrap(seq_get(args, 1), exp.Binary)
|
|
155
|
+
|
|
156
|
+
# Returns 0 when divisor is 0 OR NULL
|
|
157
|
+
cond = exp.EQ(this=rhs, expression=exp.Literal.number(0)).or_(
|
|
158
|
+
exp.Is(this=rhs, expression=exp.null())
|
|
159
|
+
)
|
|
160
|
+
true = exp.Literal.number(0)
|
|
161
|
+
false = exp.Div(this=lhs, expression=rhs)
|
|
162
|
+
return exp.If(this=cond, true=true, false=false)
|
|
163
|
+
|
|
164
|
+
|
|
140
165
|
# https://docs.snowflake.com/en/sql-reference/functions/zeroifnull
|
|
141
166
|
def _build_if_from_zeroifnull(args: t.List) -> exp.If:
|
|
142
167
|
cond = exp.Is(this=seq_get(args, 0), expression=exp.Null())
|
|
143
168
|
return exp.If(this=cond, true=exp.Literal.number(0), false=seq_get(args, 0))
|
|
144
169
|
|
|
145
170
|
|
|
171
|
+
def _build_search(args: t.List) -> exp.Search:
|
|
172
|
+
kwargs = {
|
|
173
|
+
"this": seq_get(args, 0),
|
|
174
|
+
"expression": seq_get(args, 1),
|
|
175
|
+
**{arg.name.lower(): arg for arg in args[2:] if isinstance(arg, exp.Kwarg)},
|
|
176
|
+
}
|
|
177
|
+
return exp.Search(**kwargs)
|
|
178
|
+
|
|
179
|
+
|
|
146
180
|
# https://docs.snowflake.com/en/sql-reference/functions/zeroifnull
|
|
147
181
|
def _build_if_from_nullifzero(args: t.List) -> exp.If:
|
|
148
182
|
cond = exp.EQ(this=seq_get(args, 0), expression=exp.Literal.number(0))
|
|
@@ -529,6 +563,16 @@ class Snowflake(Dialect):
|
|
|
529
563
|
|
|
530
564
|
TYPE_TO_EXPRESSIONS = {
|
|
531
565
|
**Dialect.TYPE_TO_EXPRESSIONS,
|
|
566
|
+
exp.DataType.Type.DOUBLE: {
|
|
567
|
+
*Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.DOUBLE],
|
|
568
|
+
exp.Cos,
|
|
569
|
+
exp.Cosh,
|
|
570
|
+
exp.Cot,
|
|
571
|
+
exp.Degrees,
|
|
572
|
+
exp.Exp,
|
|
573
|
+
exp.Sin,
|
|
574
|
+
exp.Tan,
|
|
575
|
+
},
|
|
532
576
|
exp.DataType.Type.INT: {
|
|
533
577
|
*Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.INT],
|
|
534
578
|
exp.Ascii,
|
|
@@ -539,6 +583,7 @@ class Snowflake(Dialect):
|
|
|
539
583
|
exp.Levenshtein,
|
|
540
584
|
exp.JarowinklerSimilarity,
|
|
541
585
|
exp.StrPosition,
|
|
586
|
+
exp.Unicode,
|
|
542
587
|
},
|
|
543
588
|
exp.DataType.Type.VARCHAR: {
|
|
544
589
|
*Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.VARCHAR],
|
|
@@ -564,8 +609,10 @@ class Snowflake(Dialect):
|
|
|
564
609
|
exp.SHA,
|
|
565
610
|
exp.SHA2,
|
|
566
611
|
exp.Soundex,
|
|
612
|
+
exp.SoundexP123,
|
|
567
613
|
exp.Space,
|
|
568
614
|
exp.SplitPart,
|
|
615
|
+
exp.Translate,
|
|
569
616
|
exp.Uuid,
|
|
570
617
|
},
|
|
571
618
|
exp.DataType.Type.BINARY: {
|
|
@@ -587,6 +634,8 @@ class Snowflake(Dialect):
|
|
|
587
634
|
},
|
|
588
635
|
exp.DataType.Type.ARRAY: {
|
|
589
636
|
exp.Split,
|
|
637
|
+
exp.RegexpExtractAll,
|
|
638
|
+
exp.StringToArray,
|
|
590
639
|
},
|
|
591
640
|
exp.DataType.Type.OBJECT: {
|
|
592
641
|
exp.ParseUrl,
|
|
@@ -595,6 +644,10 @@ class Snowflake(Dialect):
|
|
|
595
644
|
exp.DataType.Type.DECIMAL: {
|
|
596
645
|
exp.RegexpCount,
|
|
597
646
|
},
|
|
647
|
+
exp.DataType.Type.BOOLEAN: {
|
|
648
|
+
*Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.BOOLEAN],
|
|
649
|
+
exp.Search,
|
|
650
|
+
},
|
|
598
651
|
}
|
|
599
652
|
|
|
600
653
|
ANNOTATORS = {
|
|
@@ -612,13 +665,20 @@ class Snowflake(Dialect):
|
|
|
612
665
|
exp.Right,
|
|
613
666
|
exp.Stuff,
|
|
614
667
|
exp.Substring,
|
|
668
|
+
exp.Round,
|
|
669
|
+
)
|
|
670
|
+
},
|
|
671
|
+
**{
|
|
672
|
+
expr_type: lambda self, e: self._annotate_with_type(
|
|
673
|
+
e, exp.DataType.build("NUMBER", dialect="snowflake")
|
|
674
|
+
)
|
|
675
|
+
for expr_type in (
|
|
676
|
+
exp.RegexpCount,
|
|
677
|
+
exp.RegexpInstr,
|
|
615
678
|
)
|
|
616
679
|
},
|
|
617
680
|
exp.ConcatWs: lambda self, e: self._annotate_by_args(e, "expressions"),
|
|
618
681
|
exp.Reverse: _annotate_reverse,
|
|
619
|
-
exp.RegexpCount: lambda self, e: self._annotate_with_type(
|
|
620
|
-
e, exp.DataType.build("NUMBER", dialect="snowflake")
|
|
621
|
-
),
|
|
622
682
|
}
|
|
623
683
|
|
|
624
684
|
TIME_MAPPING = {
|
|
@@ -691,7 +751,7 @@ class Snowflake(Dialect):
|
|
|
691
751
|
"APPROX_PERCENTILE": exp.ApproxQuantile.from_arg_list,
|
|
692
752
|
"ARRAY_CONSTRUCT": lambda args: exp.Array(expressions=args),
|
|
693
753
|
"ARRAY_CONTAINS": lambda args: exp.ArrayContains(
|
|
694
|
-
this=seq_get(args, 1), expression=seq_get(args, 0)
|
|
754
|
+
this=seq_get(args, 1), expression=seq_get(args, 0), ensure_variant=False
|
|
695
755
|
),
|
|
696
756
|
"ARRAY_GENERATE_RANGE": lambda args: exp.GenerateSeries(
|
|
697
757
|
# ARRAY_GENERATE_RANGE has an exlusive end; we normalize it to be inclusive
|
|
@@ -727,6 +787,7 @@ class Snowflake(Dialect):
|
|
|
727
787
|
"DATEDIFF": _build_datediff,
|
|
728
788
|
"DAYOFWEEKISO": exp.DayOfWeekIso.from_arg_list,
|
|
729
789
|
"DIV0": _build_if_from_div0,
|
|
790
|
+
"DIV0NULL": _build_if_from_div0null,
|
|
730
791
|
"EDITDISTANCE": lambda args: exp.Levenshtein(
|
|
731
792
|
this=seq_get(args, 0), expression=seq_get(args, 1), max_dist=seq_get(args, 2)
|
|
732
793
|
),
|
|
@@ -765,6 +826,7 @@ class Snowflake(Dialect):
|
|
|
765
826
|
"SHA2_BINARY": exp.SHA2Digest.from_arg_list,
|
|
766
827
|
"SHA2_HEX": exp.SHA2.from_arg_list,
|
|
767
828
|
"SQUARE": lambda args: exp.Pow(this=seq_get(args, 0), expression=exp.Literal.number(2)),
|
|
829
|
+
"STRTOK": _build_strtok,
|
|
768
830
|
"TABLE": lambda args: exp.TableFromRows(this=seq_get(args, 0)),
|
|
769
831
|
"TIMEADD": _build_date_time_add(exp.TimeAdd),
|
|
770
832
|
"TIMEDIFF": _build_datediff,
|
|
@@ -799,6 +861,7 @@ class Snowflake(Dialect):
|
|
|
799
861
|
"ZEROIFNULL": _build_if_from_zeroifnull,
|
|
800
862
|
"LIKE": _build_like(exp.Like),
|
|
801
863
|
"ILIKE": _build_like(exp.ILike),
|
|
864
|
+
"SEARCH": _build_search,
|
|
802
865
|
}
|
|
803
866
|
FUNCTIONS.pop("PREDICT")
|
|
804
867
|
|
|
@@ -1364,7 +1427,13 @@ class Snowflake(Dialect):
|
|
|
1364
1427
|
exp.ArgMax: rename_func("MAX_BY"),
|
|
1365
1428
|
exp.ArgMin: rename_func("MIN_BY"),
|
|
1366
1429
|
exp.ArrayConcat: lambda self, e: self.arrayconcat_sql(e, name="ARRAY_CAT"),
|
|
1367
|
-
exp.ArrayContains: lambda self, e: self.func(
|
|
1430
|
+
exp.ArrayContains: lambda self, e: self.func(
|
|
1431
|
+
"ARRAY_CONTAINS",
|
|
1432
|
+
e.expression
|
|
1433
|
+
if e.args.get("ensure_variant") is False
|
|
1434
|
+
else exp.cast(e.expression, exp.DataType.Type.VARIANT, copy=False),
|
|
1435
|
+
e.this,
|
|
1436
|
+
),
|
|
1368
1437
|
exp.ArrayIntersect: rename_func("ARRAY_INTERSECTION"),
|
|
1369
1438
|
exp.AtTimeZone: lambda self, e: self.func(
|
|
1370
1439
|
"CONVERT_TIMEZONE", e.args.get("zone"), e.this
|
|
@@ -1894,3 +1963,13 @@ class Snowflake(Dialect):
|
|
|
1894
1963
|
return self.func("TO_CHAR", expression.expressions[0])
|
|
1895
1964
|
|
|
1896
1965
|
return self.function_fallback_sql(expression)
|
|
1966
|
+
|
|
1967
|
+
def splitpart_sql(self, expression: exp.SplitPart) -> str:
|
|
1968
|
+
# Set part_index to 1 if missing
|
|
1969
|
+
if not expression.args.get("delimiter"):
|
|
1970
|
+
expression.set("delimiter", exp.Literal.string(" "))
|
|
1971
|
+
|
|
1972
|
+
if not expression.args.get("part_index"):
|
|
1973
|
+
expression.set("part_index", exp.Literal.number(1))
|
|
1974
|
+
|
|
1975
|
+
return rename_func("SPLIT_PART")(self, expression)
|
sqlglot/dialects/spark.py
CHANGED
sqlglot/dialects/spark2.py
CHANGED
|
@@ -151,6 +151,8 @@ def _annotate_by_similar_args(
|
|
|
151
151
|
|
|
152
152
|
|
|
153
153
|
class Spark2(Hive):
|
|
154
|
+
ALTER_TABLE_SUPPORTS_CASCADE = False
|
|
155
|
+
|
|
154
156
|
ANNOTATORS = {
|
|
155
157
|
**Hive.ANNOTATORS,
|
|
156
158
|
exp.Substring: lambda self, e: self._annotate_by_args(e, "this"),
|
|
@@ -172,6 +174,7 @@ class Spark2(Hive):
|
|
|
172
174
|
|
|
173
175
|
class Parser(Hive.Parser):
|
|
174
176
|
TRIM_PATTERN_FIRST = True
|
|
177
|
+
CHANGE_COLUMN_ALTER_SYNTAX = True
|
|
175
178
|
|
|
176
179
|
FUNCTIONS = {
|
|
177
180
|
**Hive.Parser.FUNCTIONS,
|
|
@@ -248,6 +251,7 @@ class Spark2(Hive):
|
|
|
248
251
|
QUERY_HINTS = True
|
|
249
252
|
NVL2_SUPPORTED = True
|
|
250
253
|
CAN_IMPLEMENT_ARRAY_ANY = True
|
|
254
|
+
ALTER_SET_TYPE = "TYPE"
|
|
251
255
|
|
|
252
256
|
PROPERTIES_LOCATION = {
|
|
253
257
|
**Hive.Generator.PROPERTIES_LOCATION,
|
|
@@ -364,3 +368,16 @@ class Spark2(Hive):
|
|
|
364
368
|
return super().fileformatproperty_sql(expression)
|
|
365
369
|
|
|
366
370
|
return f"USING {expression.name.upper()}"
|
|
371
|
+
|
|
372
|
+
def altercolumn_sql(self, expression: exp.AlterColumn) -> str:
|
|
373
|
+
this = self.sql(expression, "this")
|
|
374
|
+
new_name = self.sql(expression, "rename_to") or this
|
|
375
|
+
comment = self.sql(expression, "comment")
|
|
376
|
+
if new_name == this:
|
|
377
|
+
if comment:
|
|
378
|
+
return f"ALTER COLUMN {this} COMMENT {comment}"
|
|
379
|
+
return super(Hive.Generator, self).altercolumn_sql(expression)
|
|
380
|
+
return f"RENAME COLUMN {this} TO {new_name}"
|
|
381
|
+
|
|
382
|
+
def renamecolumn_sql(self, expression: exp.RenameColumn) -> str:
|
|
383
|
+
return super(Hive.Generator, self).renamecolumn_sql(expression)
|
sqlglot/dialects/tsql.py
CHANGED
|
@@ -670,6 +670,12 @@ class TSQL(Dialect):
|
|
|
670
670
|
|
|
671
671
|
SET_OP_MODIFIERS = {"offset"}
|
|
672
672
|
|
|
673
|
+
ODBC_DATETIME_LITERALS = {
|
|
674
|
+
"d": exp.Date,
|
|
675
|
+
"t": exp.Time,
|
|
676
|
+
"ts": exp.Timestamp,
|
|
677
|
+
}
|
|
678
|
+
|
|
673
679
|
def _parse_alter_table_set(self) -> exp.AlterSet:
|
|
674
680
|
return self._parse_wrapped(super()._parse_alter_table_set)
|
|
675
681
|
|
|
@@ -902,6 +908,11 @@ class TSQL(Dialect):
|
|
|
902
908
|
|
|
903
909
|
return self.expression(exp.UniqueColumnConstraint, this=this)
|
|
904
910
|
|
|
911
|
+
def _parse_update(self) -> exp.Update:
|
|
912
|
+
expression = super()._parse_update()
|
|
913
|
+
expression.set("options", self._parse_options())
|
|
914
|
+
return expression
|
|
915
|
+
|
|
905
916
|
def _parse_partition(self) -> t.Optional[exp.Partition]:
|
|
906
917
|
if not self._match_text_seq("WITH", "(", "PARTITIONS"):
|
|
907
918
|
return None
|
sqlglot/expressions.py
CHANGED
|
@@ -1838,6 +1838,7 @@ class AlterColumn(Expression):
|
|
|
1838
1838
|
"comment": False,
|
|
1839
1839
|
"allow_null": False,
|
|
1840
1840
|
"visible": False,
|
|
1841
|
+
"rename_to": False,
|
|
1841
1842
|
}
|
|
1842
1843
|
|
|
1843
1844
|
|
|
@@ -3633,6 +3634,7 @@ class Update(DML):
|
|
|
3633
3634
|
"returning": False,
|
|
3634
3635
|
"order": False,
|
|
3635
3636
|
"limit": False,
|
|
3637
|
+
"options": False,
|
|
3636
3638
|
}
|
|
3637
3639
|
|
|
3638
3640
|
def table(
|
|
@@ -4956,6 +4958,7 @@ class Alter(Expression):
|
|
|
4956
4958
|
"cluster": False,
|
|
4957
4959
|
"not_valid": False,
|
|
4958
4960
|
"check": False,
|
|
4961
|
+
"cascade": False,
|
|
4959
4962
|
}
|
|
4960
4963
|
|
|
4961
4964
|
@property
|
|
@@ -5385,7 +5388,7 @@ class TimeUnit(Expression):
|
|
|
5385
5388
|
|
|
5386
5389
|
def __init__(self, **args):
|
|
5387
5390
|
unit = args.get("unit")
|
|
5388
|
-
if type(unit) in self.VAR_LIKE:
|
|
5391
|
+
if type(unit) in self.VAR_LIKE and not (isinstance(unit, Column) and len(unit.parts) != 1):
|
|
5389
5392
|
args["unit"] = Var(
|
|
5390
5393
|
this=(self.UNABBREVIATED_UNIT_NAME.get(unit.name) or unit.name).upper()
|
|
5391
5394
|
)
|
|
@@ -5525,6 +5528,10 @@ class Coth(Func):
|
|
|
5525
5528
|
pass
|
|
5526
5529
|
|
|
5527
5530
|
|
|
5531
|
+
class Cos(Func):
|
|
5532
|
+
pass
|
|
5533
|
+
|
|
5534
|
+
|
|
5528
5535
|
class Csc(Func):
|
|
5529
5536
|
pass
|
|
5530
5537
|
|
|
@@ -5549,6 +5556,18 @@ class Sinh(Func):
|
|
|
5549
5556
|
pass
|
|
5550
5557
|
|
|
5551
5558
|
|
|
5559
|
+
class Tan(Func):
|
|
5560
|
+
pass
|
|
5561
|
+
|
|
5562
|
+
|
|
5563
|
+
class Degrees(Func):
|
|
5564
|
+
pass
|
|
5565
|
+
|
|
5566
|
+
|
|
5567
|
+
class Cosh(Func):
|
|
5568
|
+
pass
|
|
5569
|
+
|
|
5570
|
+
|
|
5552
5571
|
class CosineDistance(Func):
|
|
5553
5572
|
arg_types = {"this": True, "expression": True}
|
|
5554
5573
|
|
|
@@ -5840,6 +5859,7 @@ class ArrayConstructCompact(Func):
|
|
|
5840
5859
|
|
|
5841
5860
|
|
|
5842
5861
|
class ArrayContains(Binary, Func):
|
|
5862
|
+
arg_types = {"this": True, "expression": True, "ensure_variant": False}
|
|
5843
5863
|
_sql_names = ["ARRAY_CONTAINS", "ARRAY_HAS"]
|
|
5844
5864
|
|
|
5845
5865
|
|
|
@@ -6172,7 +6192,9 @@ class DateTrunc(Func):
|
|
|
6172
6192
|
unabbreviate = args.pop("unabbreviate", True)
|
|
6173
6193
|
|
|
6174
6194
|
unit = args.get("unit")
|
|
6175
|
-
if isinstance(unit, TimeUnit.VAR_LIKE)
|
|
6195
|
+
if isinstance(unit, TimeUnit.VAR_LIKE) and not (
|
|
6196
|
+
isinstance(unit, Column) and len(unit.parts) != 1
|
|
6197
|
+
):
|
|
6176
6198
|
unit_name = unit.name.upper()
|
|
6177
6199
|
if unabbreviate and unit_name in TimeUnit.UNABBREVIATED_UNIT_NAME:
|
|
6178
6200
|
unit_name = TimeUnit.UNABBREVIATED_UNIT_NAME[unit_name]
|
|
@@ -6735,7 +6757,13 @@ class JSONExists(Func):
|
|
|
6735
6757
|
# https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/JSON_TABLE.html
|
|
6736
6758
|
# Note: parsing of JSON column definitions is currently incomplete.
|
|
6737
6759
|
class JSONColumnDef(Expression):
|
|
6738
|
-
arg_types = {
|
|
6760
|
+
arg_types = {
|
|
6761
|
+
"this": False,
|
|
6762
|
+
"kind": False,
|
|
6763
|
+
"path": False,
|
|
6764
|
+
"nested_schema": False,
|
|
6765
|
+
"ordinality": False,
|
|
6766
|
+
}
|
|
6739
6767
|
|
|
6740
6768
|
|
|
6741
6769
|
class JSONSchema(Expression):
|
|
@@ -7279,6 +7307,10 @@ class RegexpILike(Binary, Func):
|
|
|
7279
7307
|
arg_types = {"this": True, "expression": True, "flag": False}
|
|
7280
7308
|
|
|
7281
7309
|
|
|
7310
|
+
class RegexpFullMatch(Binary, Func):
|
|
7311
|
+
arg_types = {"this": True, "expression": True, "options": False}
|
|
7312
|
+
|
|
7313
|
+
|
|
7282
7314
|
class RegexpInstr(Func):
|
|
7283
7315
|
arg_types = {
|
|
7284
7316
|
"this": True,
|
|
@@ -7380,13 +7412,20 @@ class Soundex(Func):
|
|
|
7380
7412
|
pass
|
|
7381
7413
|
|
|
7382
7414
|
|
|
7415
|
+
# https://docs.snowflake.com/en/sql-reference/functions/soundex_p123
|
|
7416
|
+
class SoundexP123(Func):
|
|
7417
|
+
pass
|
|
7418
|
+
|
|
7419
|
+
|
|
7383
7420
|
class Split(Func):
|
|
7384
7421
|
arg_types = {"this": True, "expression": True, "limit": False}
|
|
7385
7422
|
|
|
7386
7423
|
|
|
7387
7424
|
# https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.split_part.html
|
|
7425
|
+
# https://docs.snowflake.com/en/sql-reference/functions/split_part
|
|
7426
|
+
# https://docs.snowflake.com/en/sql-reference/functions/strtok
|
|
7388
7427
|
class SplitPart(Func):
|
|
7389
|
-
arg_types = {"this": True, "delimiter":
|
|
7428
|
+
arg_types = {"this": True, "delimiter": False, "part_index": False}
|
|
7390
7429
|
|
|
7391
7430
|
|
|
7392
7431
|
# Start may be omitted in the case of postgres
|
|
@@ -7430,6 +7469,19 @@ class StrPosition(Func):
|
|
|
7430
7469
|
}
|
|
7431
7470
|
|
|
7432
7471
|
|
|
7472
|
+
# Snowflake: https://docs.snowflake.com/en/sql-reference/functions/search
|
|
7473
|
+
# BigQuery: https://cloud.google.com/bigquery/docs/reference/standard-sql/search_functions#search
|
|
7474
|
+
class Search(Func):
|
|
7475
|
+
arg_types = {
|
|
7476
|
+
"this": True, # data_to_search / search_data
|
|
7477
|
+
"expression": True, # search_query / search_string
|
|
7478
|
+
"json_scope": False, # BigQuery: JSON_VALUES | JSON_KEYS | JSON_KEYS_AND_VALUES
|
|
7479
|
+
"analyzer": False, # Both: analyzer / ANALYZER
|
|
7480
|
+
"analyzer_options": False, # BigQuery: analyzer_options_values
|
|
7481
|
+
"search_mode": False, # Snowflake: OR | AND
|
|
7482
|
+
}
|
|
7483
|
+
|
|
7484
|
+
|
|
7433
7485
|
class StrToDate(Func):
|
|
7434
7486
|
arg_types = {"this": True, "format": False, "safe": False}
|
|
7435
7487
|
|
sqlglot/generator.py
CHANGED
|
@@ -2200,7 +2200,9 @@ class Generator(metaclass=_Generator):
|
|
|
2200
2200
|
expression_sql = f"{from_sql}{where_sql}{returning}"
|
|
2201
2201
|
else:
|
|
2202
2202
|
expression_sql = f"{returning}{from_sql}{where_sql}"
|
|
2203
|
-
|
|
2203
|
+
options = self.expressions(expression, key="options")
|
|
2204
|
+
options = f" OPTION({options})" if options else ""
|
|
2205
|
+
sql = f"UPDATE {this} SET {set_sql}{expression_sql}{order}{limit}{options}"
|
|
2204
2206
|
return self.prepend_ctes(expression, sql)
|
|
2205
2207
|
|
|
2206
2208
|
def values_sql(self, expression: exp.Values, values_as_table: bool = True) -> str:
|
|
@@ -3216,7 +3218,9 @@ class Generator(metaclass=_Generator):
|
|
|
3216
3218
|
this = self.sql(expression, "this")
|
|
3217
3219
|
kind = self.sql(expression, "kind")
|
|
3218
3220
|
kind = f" {kind}" if kind else ""
|
|
3219
|
-
|
|
3221
|
+
|
|
3222
|
+
ordinality = " FOR ORDINALITY" if expression.args.get("ordinality") else ""
|
|
3223
|
+
return f"{this}{kind}{path}{ordinality}"
|
|
3220
3224
|
|
|
3221
3225
|
def jsonschema_sql(self, expression: exp.JSONSchema) -> str:
|
|
3222
3226
|
return self.func("COLUMNS", *expression.expressions)
|
|
@@ -3621,10 +3625,15 @@ class Generator(metaclass=_Generator):
|
|
|
3621
3625
|
kind = self.sql(expression, "kind")
|
|
3622
3626
|
not_valid = " NOT VALID" if expression.args.get("not_valid") else ""
|
|
3623
3627
|
check = " WITH CHECK" if expression.args.get("check") else ""
|
|
3628
|
+
cascade = (
|
|
3629
|
+
" CASCADE"
|
|
3630
|
+
if expression.args.get("cascade") and self.dialect.ALTER_TABLE_SUPPORTS_CASCADE
|
|
3631
|
+
else ""
|
|
3632
|
+
)
|
|
3624
3633
|
this = self.sql(expression, "this")
|
|
3625
3634
|
this = f" {this}" if this else ""
|
|
3626
3635
|
|
|
3627
|
-
return f"ALTER {kind}{exists}{only}{this}{on_cluster}{check}{self.sep()}{actions_sql}{not_valid}{options}"
|
|
3636
|
+
return f"ALTER {kind}{exists}{only}{this}{on_cluster}{check}{self.sep()}{actions_sql}{not_valid}{options}{cascade}"
|
|
3628
3637
|
|
|
3629
3638
|
def altersession_sql(self, expression: exp.AlterSession) -> str:
|
|
3630
3639
|
items_sql = self.expressions(expression, flat=True)
|
|
@@ -77,7 +77,7 @@ def coerce_type(node: exp.Expression, promote_to_inferred_datetime_type: bool) -
|
|
|
77
77
|
_coerce_date(node.left, node.right, promote_to_inferred_datetime_type)
|
|
78
78
|
elif isinstance(node, exp.Between):
|
|
79
79
|
_coerce_date(node.this, node.args["low"], promote_to_inferred_datetime_type)
|
|
80
|
-
elif isinstance(node, exp.Extract) and not node.expression.
|
|
80
|
+
elif isinstance(node, exp.Extract) and not node.expression.is_type(
|
|
81
81
|
*exp.DataType.TEMPORAL_TYPES
|
|
82
82
|
):
|
|
83
83
|
_replace_cast(node.expression, exp.DataType.Type.DATETIME)
|
|
@@ -201,6 +201,7 @@ def _mergeable(
|
|
|
201
201
|
and not outer_scope.pivots
|
|
202
202
|
and not any(e.find(exp.AggFunc, exp.Select, exp.Explode) for e in inner_select.expressions)
|
|
203
203
|
and not (leave_tables_isolated and len(outer_scope.selected_sources) > 1)
|
|
204
|
+
and not (isinstance(from_or_join, exp.Join) and inner_select.args.get("joins"))
|
|
204
205
|
and not (
|
|
205
206
|
isinstance(from_or_join, exp.Join)
|
|
206
207
|
and inner_select.args.get("where")
|
|
@@ -282,6 +283,7 @@ def _merge_joins(outer_scope: Scope, inner_scope: Scope, from_or_join: FromOrJoi
|
|
|
282
283
|
new_joins = []
|
|
283
284
|
|
|
284
285
|
joins = inner_scope.expression.args.get("joins") or []
|
|
286
|
+
|
|
285
287
|
for join in joins:
|
|
286
288
|
new_joins.append(join)
|
|
287
289
|
outer_scope.add_source(join.alias_or_name, inner_scope.sources[join.alias_or_name])
|
|
@@ -19,10 +19,15 @@ def optimize_joins(expression):
|
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
for select in expression.find_all(exp.Select):
|
|
22
|
+
joins = select.args.get("joins", [])
|
|
23
|
+
|
|
24
|
+
if not _is_reorderable(joins):
|
|
25
|
+
continue
|
|
26
|
+
|
|
22
27
|
references = {}
|
|
23
28
|
cross_joins = []
|
|
24
29
|
|
|
25
|
-
for join in
|
|
30
|
+
for join in joins:
|
|
26
31
|
tables = other_table_names(join)
|
|
27
32
|
|
|
28
33
|
if tables:
|
|
@@ -59,11 +64,20 @@ def reorder_joins(expression):
|
|
|
59
64
|
"""
|
|
60
65
|
for from_ in expression.find_all(exp.From):
|
|
61
66
|
parent = from_.parent
|
|
62
|
-
joins =
|
|
63
|
-
|
|
67
|
+
joins = parent.args.get("joins", [])
|
|
68
|
+
|
|
69
|
+
if not _is_reorderable(joins):
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
joins_by_name = {join.alias_or_name: join for join in joins}
|
|
73
|
+
dag = {name: other_table_names(join) for name, join in joins_by_name.items()}
|
|
64
74
|
parent.set(
|
|
65
75
|
"joins",
|
|
66
|
-
[
|
|
76
|
+
[
|
|
77
|
+
joins_by_name[name]
|
|
78
|
+
for name in tsort(dag)
|
|
79
|
+
if name != from_.alias_or_name and name in joins_by_name
|
|
80
|
+
],
|
|
67
81
|
)
|
|
68
82
|
return expression
|
|
69
83
|
|
|
@@ -90,3 +104,23 @@ def normalize(expression):
|
|
|
90
104
|
def other_table_names(join: exp.Join) -> t.Set[str]:
|
|
91
105
|
on = join.args.get("on")
|
|
92
106
|
return exp.column_table_names(on, join.alias_or_name) if on else set()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _is_reorderable(joins: t.List[exp.Join]) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Checks if joins can be reordered without changing query semantics.
|
|
112
|
+
|
|
113
|
+
Joins with a side (LEFT, RIGHT, FULL) cannot be reordered easily,
|
|
114
|
+
the order affects which rows are included in the result.
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
>>> from sqlglot import parse_one, exp
|
|
118
|
+
>>> from sqlglot.optimizer.optimize_joins import _is_reorderable
|
|
119
|
+
>>> ast = parse_one("SELECT * FROM x JOIN y ON x.id = y.id JOIN z ON y.id = z.id")
|
|
120
|
+
>>> _is_reorderable(ast.find(exp.Select).args.get("joins", []))
|
|
121
|
+
True
|
|
122
|
+
>>> ast = parse_one("SELECT * FROM x LEFT JOIN y ON x.id = y.id JOIN z ON y.id = z.id")
|
|
123
|
+
>>> _is_reorderable(ast.find(exp.Select).args.get("joins", []))
|
|
124
|
+
False
|
|
125
|
+
"""
|
|
126
|
+
return not any(join.side for join in joins)
|
sqlglot/parser.py
CHANGED
|
@@ -1141,11 +1141,6 @@ class Parser(metaclass=_Parser):
|
|
|
1141
1141
|
"TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
|
|
1142
1142
|
"UNIQUE": lambda self: self._parse_unique(),
|
|
1143
1143
|
"UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
|
|
1144
|
-
"WATERMARK": lambda self: self.expression(
|
|
1145
|
-
exp.WatermarkColumnConstraint,
|
|
1146
|
-
this=self._match(TokenType.FOR) and self._parse_column(),
|
|
1147
|
-
expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
|
|
1148
|
-
),
|
|
1149
1144
|
"WITH": lambda self: self.expression(
|
|
1150
1145
|
exp.Properties, expressions=self._parse_wrapped_properties()
|
|
1151
1146
|
),
|
|
@@ -1211,7 +1206,6 @@ class Parser(metaclass=_Parser):
|
|
|
1211
1206
|
"PERIOD",
|
|
1212
1207
|
"PRIMARY KEY",
|
|
1213
1208
|
"UNIQUE",
|
|
1214
|
-
"WATERMARK",
|
|
1215
1209
|
"BUCKET",
|
|
1216
1210
|
"TRUNCATE",
|
|
1217
1211
|
}
|
|
@@ -1438,11 +1432,7 @@ class Parser(metaclass=_Parser):
|
|
|
1438
1432
|
|
|
1439
1433
|
IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
|
|
1440
1434
|
|
|
1441
|
-
ODBC_DATETIME_LITERALS = {
|
|
1442
|
-
"d": exp.Date,
|
|
1443
|
-
"t": exp.Time,
|
|
1444
|
-
"ts": exp.Timestamp,
|
|
1445
|
-
}
|
|
1435
|
+
ODBC_DATETIME_LITERALS: t.Dict[str, t.Type[exp.Expression]] = {}
|
|
1446
1436
|
|
|
1447
1437
|
ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
|
|
1448
1438
|
|
|
@@ -1541,6 +1531,9 @@ class Parser(metaclass=_Parser):
|
|
|
1541
1531
|
# Whether renaming a column with an ALTER statement requires the presence of the COLUMN keyword
|
|
1542
1532
|
ALTER_RENAME_REQUIRES_COLUMN = True
|
|
1543
1533
|
|
|
1534
|
+
# Whether Alter statements are allowed to contain Partition specifications
|
|
1535
|
+
ALTER_TABLE_PARTITIONS = False
|
|
1536
|
+
|
|
1544
1537
|
# Whether all join types have the same precedence, i.e., they "naturally" produce a left-deep tree.
|
|
1545
1538
|
# In standard SQL, joins that use the JOIN keyword take higher precedence than comma-joins. That is
|
|
1546
1539
|
# to say, JOIN operators happen before comma operators. This is not the case in some dialects, such
|
|
@@ -3545,9 +3538,13 @@ class Parser(metaclass=_Parser):
|
|
|
3545
3538
|
|
|
3546
3539
|
return this
|
|
3547
3540
|
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3541
|
+
@t.overload
|
|
3542
|
+
def _parse_query_modifiers(self, this: E) -> E: ...
|
|
3543
|
+
|
|
3544
|
+
@t.overload
|
|
3545
|
+
def _parse_query_modifiers(self, this: None) -> None: ...
|
|
3546
|
+
|
|
3547
|
+
def _parse_query_modifiers(self, this):
|
|
3551
3548
|
if isinstance(this, self.MODIFIABLES):
|
|
3552
3549
|
for join in self._parse_joins():
|
|
3553
3550
|
this.append("joins", join)
|
|
@@ -4592,21 +4589,11 @@ class Parser(metaclass=_Parser):
|
|
|
4592
4589
|
before_with_index = self._index
|
|
4593
4590
|
with_prefix = self._match(TokenType.WITH)
|
|
4594
4591
|
|
|
4595
|
-
if self.
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
elements["cube"].append(
|
|
4601
|
-
self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
|
|
4602
|
-
)
|
|
4603
|
-
elif self._match(TokenType.GROUPING_SETS):
|
|
4604
|
-
elements["grouping_sets"].append(
|
|
4605
|
-
self.expression(
|
|
4606
|
-
exp.GroupingSets,
|
|
4607
|
-
expressions=self._parse_wrapped_csv(self._parse_grouping_set),
|
|
4608
|
-
)
|
|
4609
|
-
)
|
|
4592
|
+
if cube_or_rollup := self._parse_cube_or_rollup(with_prefix=with_prefix):
|
|
4593
|
+
key = "rollup" if isinstance(cube_or_rollup, exp.Rollup) else "cube"
|
|
4594
|
+
elements[key].append(cube_or_rollup)
|
|
4595
|
+
elif grouping_sets := self._parse_grouping_sets():
|
|
4596
|
+
elements["grouping_sets"].append(grouping_sets)
|
|
4610
4597
|
elif self._match_text_seq("TOTALS"):
|
|
4611
4598
|
elements["totals"] = True # type: ignore
|
|
4612
4599
|
|
|
@@ -4619,18 +4606,27 @@ class Parser(metaclass=_Parser):
|
|
|
4619
4606
|
|
|
4620
4607
|
return self.expression(exp.Group, comments=comments, **elements) # type: ignore
|
|
4621
4608
|
|
|
4622
|
-
def _parse_cube_or_rollup(self,
|
|
4609
|
+
def _parse_cube_or_rollup(self, with_prefix: bool = False) -> t.Optional[exp.Cube | exp.Rollup]:
|
|
4610
|
+
if self._match(TokenType.CUBE):
|
|
4611
|
+
kind: t.Type[exp.Cube | exp.Rollup] = exp.Cube
|
|
4612
|
+
elif self._match(TokenType.ROLLUP):
|
|
4613
|
+
kind = exp.Rollup
|
|
4614
|
+
else:
|
|
4615
|
+
return None
|
|
4616
|
+
|
|
4623
4617
|
return self.expression(
|
|
4624
4618
|
kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
|
|
4625
4619
|
)
|
|
4626
4620
|
|
|
4627
|
-
def
|
|
4628
|
-
if self._match(TokenType.
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4621
|
+
def _parse_grouping_sets(self) -> t.Optional[exp.GroupingSets]:
|
|
4622
|
+
if self._match(TokenType.GROUPING_SETS):
|
|
4623
|
+
return self.expression(
|
|
4624
|
+
exp.GroupingSets, expressions=self._parse_wrapped_csv(self._parse_grouping_set)
|
|
4625
|
+
)
|
|
4626
|
+
return None
|
|
4632
4627
|
|
|
4633
|
-
|
|
4628
|
+
def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
|
|
4629
|
+
return self._parse_grouping_sets() or self._parse_cube_or_rollup() or self._parse_bitwise()
|
|
4634
4630
|
|
|
4635
4631
|
def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
|
|
4636
4632
|
if not skip_having_token and not self._match(TokenType.HAVING):
|
|
@@ -4749,11 +4745,15 @@ class Parser(metaclass=_Parser):
|
|
|
4749
4745
|
exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
|
|
4750
4746
|
)
|
|
4751
4747
|
|
|
4752
|
-
def _parse_limit_options(self) -> exp.LimitOptions:
|
|
4753
|
-
percent = self.
|
|
4748
|
+
def _parse_limit_options(self) -> t.Optional[exp.LimitOptions]:
|
|
4749
|
+
percent = self._match_set((TokenType.PERCENT, TokenType.MOD))
|
|
4754
4750
|
rows = self._match_set((TokenType.ROW, TokenType.ROWS))
|
|
4755
4751
|
self._match_text_seq("ONLY")
|
|
4756
4752
|
with_ties = self._match_text_seq("WITH", "TIES")
|
|
4753
|
+
|
|
4754
|
+
if not (percent or rows or with_ties):
|
|
4755
|
+
return None
|
|
4756
|
+
|
|
4757
4757
|
return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
|
|
4758
4758
|
|
|
4759
4759
|
def _parse_limit(
|
|
@@ -4771,10 +4771,13 @@ class Parser(metaclass=_Parser):
|
|
|
4771
4771
|
if limit_paren:
|
|
4772
4772
|
self._match_r_paren()
|
|
4773
4773
|
|
|
4774
|
-
limit_options = self._parse_limit_options()
|
|
4775
4774
|
else:
|
|
4776
|
-
|
|
4777
|
-
|
|
4775
|
+
# Parsing LIMIT x% (i.e x PERCENT) as a term leads to an error, since
|
|
4776
|
+
# we try to build an exp.Mod expr. For that matter, we backtrack and instead
|
|
4777
|
+
# consume the factor plus parse the percentage separately
|
|
4778
|
+
expression = self._try_parse(self._parse_term) or self._parse_factor()
|
|
4779
|
+
|
|
4780
|
+
limit_options = self._parse_limit_options()
|
|
4778
4781
|
|
|
4779
4782
|
if self._match(TokenType.COMMA):
|
|
4780
4783
|
offset = expression
|
|
@@ -5060,8 +5063,12 @@ class Parser(metaclass=_Parser):
|
|
|
5060
5063
|
matched_l_paren = self._prev.token_type == TokenType.L_PAREN
|
|
5061
5064
|
expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
|
|
5062
5065
|
|
|
5063
|
-
if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
|
|
5064
|
-
this = self.expression(
|
|
5066
|
+
if len(expressions) == 1 and isinstance(query := expressions[0], exp.Query):
|
|
5067
|
+
this = self.expression(
|
|
5068
|
+
exp.In,
|
|
5069
|
+
this=this,
|
|
5070
|
+
query=self._parse_query_modifiers(query).subquery(copy=False),
|
|
5071
|
+
)
|
|
5065
5072
|
else:
|
|
5066
5073
|
this = self.expression(exp.In, this=this, expressions=expressions)
|
|
5067
5074
|
|
|
@@ -5791,14 +5798,17 @@ class Parser(metaclass=_Parser):
|
|
|
5791
5798
|
else:
|
|
5792
5799
|
expressions = self._parse_expressions()
|
|
5793
5800
|
|
|
5794
|
-
this =
|
|
5801
|
+
this = seq_get(expressions, 0)
|
|
5795
5802
|
|
|
5796
5803
|
if not this and self._match(TokenType.R_PAREN, advance=False):
|
|
5797
5804
|
this = self.expression(exp.Tuple)
|
|
5798
5805
|
elif isinstance(this, exp.UNWRAPPED_QUERIES):
|
|
5799
5806
|
this = self._parse_subquery(this=this, parse_alias=False)
|
|
5800
5807
|
elif isinstance(this, exp.Subquery):
|
|
5801
|
-
this = self._parse_subquery(
|
|
5808
|
+
this = self._parse_subquery(
|
|
5809
|
+
this=self._parse_query_modifiers(self._parse_set_operations(this)),
|
|
5810
|
+
parse_alias=False,
|
|
5811
|
+
)
|
|
5802
5812
|
elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
|
|
5803
5813
|
this = self.expression(exp.Tuple, expressions=expressions)
|
|
5804
5814
|
else:
|
|
@@ -6911,10 +6921,12 @@ class Parser(metaclass=_Parser):
|
|
|
6911
6921
|
def _parse_json_column_def(self) -> exp.JSONColumnDef:
|
|
6912
6922
|
if not self._match_text_seq("NESTED"):
|
|
6913
6923
|
this = self._parse_id_var()
|
|
6924
|
+
ordinality = self._match_pair(TokenType.FOR, TokenType.ORDINALITY)
|
|
6914
6925
|
kind = self._parse_types(allow_identifiers=False)
|
|
6915
6926
|
nested = None
|
|
6916
6927
|
else:
|
|
6917
6928
|
this = None
|
|
6929
|
+
ordinality = None
|
|
6918
6930
|
kind = None
|
|
6919
6931
|
nested = True
|
|
6920
6932
|
|
|
@@ -6927,6 +6939,7 @@ class Parser(metaclass=_Parser):
|
|
|
6927
6939
|
kind=kind,
|
|
6928
6940
|
path=path,
|
|
6929
6941
|
nested_schema=nested_schema,
|
|
6942
|
+
ordinality=ordinality,
|
|
6930
6943
|
)
|
|
6931
6944
|
|
|
6932
6945
|
def _parse_json_schema(self) -> exp.JSONSchema:
|
|
@@ -7722,7 +7735,7 @@ class Parser(metaclass=_Parser):
|
|
|
7722
7735
|
check = None
|
|
7723
7736
|
cluster = None
|
|
7724
7737
|
else:
|
|
7725
|
-
this = self._parse_table(schema=True)
|
|
7738
|
+
this = self._parse_table(schema=True, parse_partition=self.ALTER_TABLE_PARTITIONS)
|
|
7726
7739
|
check = self._match_text_seq("WITH", "CHECK")
|
|
7727
7740
|
cluster = self._parse_on_property() if self._match(TokenType.ON) else None
|
|
7728
7741
|
|
|
@@ -7734,6 +7747,7 @@ class Parser(metaclass=_Parser):
|
|
|
7734
7747
|
actions = ensure_list(parser(self))
|
|
7735
7748
|
not_valid = self._match_text_seq("NOT", "VALID")
|
|
7736
7749
|
options = self._parse_csv(self._parse_property)
|
|
7750
|
+
cascade = self.dialect.ALTER_TABLE_SUPPORTS_CASCADE and self._match_text_seq("CASCADE")
|
|
7737
7751
|
|
|
7738
7752
|
if not self._curr and actions:
|
|
7739
7753
|
return self.expression(
|
|
@@ -7747,6 +7761,7 @@ class Parser(metaclass=_Parser):
|
|
|
7747
7761
|
cluster=cluster,
|
|
7748
7762
|
not_valid=not_valid,
|
|
7749
7763
|
check=check,
|
|
7764
|
+
cascade=cascade,
|
|
7750
7765
|
)
|
|
7751
7766
|
|
|
7752
7767
|
return self._parse_as_command(start)
|
|
@@ -8642,10 +8657,10 @@ class Parser(metaclass=_Parser):
|
|
|
8642
8657
|
args: t.List[exp.Expression] = []
|
|
8643
8658
|
|
|
8644
8659
|
if self._match(TokenType.DISTINCT):
|
|
8645
|
-
args.append(self.expression(exp.Distinct, expressions=[self.
|
|
8660
|
+
args.append(self.expression(exp.Distinct, expressions=[self._parse_lambda()]))
|
|
8646
8661
|
self._match(TokenType.COMMA)
|
|
8647
8662
|
|
|
8648
|
-
args.extend(self.
|
|
8663
|
+
args.extend(self._parse_function_args())
|
|
8649
8664
|
|
|
8650
8665
|
return self.expression(
|
|
8651
8666
|
expr_type, this=seq_get(args, 0), expression=seq_get(args, 1), count=seq_get(args, 2)
|
sqlglot/tokens.py
CHANGED
|
@@ -1421,7 +1421,11 @@ class Tokenizer(metaclass=_Tokenizer):
|
|
|
1421
1421
|
raise_unmatched=not self.HEREDOC_TAG_IS_IDENTIFIER,
|
|
1422
1422
|
)
|
|
1423
1423
|
|
|
1424
|
-
if
|
|
1424
|
+
if (
|
|
1425
|
+
tag
|
|
1426
|
+
and self.HEREDOC_TAG_IS_IDENTIFIER
|
|
1427
|
+
and (self._end or tag.isdigit() or any(c.isspace() for c in tag))
|
|
1428
|
+
):
|
|
1425
1429
|
if not self._end:
|
|
1426
1430
|
self._advance(-1)
|
|
1427
1431
|
|
sqlglot/transforms.py
CHANGED
|
@@ -131,39 +131,6 @@ def unnest_generate_series(expression: exp.Expression) -> exp.Expression:
|
|
|
131
131
|
return expression
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def unalias_group(expression: exp.Expression) -> exp.Expression:
|
|
135
|
-
"""
|
|
136
|
-
Replace references to select aliases in GROUP BY clauses.
|
|
137
|
-
|
|
138
|
-
Example:
|
|
139
|
-
>>> import sqlglot
|
|
140
|
-
>>> sqlglot.parse_one("SELECT a AS b FROM x GROUP BY b").transform(unalias_group).sql()
|
|
141
|
-
'SELECT a AS b FROM x GROUP BY 1'
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
expression: the expression that will be transformed.
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
The transformed expression.
|
|
148
|
-
"""
|
|
149
|
-
if isinstance(expression, exp.Group) and isinstance(expression.parent, exp.Select):
|
|
150
|
-
aliased_selects = {
|
|
151
|
-
e.alias: i
|
|
152
|
-
for i, e in enumerate(expression.parent.expressions, start=1)
|
|
153
|
-
if isinstance(e, exp.Alias)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
for group_by in expression.expressions:
|
|
157
|
-
if (
|
|
158
|
-
isinstance(group_by, exp.Column)
|
|
159
|
-
and not group_by.table
|
|
160
|
-
and group_by.name in aliased_selects
|
|
161
|
-
):
|
|
162
|
-
group_by.replace(exp.Literal.number(aliased_selects.get(group_by.name)))
|
|
163
|
-
|
|
164
|
-
return expression
|
|
165
|
-
|
|
166
|
-
|
|
167
134
|
def eliminate_distinct_on(expression: exp.Expression) -> exp.Expression:
|
|
168
135
|
"""
|
|
169
136
|
Convert SELECT DISTINCT ON statements to a subquery with a window function.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglot
|
|
3
|
-
Version: 27.
|
|
3
|
+
Version: 27.22.0
|
|
4
4
|
Summary: An easily customizable SQL parser and transpiler
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,7 +33,7 @@ Requires-Dist: typing_extensions; extra == "dev"
|
|
|
33
33
|
Requires-Dist: maturin<2.0,>=1.4; extra == "dev"
|
|
34
34
|
Requires-Dist: pyperf; extra == "dev"
|
|
35
35
|
Provides-Extra: rs
|
|
36
|
-
Requires-Dist: sqlglotrs==0.
|
|
36
|
+
Requires-Dist: sqlglotrs==0.7.0; extra == "rs"
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
Dynamic: provides-extra
|
|
39
39
|
|
|
@@ -1,57 +1,57 @@
|
|
|
1
1
|
sqlglot/__init__.py,sha256=za08rtdPh2v7dOpGdNomttlIVGgTrKja7rPd6sQwaTg,5391
|
|
2
2
|
sqlglot/__main__.py,sha256=022c173KqxsiABWTEpUIq_tJUxuNiW7a7ABsxBXqvu8,2069
|
|
3
3
|
sqlglot/_typing.py,sha256=-1HPyr3w5COlSJWqlgt8jhFk2dyMvBuvVBqIX1wyVCM,642
|
|
4
|
-
sqlglot/_version.py,sha256=
|
|
4
|
+
sqlglot/_version.py,sha256=E5VE3-EaKBoByAYk3KI0bC-SdIUPpA7ebugcTIcI_gA,708
|
|
5
5
|
sqlglot/diff.py,sha256=PtOllQMQa1Sw1-V2Y8eypmDqGujXYPaTOp_WLsWkAWk,17314
|
|
6
6
|
sqlglot/errors.py,sha256=QNKMr-pzLUDR-tuMmn_GK6iMHUIVdb_YSJ_BhGEvuso,2126
|
|
7
|
-
sqlglot/expressions.py,sha256=
|
|
8
|
-
sqlglot/generator.py,sha256=
|
|
7
|
+
sqlglot/expressions.py,sha256=PTwHBbIp3jRz7sjVKZShHJuzlkSg_8rNTxsONy0gfAc,261611
|
|
8
|
+
sqlglot/generator.py,sha256=CmYKDYSuwgPjgRsDlf3e__PFeTdojkUCCplMu4xT4qc,226966
|
|
9
9
|
sqlglot/helper.py,sha256=OOt5_Mbmnl4Uy6WO6v7DR1iLPcb3v6ITybpq6usf3jw,14471
|
|
10
10
|
sqlglot/jsonpath.py,sha256=SQgaxzaEYBN7At9dkTK4N1Spk6xHxvHL6QtCIP6iM30,7905
|
|
11
11
|
sqlglot/lineage.py,sha256=Qj5ykuDNcATppb9vOjoIKBqRVLbu3OMPiZk9f3iyv40,15312
|
|
12
|
-
sqlglot/parser.py,sha256=
|
|
12
|
+
sqlglot/parser.py,sha256=N7pgpA20wuXDU2Wo1zjjEGuBcl3fZyBMp_Ss3nLppoY,338172
|
|
13
13
|
sqlglot/planner.py,sha256=ql7Li-bWJRcyXzNaZy_n6bQ6B2ZfunEIB8Ztv2xaxq4,14634
|
|
14
14
|
sqlglot/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
sqlglot/schema.py,sha256=13H2qKQs27EKdTpDLOvcNnSTDAUbYNKjWtJs4aQCSOA,20509
|
|
16
16
|
sqlglot/serde.py,sha256=nWpBFUjwZh06Li4qBuNb0YRU_QyflzSVyWkFxujM0WM,3175
|
|
17
17
|
sqlglot/time.py,sha256=Q62gv6kL40OiRBF6BMESxKJcMVn7ZLNw7sv8H34z5FI,18400
|
|
18
|
-
sqlglot/tokens.py,sha256=
|
|
19
|
-
sqlglot/transforms.py,sha256=
|
|
18
|
+
sqlglot/tokens.py,sha256=46CMEmRhJOa3eNagIIK9ndm-_ZSwnaV-AqgZs-SHNro,49321
|
|
19
|
+
sqlglot/transforms.py,sha256=Nx0AM6b2ApfPOcbTlz9_m6DiauWMKC4s4Xe0yuuBmYk,40175
|
|
20
20
|
sqlglot/trie.py,sha256=v27uXMrHfqrXlJ6GmeTSMovsB_3o0ctnlKhdNt7W6fI,2245
|
|
21
21
|
sqlglot/dialects/__init__.py,sha256=g3HRtyb32r3LooiHKTzuUNB0_rBO_RauuOegp42gB48,3811
|
|
22
22
|
sqlglot/dialects/athena.py,sha256=ofArmayYLev4qZQ15GM8mevG04qqR5WGFb2ZcuYm6x4,10966
|
|
23
|
-
sqlglot/dialects/bigquery.py,sha256=
|
|
23
|
+
sqlglot/dialects/bigquery.py,sha256=l_t70png3A83zEDWUBBsCbiM40HfKIP03Wuq3Zt9CUI,72889
|
|
24
24
|
sqlglot/dialects/clickhouse.py,sha256=6kx1cm0YhtHbg5kvcY64Hau2KdeC7Y26SVlVHGLyPEA,58579
|
|
25
25
|
sqlglot/dialects/databricks.py,sha256=H4QTq7gg6tJylKc_YWsGp6049KydoI_wlQUHM7iCJtI,4753
|
|
26
|
-
sqlglot/dialects/dialect.py,sha256=
|
|
26
|
+
sqlglot/dialects/dialect.py,sha256=wUobB-jvOgd_JucRCyUYK6qRx2Hts8mQKmk8kgwWkdc,73979
|
|
27
27
|
sqlglot/dialects/doris.py,sha256=CFnF955Oav3IjZWA80ickOI8tPpCjxk7BN5R4Z6pA1U,25263
|
|
28
28
|
sqlglot/dialects/dremio.py,sha256=nOMxu_4xVKSOmMGNSwdxXSPc243cNbbpb-xXzYdgdeg,8460
|
|
29
29
|
sqlglot/dialects/drill.py,sha256=FOh7_KjPx_77pv0DiHKZog0CcmzqeF9_PEmGnJ1ESSM,5825
|
|
30
30
|
sqlglot/dialects/druid.py,sha256=kh3snZtneehNOWqs3XcPjsrhNaRbkCQ8E4hHbWJ1fHM,690
|
|
31
|
-
sqlglot/dialects/duckdb.py,sha256=
|
|
31
|
+
sqlglot/dialects/duckdb.py,sha256=xennAC2Gh3eImkpHo0-cf4BBzcAKx-HkexyZfQMiUCo,54655
|
|
32
32
|
sqlglot/dialects/dune.py,sha256=gALut-fFfN2qMsr8LvZ1NQK3F3W9z2f4PwMvTMXVVVg,375
|
|
33
33
|
sqlglot/dialects/exasol.py,sha256=ay3g_VyT5WvHTgNyJuCQu0nBt4bpllLZ9IdMBizEgYM,15761
|
|
34
34
|
sqlglot/dialects/fabric.py,sha256=BdkvzM8s-m5DIdBwdjEYskp32ub7aHCAex_xlhQn92I,10222
|
|
35
|
-
sqlglot/dialects/hive.py,sha256=
|
|
35
|
+
sqlglot/dialects/hive.py,sha256=Uw-7Y1LnYOdcv71jCIZXhMvJAWwU5AVcFlIuM-YArnY,34530
|
|
36
36
|
sqlglot/dialects/materialize.py,sha256=LD2q1kTRrCwkIu1BfoBvnjTGbupDtoQ8JQMDCIYAXHg,3533
|
|
37
37
|
sqlglot/dialects/mysql.py,sha256=xxVAR-pXMljYCUioavP3nROtOqKmK4kfdp4WWXX7X9g,50049
|
|
38
|
-
sqlglot/dialects/oracle.py,sha256=
|
|
38
|
+
sqlglot/dialects/oracle.py,sha256=qB6Ga0Si2-TpVNqU_2COvWESIUYNL32rYk_BC9aiujE,15898
|
|
39
39
|
sqlglot/dialects/postgres.py,sha256=_pXSu29684utgeuzPziSJ0Sw54WEIIunwLugJw7KFD8,34853
|
|
40
|
-
sqlglot/dialects/presto.py,sha256=
|
|
40
|
+
sqlglot/dialects/presto.py,sha256=5C6I_aDC-9CDrLfY97EFsUWymaS3B7aW_-h-mHleWIQ,33339
|
|
41
41
|
sqlglot/dialects/prql.py,sha256=fwN-SPEGx-drwf1K0U2MByN-PkW3C_rOgQ3xeJeychg,7908
|
|
42
42
|
sqlglot/dialects/redshift.py,sha256=FIwtP3yEg-way9pa32kxCJc6IaFkHVIvgYKZA-Ilmi0,15919
|
|
43
|
-
sqlglot/dialects/risingwave.py,sha256=
|
|
43
|
+
sqlglot/dialects/risingwave.py,sha256=Wd-I_Hbwl-6Rgf_NM0I_axliInY418k2kaAWRCmaqyE,3791
|
|
44
44
|
sqlglot/dialects/singlestore.py,sha256=0QqNYOucNklPQuyeGcsisLI97qPGx_RfWKOFarJz2qw,61711
|
|
45
|
-
sqlglot/dialects/snowflake.py,sha256=
|
|
45
|
+
sqlglot/dialects/snowflake.py,sha256=JZfQ9QO_67TIpI36HIkk77gsjJWsZ1eOZWmWZpoUkjc,82018
|
|
46
46
|
sqlglot/dialects/solr.py,sha256=pydnl4ml-3M1Fc4ALm6cMVO9h-5EtqZxPZH_91Nz1Ss,617
|
|
47
|
-
sqlglot/dialects/spark.py,sha256=
|
|
48
|
-
sqlglot/dialects/spark2.py,sha256=
|
|
47
|
+
sqlglot/dialects/spark.py,sha256=mt3Twh0_EJelYy_7HLinDEQ1Chj2EYMjeLCPLRzAJXY,10113
|
|
48
|
+
sqlglot/dialects/spark2.py,sha256=s4RTOGunYT1_HJt4KbhBWK_eOgmtzlpBCQCl60KEPAQ,15621
|
|
49
49
|
sqlglot/dialects/sqlite.py,sha256=FuEDDyKZeeWVblknhFSMX7dNoS-ci5ktXpSXZeBK5xA,13592
|
|
50
50
|
sqlglot/dialects/starrocks.py,sha256=-NWQa2gJbiMMfLauX-Jy9ciJ5DUzUOk2QkPbhglz5W4,11446
|
|
51
51
|
sqlglot/dialects/tableau.py,sha256=oIawDzUITxGCWaEMB8OaNMPWhbC3U-2y09pYPm4eazc,2190
|
|
52
52
|
sqlglot/dialects/teradata.py,sha256=7LxCcRwP0Idd_OnCzA57NCdheVjHcKC2aFAKG5N49IU,18202
|
|
53
53
|
sqlglot/dialects/trino.py,sha256=Z7prRhCxIBh0KCxIQpWmVOIGHCJM9Xl5oRlqySxln4Y,4350
|
|
54
|
-
sqlglot/dialects/tsql.py,sha256=
|
|
54
|
+
sqlglot/dialects/tsql.py,sha256=w4wdIwYiA9JY4JvESYLEqp-KDvRR89MjE88rdTPK410,54783
|
|
55
55
|
sqlglot/executor/__init__.py,sha256=FslewzYQtQdDNg_0Ju2UaiP4vo4IMUgkfkmFsYUhcN0,2958
|
|
56
56
|
sqlglot/executor/context.py,sha256=WJHJdYQCOeVXwLw0uSSrWSc25eBMn5Ix108RCvdsKRQ,3386
|
|
57
57
|
sqlglot/executor/env.py,sha256=tQhU5PpTBMcxgZIFddFqxWMNPtHN0vOOz72voncY3KY,8276
|
|
@@ -59,15 +59,15 @@ sqlglot/executor/python.py,sha256=09GYRzrPn3lZGfDJY9pbONOvmYxsRyeSWjUiqkSRHGo,16
|
|
|
59
59
|
sqlglot/executor/table.py,sha256=xkuJlgLVNYUXsSUaX0zTcnFekldXLLU8LqDyjR5K9wY,4419
|
|
60
60
|
sqlglot/optimizer/__init__.py,sha256=FdAvVz6rQLLkiiH21-SD4RxB5zS3WDeU-s03PZkJ-F4,343
|
|
61
61
|
sqlglot/optimizer/annotate_types.py,sha256=kCPwrbBXSiO0oJUlkw8NkdsoLgjJ4l5LOouCHPqOFlA,26728
|
|
62
|
-
sqlglot/optimizer/canonicalize.py,sha256=
|
|
62
|
+
sqlglot/optimizer/canonicalize.py,sha256=5Yc6cFAd1gENqJ3OqejsUE40MV4vqQ-PqBnJXV3SMj8,7714
|
|
63
63
|
sqlglot/optimizer/eliminate_ctes.py,sha256=fUBM0RUnPrm2sYptEWBux98B7fcx7W-BM1zVqfgDz9c,1448
|
|
64
64
|
sqlglot/optimizer/eliminate_joins.py,sha256=2iYtG93aJGxvURqm1BVPosrnnnQ_IXI14RcD4pM8eHc,5942
|
|
65
65
|
sqlglot/optimizer/eliminate_subqueries.py,sha256=sAB_Pk94_n2n1PIaZ2Mc3M-n2TV-JmjjaomaY14u0Og,6292
|
|
66
66
|
sqlglot/optimizer/isolate_table_selects.py,sha256=_8rIKVMoL7eY3rrJsmgIdTRvfmBSLUxeHg42q1JW990,1464
|
|
67
|
-
sqlglot/optimizer/merge_subqueries.py,sha256
|
|
67
|
+
sqlglot/optimizer/merge_subqueries.py,sha256=tis4la3HeAsglhYcLu9EMaVGsNiyecq5iwHkfmW0WQU,15532
|
|
68
68
|
sqlglot/optimizer/normalize.py,sha256=wu3GeKY36PLyAb9f534jDDfzDwvZJpZ8g_H5QH6acZQ,6667
|
|
69
69
|
sqlglot/optimizer/normalize_identifiers.py,sha256=uD4xICJAgj0X7EFc2LYcDWxAW2aTHANO2wy7kfn9gfY,2098
|
|
70
|
-
sqlglot/optimizer/optimize_joins.py,sha256=
|
|
70
|
+
sqlglot/optimizer/optimize_joins.py,sha256=nnfRpL03lpDQF1oBO1EgaABqnr6t2GP6uMWoSLPW3IQ,4120
|
|
71
71
|
sqlglot/optimizer/optimizer.py,sha256=vXEXDWHvbO-vJmSI7UqJuydM2WrD1xko7rETq2EtVJo,3533
|
|
72
72
|
sqlglot/optimizer/pushdown_predicates.py,sha256=HGjs3Z4V3-X2d1VTfWhyByY3aL5SmKnVvt3aDXiiBM0,8414
|
|
73
73
|
sqlglot/optimizer/pushdown_projections.py,sha256=7NoK5NAUVYVhs0YnYyo6WuXfaO-BShSwS6lA8Y-ATQ4,6668
|
|
@@ -77,8 +77,8 @@ sqlglot/optimizer/qualify_tables.py,sha256=dA4ZazL7ShQh2JgBwpHuG-4c5lBw1TNzCnuN7
|
|
|
77
77
|
sqlglot/optimizer/scope.py,sha256=UOTrbwqcTc5iRQf0WStgYWXpE24w6riZy-tJYA18yTw,31229
|
|
78
78
|
sqlglot/optimizer/simplify.py,sha256=27IYsqbz1kyMlURSfRkm_ADSQJg-4805AOMFOjKKytU,51049
|
|
79
79
|
sqlglot/optimizer/unnest_subqueries.py,sha256=kzWUVDlxs8z9nmRx-8U-pHXPtVZhEIwkKqmKhr2QLvc,10908
|
|
80
|
-
sqlglot-27.
|
|
81
|
-
sqlglot-27.
|
|
82
|
-
sqlglot-27.
|
|
83
|
-
sqlglot-27.
|
|
84
|
-
sqlglot-27.
|
|
80
|
+
sqlglot-27.22.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
|
|
81
|
+
sqlglot-27.22.0.dist-info/METADATA,sha256=aoHNF0rhdj1BNAUJDXumHET2la45gugovXSPzFCXL4k,20825
|
|
82
|
+
sqlglot-27.22.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
83
|
+
sqlglot-27.22.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
|
|
84
|
+
sqlglot-27.22.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|