sqlglot 28.4.0__py3-none-any.whl → 28.8.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.
Files changed (50) hide show
  1. sqlglot/_version.py +2 -2
  2. sqlglot/dialects/bigquery.py +20 -23
  3. sqlglot/dialects/clickhouse.py +2 -0
  4. sqlglot/dialects/dialect.py +355 -18
  5. sqlglot/dialects/doris.py +38 -90
  6. sqlglot/dialects/druid.py +1 -0
  7. sqlglot/dialects/duckdb.py +1739 -163
  8. sqlglot/dialects/exasol.py +17 -1
  9. sqlglot/dialects/hive.py +27 -2
  10. sqlglot/dialects/mysql.py +103 -11
  11. sqlglot/dialects/oracle.py +38 -1
  12. sqlglot/dialects/postgres.py +142 -33
  13. sqlglot/dialects/presto.py +6 -2
  14. sqlglot/dialects/redshift.py +7 -1
  15. sqlglot/dialects/singlestore.py +13 -3
  16. sqlglot/dialects/snowflake.py +271 -21
  17. sqlglot/dialects/spark.py +25 -0
  18. sqlglot/dialects/spark2.py +4 -3
  19. sqlglot/dialects/starrocks.py +152 -17
  20. sqlglot/dialects/trino.py +1 -0
  21. sqlglot/dialects/tsql.py +5 -0
  22. sqlglot/diff.py +1 -1
  23. sqlglot/expressions.py +239 -47
  24. sqlglot/generator.py +173 -44
  25. sqlglot/optimizer/annotate_types.py +129 -60
  26. sqlglot/optimizer/merge_subqueries.py +13 -2
  27. sqlglot/optimizer/qualify_columns.py +7 -0
  28. sqlglot/optimizer/resolver.py +19 -0
  29. sqlglot/optimizer/scope.py +12 -0
  30. sqlglot/optimizer/unnest_subqueries.py +7 -0
  31. sqlglot/parser.py +251 -58
  32. sqlglot/schema.py +186 -14
  33. sqlglot/tokens.py +36 -6
  34. sqlglot/transforms.py +6 -5
  35. sqlglot/typing/__init__.py +29 -10
  36. sqlglot/typing/bigquery.py +5 -10
  37. sqlglot/typing/duckdb.py +39 -0
  38. sqlglot/typing/hive.py +50 -1
  39. sqlglot/typing/mysql.py +32 -0
  40. sqlglot/typing/presto.py +0 -1
  41. sqlglot/typing/snowflake.py +80 -17
  42. sqlglot/typing/spark.py +29 -0
  43. sqlglot/typing/spark2.py +9 -1
  44. sqlglot/typing/tsql.py +21 -0
  45. {sqlglot-28.4.0.dist-info → sqlglot-28.8.0.dist-info}/METADATA +47 -2
  46. sqlglot-28.8.0.dist-info/RECORD +95 -0
  47. {sqlglot-28.4.0.dist-info → sqlglot-28.8.0.dist-info}/WHEEL +1 -1
  48. sqlglot-28.4.0.dist-info/RECORD +0 -92
  49. {sqlglot-28.4.0.dist-info → sqlglot-28.8.0.dist-info}/licenses/LICENSE +0 -0
  50. {sqlglot-28.4.0.dist-info → sqlglot-28.8.0.dist-info}/top_level.txt +0 -0
sqlglot/dialects/doris.py CHANGED
@@ -68,11 +68,36 @@ class Doris(MySQL):
68
68
  "UNIQUE": lambda self: self._parse_composite_key_property(exp.UniqueKeyProperty),
69
69
  # Plain KEY without UNIQUE/DUPLICATE/AGGREGATE prefixes should be treated as UniqueKeyProperty with unique=False
70
70
  "KEY": lambda self: self._parse_composite_key_property(exp.UniqueKeyProperty),
71
- "PARTITION BY": lambda self: self._parse_partition_by_opt_range(),
72
71
  "BUILD": lambda self: self._parse_build_property(),
73
72
  "REFRESH": lambda self: self._parse_refresh_property(),
74
73
  }
75
74
 
