sqlglot 27.27.0__py3-none-any.whl → 28.4.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 (68) hide show
  1. sqlglot/__init__.py +1 -0
  2. sqlglot/__main__.py +6 -4
  3. sqlglot/_version.py +2 -2
  4. sqlglot/dialects/bigquery.py +118 -279
  5. sqlglot/dialects/clickhouse.py +73 -5
  6. sqlglot/dialects/databricks.py +38 -1
  7. sqlglot/dialects/dialect.py +354 -275
  8. sqlglot/dialects/dremio.py +4 -1
  9. sqlglot/dialects/duckdb.py +754 -25
  10. sqlglot/dialects/exasol.py +243 -10
  11. sqlglot/dialects/hive.py +8 -8
  12. sqlglot/dialects/mysql.py +14 -4
  13. sqlglot/dialects/oracle.py +29 -0
  14. sqlglot/dialects/postgres.py +60 -26
  15. sqlglot/dialects/presto.py +47 -16
  16. sqlglot/dialects/redshift.py +16 -0
  17. sqlglot/dialects/risingwave.py +3 -0
  18. sqlglot/dialects/singlestore.py +12 -3
  19. sqlglot/dialects/snowflake.py +239 -218
  20. sqlglot/dialects/spark.py +15 -4
  21. sqlglot/dialects/spark2.py +11 -48
  22. sqlglot/dialects/sqlite.py +10 -0
  23. sqlglot/dialects/starrocks.py +3 -0
  24. sqlglot/dialects/teradata.py +5 -8
  25. sqlglot/dialects/trino.py +6 -0
  26. sqlglot/dialects/tsql.py +61 -22
  27. sqlglot/diff.py +4 -2
  28. sqlglot/errors.py +69 -0
  29. sqlglot/executor/__init__.py +5 -10
  30. sqlglot/executor/python.py +1 -29
  31. sqlglot/expressions.py +637 -100
  32. sqlglot/generator.py +160 -43
  33. sqlglot/helper.py +2 -44
  34. sqlglot/lineage.py +10 -4
  35. sqlglot/optimizer/annotate_types.py +247 -140
  36. sqlglot/optimizer/canonicalize.py +6 -1
  37. sqlglot/optimizer/eliminate_joins.py +1 -1
  38. sqlglot/optimizer/eliminate_subqueries.py +2 -2
  39. sqlglot/optimizer/merge_subqueries.py +5 -5
  40. sqlglot/optimizer/normalize.py +20 -13
  41. sqlglot/optimizer/normalize_identifiers.py +17 -3
  42. sqlglot/optimizer/optimizer.py +4 -0
  43. sqlglot/optimizer/pushdown_predicates.py +1 -1
  44. sqlglot/optimizer/qualify.py +18 -10
  45. sqlglot/optimizer/qualify_columns.py +122 -275
  46. sqlglot/optimizer/qualify_tables.py +128 -76
  47. sqlglot/optimizer/resolver.py +374 -0
  48. sqlglot/optimizer/scope.py +27 -16
  49. sqlglot/optimizer/simplify.py +1075 -959
  50. sqlglot/optimizer/unnest_subqueries.py +12 -2
  51. sqlglot/parser.py +296 -170
  52. sqlglot/planner.py +2 -2
  53. sqlglot/schema.py +15 -4
  54. sqlglot/tokens.py +42 -7
  55. sqlglot/transforms.py +77 -22
  56. sqlglot/typing/__init__.py +316 -0
  57. sqlglot/typing/bigquery.py +376 -0
  58. sqlglot/typing/hive.py +12 -0
  59. sqlglot/typing/presto.py +24 -0
  60. sqlglot/typing/snowflake.py +505 -0
  61. sqlglot/typing/spark2.py +58 -0
  62. sqlglot/typing/tsql.py +9 -0
  63. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/METADATA +2 -2
  64. sqlglot-28.4.0.dist-info/RECORD +92 -0
  65. sqlglot-27.27.0.dist-info/RECORD +0 -84
  66. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/WHEEL +0 -0
  67. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/licenses/LICENSE +0 -0
  68. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/top_level.txt +0 -0
@@ -98,6 +98,7 @@ class Scope:
98
98
  self._selected_sources = None
99
99
  self._columns = None
100
100
  self._external_columns = None
101
+ self._local_columns = None
101
102
  self._join_hints = None
102
103
  self._pivots = None
103
104
  self._references = None
@@ -137,7 +138,7 @@ class Scope:
137
138
 
138
139
  if isinstance(node, exp.Dot) and node.is_star:
139
140
  self._stars.append(node)
140
- elif isinstance(node, exp.Column):
141
+ elif isinstance(node, exp.Column) and not isinstance(node, exp.Pseudocolumn):
141
142
  if isinstance(node.this, exp.Star):
