sqlglot 26.27.1__py3-none-any.whl → 26.28.1__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.
sqlglot/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '26.27.1'
21
- __version_tuple__ = version_tuple = (26, 27, 1)
20
+ __version__ = version = '26.28.1'
21
+ __version_tuple__ = version_tuple = (26, 28, 1)
sqlglot/expressions.py CHANGED
@@ -51,8 +51,8 @@ class _Expression(type):
51
51
  def __new__(cls, clsname, bases, attrs):
52
52
  klass = super().__new__(cls, clsname, bases, attrs)
53
53
 
54
- # When an Expression class is created, its key is automatically set to be
55
- # the lowercase version of the class' name.
54
+ # When an Expression class is created, its key is automatically set
55
+ # to be the lowercase version of the class' name.
56
56
  klass.key = clsname.lower()
57
57
 
58
58
  # This is so that docstrings are not inherited in pdoc
@@ -758,6 +758,8 @@ def _traverse_tables(scope):
758
758
  expressions.extend(join.this for join in expression.args.get("joins") or [])
759
759
  continue
760
760
 
761
+ child_scope = None
762
+
761
763
  for child_scope in _traverse_scope(
762
764
  scope.branch(
763
765
  expression,
@@ -775,8 +777,9 @@ def _traverse_tables(scope):
775
777
  sources[expression.alias] = child_scope
776
778
 
777
779
  # append the final child_scope yielded
778
- scopes.append(child_scope)
779
- scope.table_scopes.append(child_scope)
780
+ if child_scope:
781
+ scopes.append(child_scope)
782
+ scope.table_scopes.append(child_scope)
780
783
 
781
784
  scope.sources.update(sources)
782
785
 
sqlglot/parser.py CHANGED
@@ -932,13 +932,14 @@ class Parser(metaclass=_Parser):
932
932
 
933
933
  PIPE_SYNTAX_TRANSFORM_PARSERS = {
934
934
  "SELECT": lambda self, query: self._parse_pipe_syntax_select(query),
935
- "WHERE": lambda self, query: self._parse_pipe_syntax_where(query),
935
+ "WHERE": lambda self, query: query.where(self._parse_where(), copy=False),
936
936
  "ORDER BY": lambda self, query: query.order_by(
937
937
  self._parse_order(), append=False, copy=False
938
938
  ),
939
939
  "LIMIT": lambda self, query: self._parse_pipe_syntax_limit(query),
940
- "OFFSET": lambda self, query: query.offset(self._parse_offset(), copy=False),
941
940
  "AGGREGATE": lambda self, query: self._parse_pipe_syntax_aggregate(query),
941
+ "PIVOT": lambda self, query: self._parse_pipe_syntax_pivot(query),
942
+ "UNPIVOT": lambda self, query: self._parse_pipe_syntax_pivot(query),
942
943
  }
943
944
 
944
945
  PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
@@ -8327,40 +8328,33 @@ class Parser(metaclass=_Parser):
8327
8328
  expression.update_positions(token)
8328
8329
  return expression
8329
8330
 
8330
- def _build_pipe_cte(self, query: exp.Query, expressions: t.List[exp.Expression]) -> exp.Query:
8331
- if query.selects:
8332
- self._pipe_cte_counter += 1
8333
- new_cte = f"__tmp{self._pipe_cte_counter}"
8334
-
8335
- # For `exp.Select`, generated CTEs are attached to its `with`
8336
- # For `exp.SetOperation`, generated CTEs are attached to the `with` of its LHS, accessed via `this`
8337
- with_ = (
8338
- query.args.get("with")
8339
- if isinstance(query, exp.Select)
8340
- else query.this.args.get("with")
8341
- )
8342
- ctes = with_.pop() if with_ else None
8331
+ def _build_pipe_cte(self, query: exp.Query, expressions: t.List[exp.Expression]) -> exp.Select:
8332
+ if not query.selects:
8333
+ query = query.select("*", copy=False)
8334
+
8335
+ self._pipe_cte_counter += 1
8336
+ new_cte = f"__tmp{self._pipe_cte_counter}"
8343
8337
 
8344
- new_select = exp.select(*expressions, copy=False).from_(new_cte, copy=False)
8345
- if ctes:
8346
- new_select.set("with", ctes)
8338
+ with_ = query.args.get("with")
8339
+ ctes = with_.pop() if with_ else None
8347
8340
 
8348
- return new_select.with_(new_cte, as_=query, copy=False)
8341
+ new_select = exp.select(*expressions, copy=False).from_(new_cte, copy=False)
8342
+ if ctes:
8343
+ new_select.set("with", ctes)
8349
8344
 
8350
- return query.select(*expressions, copy=False)
8345
+ return new_select.with_(new_cte, as_=query, copy=False)
8351
8346
 
8352
- def _parse_pipe_syntax_select(self, query: exp.Query) -> exp.Query:
8347
+ def _parse_pipe_syntax_select(self, query: exp.Select) -> exp.Select:
8353
8348
  select = self._parse_select()
8354
- if isinstance(select, exp.Select):
8355
- return self._build_pipe_cte(query, select.expressions)
8349
+ if not select:
8350
+ return query
8356
8351
 
8357
- return query
8352
+ if not query.selects:
8353
+ return self._build_pipe_cte(query.select(*select.expressions), [exp.Star()])
8358
8354
 
8359
- def _parse_pipe_syntax_where(self, query: exp.Query) -> exp.Query:
8360
- where = self._parse_where()
8361
- return query.where(where, copy=False)
8355
+ return self._build_pipe_cte(query, select.expressions)
8362
8356
 
8363
- def _parse_pipe_syntax_limit(self, query: exp.Query) -> exp.Query:
8357
+ def _parse_pipe_syntax_limit(self, query: exp.Select) -> exp.Select:
8364
8358
  limit = self._parse_limit()
8365
8359
  offset = self._parse_offset()
8366
8360
  if limit:
@@ -8371,6 +8365,7 @@ class Parser(metaclass=_Parser):
8371
8365
  curr_offset = query.args.get("offset")
8372
8366
  curr_offset = curr_offset.expression.to_py() if curr_offset else 0
8373
8367
  query.offset(exp.Literal.number(curr_offset + offset.expression.to_py()), copy=False)
8368
+
8374
8369
  return query
8375
8370
 
8376
8371
  def _parse_pipe_syntax_aggregate_fields(self) -> t.Optional[exp.Expression]:
@@ -8386,8 +8381,8 @@ class Parser(metaclass=_Parser):
8386
8381
  return this
8387
8382
 
8388
8383
  def _parse_pipe_syntax_aggregate_group_order_by(
8389
- self, query: exp.Query, group_by_exists: bool = True
8390
- ) -> exp.Query:
8384
+ self, query: exp.Select, group_by_exists: bool = True
8385
+ ) -> exp.Select:
8391
8386
  expr = self._parse_csv(self._parse_pipe_syntax_aggregate_fields)
8392
8387
  aggregates_or_groups, orders = [], []
8393
8388
  for element in expr:
@@ -8400,45 +8395,46 @@ class Parser(metaclass=_Parser):
8400
8395
  this = element
8401
8396
  aggregates_or_groups.append(this)
8402
8397
 
8403
- if group_by_exists and isinstance(query, exp.Select):
8398
+ if group_by_exists:
8404
8399
  query = query.select(*aggregates_or_groups, copy=False).group_by(
8405
8400
  *[projection.args.get("alias", projection) for projection in aggregates_or_groups],
8406
8401
  copy=False,
8407
8402
  )
8408
8403
  else:
8409
- query = query.select(*aggregates_or_groups, append=False, copy=False)
8404
+ query = query.select(*aggregates_or_groups, copy=False)
8410
8405
 
8411
8406
  if orders:
8412
8407
  return query.order_by(*orders, append=False, copy=False)
8413
8408
 
8414
8409
  return query
8415
8410
 
8416
- def _parse_pipe_syntax_aggregate(self, query: exp.Query) -> exp.Query:
8411
+ def _parse_pipe_syntax_aggregate(self, query: exp.Select) -> exp.Select:
8417
8412
  self._match_text_seq("AGGREGATE")
8418
8413
  query = self._parse_pipe_syntax_aggregate_group_order_by(query, group_by_exists=False)
8419
8414
 
8420
8415
  if self._match(TokenType.GROUP_BY) or (
8421
8416
  self._match_text_seq("GROUP", "AND") and self._match(TokenType.ORDER_BY)
8422
8417
  ):
8423
- return self._parse_pipe_syntax_aggregate_group_order_by(query)
8418
+ query = self._parse_pipe_syntax_aggregate_group_order_by(query)
8424
8419
 
8425
- return query
8420
+ return self._build_pipe_cte(query, [exp.Star()])
8426
8421
 
8427
8422
  def _parse_pipe_syntax_set_operator(
8428
8423
  self, query: t.Optional[exp.Query]
8429
- ) -> t.Optional[exp.Query]:
8424
+ ) -> t.Optional[exp.Select]:
8430
8425
  first_setop = self.parse_set_operation(this=query)