75
+ def _parse_partition_property(
76
+ self,
77
+ ) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
78
+ expr = super()._parse_partition_property()
79
+
80
+ if not expr:
81
+ return self._parse_partitioned_by()
82
+
83
+ if isinstance(expr, exp.Property):
84
+ return expr
85
+
86
+ self._match_l_paren()
87
+
88
+ if self._match_text_seq("FROM", advance=False):
89
+ create_expressions = self._parse_csv(self._parse_partitioning_granularity_dynamic)
90
+ else:
91
+ create_expressions = None
92
+
93
+ self._match_r_paren()
94
+
95
+ return self.expression(
96
+ exp.PartitionByRangeProperty,
97
+ partition_expressions=expr,
98
+ create_expressions=create_expressions,
99
+ )
100
+
76
101
  def _parse_partitioning_granularity_dynamic(self) -> exp.PartitionByRangePropertyDynamic:
77
102
  self._match_text_seq("FROM")
78
103
  start = self._parse_wrapped(self._parse_string)
@@ -86,20 +111,16 @@ class Doris(MySQL):
86
111
  exp.PartitionByRangePropertyDynamic, start=start, end=end, every=every
87
112
  )
88
113
 
89
- def _parse_partition_definition(self) -> exp.Partition:
90
- self._match_text_seq("PARTITION")
114
+ def _parse_partition_range_value(self) -> exp.Partition:
115
+ expr = super()._parse_partition_range_value()
91
116
 
92
- name = self._parse_id_var()
93
- self._match_text_seq("VALUES")
94
-
95
- if self._match_text_seq("LESS", "THAN"):
96
- values = self._parse_wrapped_csv(self._parse_expression)
97
- if len(values) == 1 and values[0].name.upper() == "MAXVALUE":
98
- values = [exp.var("MAXVALUE")]
117
+ if isinstance(expr, exp.Partition):
118
+ return expr
99
119
 
100
- part_range = self.expression(exp.PartitionRange, this=name, expressions=values)
101
- return self.expression(exp.Partition, expressions=[part_range])
120
+ self._match_text_seq("VALUES")
121
+ name = expr
102
122
 
123
+ # Doris-specific bracket syntax: VALUES [(...), (...))
103
124
  self._match(TokenType.L_BRACKET)
104
125
  values = self._parse_csv(lambda: self._parse_wrapped_csv(self._parse_expression))
105
126
 
@@ -109,48 +130,6 @@ class Doris(MySQL):
109
130
  part_range = self.expression(exp.PartitionRange, this=name, expressions=values)
110
131
  return self.expression(exp.Partition, expressions=[part_range])
111
132
 
112
- def _parse_partition_definition_list(self) -> exp.Partition:
113
- # PARTITION <name> VALUES IN (<value_csv>)
114
- self._match_text_seq("PARTITION")
115
- name = self._parse_id_var()
116
- self._match_text_seq("VALUES", "IN")
117
- values = self._parse_wrapped_csv(self._parse_expression)
118
- part_list = self.expression(exp.PartitionList, this=name, expressions=values)
119
- return self.expression(exp.Partition, expressions=[part_list])
120
-
121
- def _parse_partition_by_opt_range(
122
- self,
123
- ) -> exp.PartitionedByProperty | exp.PartitionByRangeProperty | exp.PartitionByListProperty:
124
- if self._match_text_seq("LIST"):
125
- return self.expression(
126
- exp.PartitionByListProperty,
127
- partition_expressions=self._parse_wrapped_id_vars(),
128
- create_expressions=self._parse_wrapped_csv(
129
- self._parse_partition_definition_list
130
- ),
131
- )
132
-
133
- if not self._match_text_seq("RANGE"):
134
- return super()._parse_partitioned_by()
135
-
136
- partition_expressions = self._parse_wrapped_id_vars()
137
- self._match_l_paren()
138
-
139
- if self._match_text_seq("FROM", advance=False):
140
- create_expressions = self._parse_csv(self._parse_partitioning_granularity_dynamic)
141
- elif self._match_text_seq("PARTITION", advance=False):
142
- create_expressions = self._parse_csv(self._parse_partition_definition)
143
- else:
144
- create_expressions = None
145
-
146
- self._match_r_paren()
147
-
148
- return self.expression(
149
- exp.PartitionByRangeProperty,
150
- partition_expressions=partition_expressions,
151
- create_expressions=create_expressions,
152
- )
153
-
154
133
  def _parse_build_property(self) -> exp.BuildProperty:
155
134
  return self.expression(exp.BuildProperty, this=self._parse_var(upper=True))
156
135
 
@@ -178,6 +157,7 @@ class Doris(MySQL):
178
157
  VARCHAR_REQUIRES_SIZE = False
179
158
  WITH_PROPERTIES_PREFIX = "PROPERTIES"
180
159
  RENAME_TABLE_WITH_DB = False
160
+ UPDATE_STATEMENT_SUPPORTS_FROM = True
181
161
 
182
162
  TYPE_MAPPING = {
183
163
  **MySQL.Generator.TYPE_MAPPING,
@@ -189,11 +169,8 @@ class Doris(MySQL):
189
169
  PROPERTIES_LOCATION = {
190
170
  **MySQL.Generator.PROPERTIES_LOCATION,
191
171
  exp.UniqueKeyProperty: exp.Properties.Location.POST_SCHEMA,
192
- exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA,
193
- exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA,
194
172
  exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
195
173
  exp.BuildProperty: exp.Properties.Location.POST_SCHEMA,
196
- exp.RefreshTriggerProperty: exp.Properties.Location.POST_SCHEMA,
197
174
  }
198
175
 
199
176
  CAST_MAPPING = {}
@@ -720,12 +697,6 @@ class Doris(MySQL):
720
697
 
721
698
  return super().uniquekeyproperty_sql(expression)
722
699
 
723
- def partition_sql(self, expression: exp.Partition) -> str:
724
- parent = expression.parent
725
- if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)):
726
- return ", ".join(self.sql(e) for e in expression.expressions)
727
- return super().partition_sql(expression)
728
-
729
700
  def partitionrange_sql(self, expression: exp.PartitionRange) -> str:
730
701
  name = self.sql(expression, "this")
731
702
  values = expression.expressions
@@ -759,31 +730,11 @@ class Doris(MySQL):
759
730
 
760
731
  return f"FROM ({start}) TO ({end}) {interval}"
761
732
 
762
- def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str:
763
- partition_expressions = self.expressions(
764
- expression, key="partition_expressions", indent=False
765
- )
766
- create_sql = self.expressions(expression, key="create_expressions", indent=False)
767
- return f"PARTITION BY RANGE ({partition_expressions}) ({create_sql})"
768
-
769
- def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str:
770
- partition_expressions = self.expressions(
771
- expression, key="partition_expressions", indent=False
772
- )
773
- create_sql = self.expressions(expression, key="create_expressions", indent=False)
774
- return f"PARTITION BY LIST ({partition_expressions}) ({create_sql})"
775
-
776
- def partitionlist_sql(self, expression: exp.PartitionList) -> str:
777
- name = self.sql(expression, "this")
778
- values = self.expressions(expression, indent=False)
779
- return f"PARTITION {name} VALUES IN ({values})"
780
-
781
733
  def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:
782
- node = expression.this
783
- if isinstance(node, exp.Schema):
784
- parts = ", ".join(self.sql(e) for e in node.expressions)
785
- return f"PARTITION BY ({parts})"
786
- return f"PARTITION BY ({self.sql(node)})"
734
+ this = expression.this
735
+ if isinstance(this, exp.Schema):
736
+ return f"PARTITION BY ({self.expressions(this, flat=True)})"
737
+ return f"PARTITION BY ({self.sql(this)})"
787
738
 
788
739
  def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
789
740
  """Override table_sql to avoid AS keyword in UPDATE and DELETE statements."""
@@ -791,6 +742,3 @@ class Doris(MySQL):
791
742
  if not isinstance(ancestor, exp.Select):
792
743
  sep = " "
793
744
  return super().table_sql(expression, sep=sep)
794
-
795
- def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str:
796
- return super().alterrename_sql(expression, include_to=False)
sqlglot/dialects/druid.py CHANGED
@@ -17,4 +17,5 @@ class Druid(Dialect):
17
17
  **generator.Generator.TRANSFORMS,
18
18
  exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP",
19
19
  exp.Mod: rename_func("MOD"),
20
+ exp.Array: lambda self, e: f"ARRAY[{self.expressions(e)}]",
20
21
  }