142
143
  self._stars.append(node)
143
144
  else:
@@ -156,7 +157,7 @@ class Scope:
156
157
  self._ctes.append(node)
157
158
  elif _is_derived_table(node) and _is_from_or_join(node):
158
159
  self._derived_tables.append(node)
159
- elif isinstance(node, exp.UNWRAPPED_QUERIES):
160
+ elif isinstance(node, exp.UNWRAPPED_QUERIES) and not _is_from_or_join(node):
160
161
  self._subqueries.append(node)
161
162
  elif isinstance(node, exp.TableColumn):
162
163
  self._table_columns.append(node)
@@ -308,7 +309,7 @@ class Scope:
308
309
  or column.name not in named_selects
309
310
  )
310
311
  )
311
- or (isinstance(ancestor, exp.Star) and not column.arg_key == "except")
312
+ or (isinstance(ancestor, exp.Star) and not column.arg_key == "except_")
312
313
  ):
313
314
  self._columns.append(column)
314
315
 
@@ -372,8 +373,7 @@ class Scope:
372
373
  Columns that appear to reference sources in outer scopes.
373
374
 
374
375
  Returns:
375
- list[exp.Column]: Column instances that don't reference
376
- sources in the current scope.
376
+ list[exp.Column]: Column instances that don't reference sources in the current scope.
377
377
  """
378
378
  if self._external_columns is None:
379
379
  if isinstance(self.expression, exp.SetOperation):
@@ -383,12 +383,25 @@ class Scope:
383
383
  self._external_columns = [
384
384
  c
385
385
  for c in self.columns
386
- if c.table not in self.selected_sources
387
- and c.table not in self.semi_or_anti_join_tables
386
+ if c.table not in self.sources and c.table not in self.semi_or_anti_join_tables
388
387
  ]
389
388
 
390
389
  return self._external_columns
391
390
 
391
+ @property
392
+ def local_columns(self):
393
+ """
394
+ Columns in this scope that are not external.
395
+
396
+ Returns:
397
+ list[exp.Column]: Column instances that reference sources in the current scope.
398
+ """
399
+ if self._local_columns is None:
400
+ external_columns = set(self.external_columns)
401
+ self._local_columns = [c for c in self.columns if c not in external_columns]
402
+
403
+ return self._local_columns
404
+
392
405
  @property
393
406
  def unqualified_columns(self):
394
407
  """
@@ -472,8 +485,9 @@ class Scope:
472
485
 
473
486
  def rename_source(self, old_name, new_name):
474
487
  """Rename a source in this scope"""
475
- columns = self.sources.pop(old_name or "", [])
476
- self.sources[new_name] = columns
488
+ old_name = old_name or ""
489
+ if old_name in self.sources:
490
+ self.sources[new_name] = self.sources.pop(old_name)
477
491
 
478
492
  def add_source(self, name, source):
479
493
  """Add a source to this scope"""
@@ -663,7 +677,7 @@ def _traverse_ctes(scope):
663
677
 
664
678
  # if the scope is a recursive cte, it must be in the form of base_case UNION recursive.
665
679
  # thus the recursive scope is the first section of the union.
666
- with_ = scope.expression.args.get("with")
680
+ with_ = scope.expression.args.get("with_")
667
681
  if with_ and with_.recursive:
668
682
  union = cte.this
669
683
 
@@ -720,7 +734,7 @@ def _traverse_tables(scope):
720
734
 
721
735
  # Traverse FROMs, JOINs, and LATERALs in the order they are defined
722
736
  expressions = []
723
- from_ = scope.expression.args.get("from")
737
+ from_ = scope.expression.args.get("from_")
724
738
  if from_:
725
739
  expressions.append(from_.this)
726
740
 
@@ -821,7 +835,7 @@ def _traverse_udtfs(scope):
821
835
 
822
836
  sources = {}
823
837
  for expression in expressions:
824
- if _is_derived_table(expression):
838
+ if isinstance(expression, exp.Subquery):
825
839
  top = None
826
840
  for child_scope in _traverse_scope(
827
841
  scope.branch(
@@ -870,10 +884,7 @@ def walk_in_scope(expression, bfs=True, prune=None):
870
884
 
871
885
  if (
872
886
  isinstance(node, exp.CTE)
873
- or (
874
- isinstance(node.parent, (exp.From, exp.Join, exp.Subquery))
875
- and _is_derived_table(node)
876
- )
887
+ or (isinstance(node.parent, (exp.From, exp.Join)) and _is_derived_table(node))
877
888
  or (isinstance(node.parent, exp.UDTF) and isinstance(node, exp.Query))
878
889
  or isinstance(node, exp.UNWRAPPED_QUERIES)
879
890
  ):