8431
8426
 
8432
8427
  if not first_setop or not query:
8433
8428
  return None
8434
8429
 
8435
- if not query.selects:
8436
- query.select("*", copy=False)
8437
-
8438
- this = first_setop.this.pop()
8430
+ first_setop.this.pop()
8439
8431
  distinct = first_setop.args.pop("distinct")
8440
8432
  setops = [first_setop.expression.pop(), *self._parse_expressions()]
8441
8433
 
8434
+ query = self._build_pipe_cte(query, [exp.Star()])
8435
+ with_ = query.args.get("with")
8436
+ ctes = with_.pop() if with_ else None
8437
+
8442
8438
  if isinstance(first_setop, exp.Union):
8443
8439
  query = query.union(*setops, distinct=distinct, copy=False, **first_setop.args)
8444
8440
  elif isinstance(first_setop, exp.Except):
@@ -8446,22 +8442,41 @@ class Parser(metaclass=_Parser):
8446
8442
  else:
8447
8443
  query = query.intersect(*setops, distinct=distinct, copy=False, **first_setop.args)
8448
8444
 
8449
- return self._build_pipe_cte(
8450
- query, [projection.args.get("alias", projection) for projection in this.expressions]
8451
- )
8445
+ query.set("with", ctes)
8446
+
8447
+ return self._build_pipe_cte(query, [exp.Star()])
8448
+
8449
+ def _parse_pipe_syntax_join(self, query: exp.Select) -> t.Optional[exp.Select]:
8450
+ join = self._parse_join()
8451
+ if not join:
8452
+ return None
8453
+
8454
+ return query.join(join, copy=False)
8452
8455
 
8453
- def _parse_pipe_syntax_query(self, query: exp.Query) -> t.Optional[exp.Query]:
8456
+ def _parse_pipe_syntax_pivot(self, query: exp.Select) -> exp.Select:
8457
+ pivots = self._parse_pivots()
8458
+ if not pivots:
8459
+ return query
8460
+
8461
+ from_ = query.args.get("from")
8462
+ if from_:
8463
+ from_.this.set("pivots", pivots)
8464
+
8465
+ return self._build_pipe_cte(query, [exp.Star()])
8466
+
8467
+ def _parse_pipe_syntax_query(self, query: exp.Select) -> t.Optional[exp.Select]:
8454
8468
  while self._match(TokenType.PIPE_GT):
8455
8469
  start = self._curr
8456
8470
  parser = self.PIPE_SYNTAX_TRANSFORM_PARSERS.get(self._curr.text.upper())
8457
8471
  if not parser:
8458
- set_op_query = self._parse_pipe_syntax_set_operator(query)
8459
- if not set_op_query:
8472
+ parsed_query = self._parse_pipe_syntax_set_operator(
8473
+ query
8474
+ ) or self._parse_pipe_syntax_join(query)
8475
+ if not parsed_query:
8460
8476
  self._retreat(start)
8461
8477
  self.raise_error(f"Unsupported pipe syntax operator: '{start.text.upper()}'.")
8462
8478
  break
8463
-
8464
- query = set_op_query
8479
+ query = parsed_query
8465
8480
  else:
8466
8481
  query = parser(self, query)
8467
8482
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 26.27.1
3
+ Version: 26.28.1
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License: MIT License
@@ -1,15 +1,15 @@
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=tGzmcwxazE8ZaUBuCO5phuigC0f9SB40km_TjYfnb90,515
4
+ sqlglot/_version.py,sha256=lTxpjPlB8VNbv3452Opk2GFByRI5SLtHItxl9sne84Q,515
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=HspDzfH5_xnGPUvMPcwtNmIHaLbIj_NGmBWcvm8qIKw,242992
7
+ sqlglot/expressions.py,sha256=oE7OmkFEstTWoPqM7yCls2I2JNyia8Spr-jVi3n77-A,242992
8
8
  sqlglot/generator.py,sha256=4iJ0BxkzinmosIhfhb34xjxaFpzw3Zo7fvmknaf5uRs,212432
9
9
  sqlglot/helper.py,sha256=9nZjFVRBtMKFC3EdzpDQ6jkazFO19po6BF8xHiNGZIo,15111
10
10
  sqlglot/jsonpath.py,sha256=dKdI3PNINNGimmSse2IIv-GbPN_3lXncXh_70QH7Lss,7664
11
11
  sqlglot/lineage.py,sha256=kXBDSErmZZluZx_kkrMj4MPEOAbkvcbX1tbOW7Bpl-U,15303
12
- sqlglot/parser.py,sha256=Jv02-ikrk8uqmYR4nxKgLUj704lIx1_ugXf-hShkZ8w,320240
12
+ sqlglot/parser.py,sha256=TksM9cVq6bbbyM0sgglcOb-p6_1_Xk6EPIS2Buj-048,320530
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
@@ -69,11 +69,11 @@ sqlglot/optimizer/pushdown_projections.py,sha256=7NoK5NAUVYVhs0YnYyo6WuXfaO-BShS
69
69
  sqlglot/optimizer/qualify.py,sha256=oAPfwub7dEkrlCrsptcJWpLya4BgKhN6M5SwIs_86LY,4002
70
70
  sqlglot/optimizer/qualify_columns.py,sha256=X2Iydssan_Fw84cd-mrzqxG3eRfRdpP6HVRofSbfHlg,40515
71
71
  sqlglot/optimizer/qualify_tables.py,sha256=5f5enBAh-bpNB9ewF97W9fx9h1TGXj1Ih5fncvH42sY,6486
72
- sqlglot/optimizer/scope.py,sha256=Fqz9GpBqO1GWzRAnqdflXXNz44ot_1JqVBC-DnYAU_E,30063
72
+ sqlglot/optimizer/scope.py,sha256=lZWJsR1k-vx1VdxOn0yvbF_LcviXbK357WlrgOLXGEs,30123
73
73
  sqlglot/optimizer/simplify.py,sha256=S0Blqg5Mq2KRRWhWz-Eivch9sBjBhg9fRJA6EdBzj2g,50704
74
74
  sqlglot/optimizer/unnest_subqueries.py,sha256=kzWUVDlxs8z9nmRx-8U-pHXPtVZhEIwkKqmKhr2QLvc,10908
75
- sqlglot-26.27.1.dist-info/licenses/LICENSE,sha256=AI3__mHZfOtzY3EluR_pIYBm3_pE7TbVx7qaHxoZ114,1065
76
- sqlglot-26.27.1.dist-info/METADATA,sha256=R_0FXBifra90Z576tjTOsln1IrNAgj-vTzJL1-izN_4,20732
77
- sqlglot-26.27.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- sqlglot-26.27.1.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
79
- sqlglot-26.27.1.dist-info/RECORD,,
75
+ sqlglot-26.28.1.dist-info/licenses/LICENSE,sha256=AI3__mHZfOtzY3EluR_pIYBm3_pE7TbVx7qaHxoZ114,1065
76
+ sqlglot-26.28.1.dist-info/METADATA,sha256=ElrNZkPPdEmAmU1gVJgndWkFCWlhnYqLLkGB4562Bd4,20732
77
+ sqlglot-26.28.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
+ sqlglot-26.28.1.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
79
+ sqlglot-26.28.1.dist-info/RECORD,,