sqlglot 27.19.0__py3-none-any.whl → 27.20.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.
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.19.0'
32
- __version_tuple__ = version_tuple = (27, 19, 0)
31
+ __version__ = version = '27.20.0'
32
+ __version_tuple__ = version_tuple = (27, 20, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -543,6 +543,7 @@ class Snowflake(Dialect):
543
543
  exp.DataType.Type.VARCHAR: {
544
544
  *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.VARCHAR],
545
545
  exp.Base64DecodeString,
546
+ exp.TryBase64DecodeString,
546
547
  exp.Base64Encode,
547
548
  exp.DecompressString,
548
549
  exp.MD5,
@@ -553,6 +554,7 @@ class Snowflake(Dialect):
553
554
  exp.Collate,
554
555
  exp.Collation,
555
556
  exp.HexDecodeString,
557
+ exp.TryHexDecodeString,
556
558
  exp.HexEncode,
557
559
  exp.Initcap,
558
560
  exp.RegexpExtract,
@@ -561,12 +563,16 @@ class Snowflake(Dialect):
561
563
  exp.Replace,
562
564
  exp.SHA,
563
565
  exp.SHA2,
566
+ exp.Soundex,
564
567
  exp.Space,
568
+ exp.SplitPart,
565
569
  exp.Uuid,
566
570
  },
567
571
  exp.DataType.Type.BINARY: {
568
572
  *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.BINARY],
569
573
  exp.Base64DecodeBinary,
574
+ exp.TryBase64DecodeBinary,
575
+ exp.TryHexDecodeBinary,
570
576
  exp.Compress,
571
577
  exp.DecompressBinary,
572
578
  exp.MD5Digest,
@@ -586,6 +592,9 @@ class Snowflake(Dialect):
586
592
  exp.ParseUrl,
587
593
  exp.ParseIp,
588
594
  },
595
+ exp.DataType.Type.DECIMAL: {
596
+ exp.RegexpCount,
597
+ },
589
598
  }
590
599
 
591
600
  ANNOTATORS = {
@@ -607,6 +616,9 @@ class Snowflake(Dialect):
607
616
  },
608
617
  exp.ConcatWs: lambda self, e: self._annotate_by_args(e, "expressions"),
609
618
  exp.Reverse: _annotate_reverse,
619
+ exp.RegexpCount: lambda self, e: self._annotate_with_type(
620
+ e, exp.DataType.build("NUMBER", dialect="snowflake")
621
+ ),
610
622
  }
611
623
 
612
624
  TIME_MAPPING = {
@@ -793,6 +805,7 @@ class Snowflake(Dialect):
793
805
  FUNCTION_PARSERS = {
794
806
  **parser.Parser.FUNCTION_PARSERS,
795
807
  "DATE_PART": lambda self: self._parse_date_part(),
808
+ "DIRECTORY": lambda self: self._parse_directory(),
796
809
  "OBJECT_CONSTRUCT_KEEP_NULL": lambda self: self._parse_json_object(),
797
810
  "LISTAGG": lambda self: self._parse_string_agg(),
798
811
  "SEMANTIC_VIEW": lambda self: self._parse_semantic_view(),
@@ -902,6 +915,14 @@ class Snowflake(Dialect):
902
915
  ),
903
916
  }
904
917
 
918
+ def _parse_directory(self) -> exp.DirectoryStage:
919
+ table = self._parse_table_parts()
920
+
921
+ if isinstance(table, exp.Table):
922
+ table = table.this
923
+
924
+ return self.expression(exp.DirectoryStage, this=table)
925
+
905
926
  def _parse_use(self) -> exp.Use:
906
927
  if self._match_text_seq("SECONDARY", "ROLES"):
907
928
  this = self._match_texts(("ALL", "NONE")) and exp.var(self._prev.text.upper())
@@ -342,3 +342,12 @@ class SQLite(Dialect):
342
342
 
343
343
  def respectnulls_sql(self, expression: exp.RespectNulls) -> str:
344
344
  return self.sql(expression.this)
345
+
346
+ def windowspec_sql(self, expression: exp.WindowSpec) -> str:
347
+ if (
348
+ expression.text("kind").upper() == "RANGE"
349
+ and expression.text("start").upper() == "CURRENT ROW"
350
+ ):
351
+ return "RANGE CURRENT ROW"
352
+
353
+ return super().windowspec_sql(expression)
@@ -32,6 +32,7 @@ def st_distance_sphere(self, expression: exp.StDistance) -> str:
32
32
 
33
33
  class StarRocks(MySQL):
34
34
  STRICT_JSON_PATH_SYNTAX = False
35
+ INDEX_OFFSET = 1
35
36
 
36
37
  class Tokenizer(MySQL.Tokenizer):
37
38
  KEYWORDS = {
@@ -49,6 +50,7 @@ class StarRocks(MySQL):
49
50
  "DATE_DIFF": lambda args: exp.DateDiff(
50
51
  this=seq_get(args, 1), expression=seq_get(args, 2), unit=seq_get(args, 0)
51
52
  ),
53
+ "ARRAY_FLATTEN": exp.Flatten.from_arg_list,
52
54
  "REGEXP": exp.RegexpLike.from_arg_list,
53
55
  }
54
56
 
@@ -152,6 +154,7 @@ class StarRocks(MySQL):
152
154
  exp.DateDiff: lambda self, e: self.func(
153
155
  "DATE_DIFF", unit_to_str(e), e.this, e.expression
154
156
  ),
157
+ exp.Flatten: rename_func("ARRAY_FLATTEN"),
155
158
  exp.JSONExtractScalar: arrow_json_extract_sql,
156
159
  exp.JSONExtract: arrow_json_extract_sql,
157
160
  exp.Property: property_sql,
sqlglot/expressions.py CHANGED
@@ -120,19 +120,43 @@ class Expression(metaclass=_Expression):
120
120
  def __eq__(self, other) -> bool:
121
121
  return type(self) is type(other) and hash(self) == hash(other)
122
122
 
123
- @property
124
- def hashable_args(self) -> t.Any:
125
- return frozenset(
126
- (k, tuple(_norm_arg(a) for a in v) if type(v) is list else _norm_arg(v))
127
- for k, v in self.args.items()
128
- if not (v is None or v is False or (type(v) is list and not v))
129
- )
130
-
131
123
  def __hash__(self) -> int:
132
- if self._hash is not None:
133
- return self._hash
134
-
135
- return hash((self.__class__, self.hashable_args))
124
+ if self._hash is None:
125
+ nodes = []
126
+ queue = deque([self])
127
+
128
+ while queue:
129
+ node = queue.popleft()
130
+ nodes.append(node)
131
+
132
+ for v in node.iter_expressions():
133
+ if v._hash is None:
134
+ queue.append(v)
135
+
136
+ for node in reversed(nodes):
137
+ hash_ = hash(node.key)
138
+ t = type(node)
139
+
140
+ if t is Literal or t is Identifier:
141
+ for k, v in sorted(node.args.items()):
142
+ if v:
143
+ hash_ = hash((hash_, k, v))
144
+ else:
145
+ for k, v in sorted(node.args.items()):
146
+ t = type(v)
147
+
148
+ if t is list:
149
+ for x in v:
150
+ if x is not None and x is not False:
151
+ hash_ = hash((hash_, k, x.lower() if type(x) is str else x))
152
+ else:
153
+ hash_ = hash((hash_, k))
154
+ elif v is not None and v is not False:
155
+ hash_ = hash((hash_, k, v.lower() if t is str else v))
156
+
157
+ node._hash = hash_
158
+ assert self._hash
159
+ return self._hash
136
160
 
137
161
  def __reduce__(self) -> t.Tuple[t.Callable, t.Tuple[t.List[t.Dict[str, t.Any]]]]:
138
162
  from sqlglot.serde import dump, load
@@ -369,6 +393,12 @@ class Expression(metaclass=_Expression):
369
393
  overwrite: assuming an index is given, this determines whether to overwrite the
370
394
  list entry instead of only inserting a new value (i.e., like list.insert).
371
395
  """
396
+ expression: t.Optional[Expression] = self
397
+
398
+ while expression and expression._hash is not None:
399
+ expression._hash = None
400
+ expression = expression.parent
401
+
372
402
  if index is not None:
373
403
  expressions = self.args.get(arg_key) or []
374
404
 
@@ -2235,10 +2265,14 @@ class Prior(Expression):
2235
2265
 
2236
2266
 
2237
2267
  class Directory(Expression):
2238
- # https://spark.apache.org/docs/3.0.0-preview/sql-ref-syntax-dml-insert-overwrite-directory-hive.html
2239
2268
  arg_types = {"this": True, "local": False, "row_format": False}
2240
2269
 
2241
2270
 
2271
+ # https://docs.snowflake.com/en/user-guide/data-load-dirtables-query
2272
+ class DirectoryStage(Expression):
2273
+ pass
2274
+
2275
+
2242
2276
  class ForeignKey(Expression):
2243
2277
  arg_types = {
2244
2278
  "expressions": False,
@@ -2298,10 +2332,6 @@ class Identifier(Expression):
2298
2332
  def quoted(self) -> bool:
2299
2333
  return bool(self.args.get("quoted"))
2300
2334
 
2301
- @property
2302
- def hashable_args(self) -> t.Any:
2303
- return (self.this, self.quoted)
2304
-
2305
2335
  @property
2306
2336
  def output_name(self) -> str:
2307
2337
  return self.name
@@ -2536,10 +2566,6 @@ class LimitOptions(Expression):
2536
2566
  class Literal(Condition):
2537
2567
  arg_types = {"this": True, "is_string": True}
2538
2568
 
2539
- @property
2540
- def hashable_args(self) -> t.Any:
2541
- return (self.this, self.args.get("is_string"))
2542
-
2543
2569
  @classmethod
2544
2570
  def number(cls, number) -> Literal:
2545
2571
  return cls(this=str(number), is_string=False)
@@ -6427,14 +6453,36 @@ class Base64DecodeBinary(Func):
6427
6453
  arg_types = {"this": True, "alphabet": False}
6428
6454
 
6429
6455
 
6456
+ # https://docs.snowflake.com/en/sql-reference/functions/base64_decode_string
6430
6457
  class Base64DecodeString(Func):
6431
6458
  arg_types = {"this": True, "alphabet": False}
6432
6459
 
6433
6460
 
6461
+ # https://docs.snowflake.com/en/sql-reference/functions/base64_encode
6434
6462
  class Base64Encode(Func):
6435
6463
  arg_types = {"this": True, "max_line_length": False, "alphabet": False}
6436
6464
 
6437
6465
 
6466
+ # https://docs.snowflake.com/en/sql-reference/functions/try_base64_decode_binary
6467
+ class TryBase64DecodeBinary(Func):
6468
+ arg_types = {"this": True, "alphabet": False}
6469
+
6470
+
6471
+ # https://docs.snowflake.com/en/sql-reference/functions/try_base64_decode_string
6472
+ class TryBase64DecodeString(Func):
6473
+ arg_types = {"this": True, "alphabet": False}
6474
+
6475
+
6476
+ # https://docs.snowflake.com/en/sql-reference/functions/try_hex_decode_binary
6477
+ class TryHexDecodeBinary(Func):
6478
+ pass
6479
+
6480
+
6481
+ # https://docs.snowflake.com/en/sql-reference/functions/try_hex_decode_string
6482
+ class TryHexDecodeString(Func):
6483
+ pass
6484
+
6485
+
6438
6486
  # https://trino.io/docs/current/functions/datetime.html#from_iso8601_timestamp
6439
6487
  class FromISO8601Timestamp(Func):
6440
6488
  _sql_names = ["FROM_ISO8601_TIMESTAMP"]
@@ -7249,6 +7297,15 @@ class RegexpSplit(Func):
7249
7297
  arg_types = {"this": True, "expression": True, "limit": False}
7250
7298
 
7251
7299
 
7300
+ class RegexpCount(Func):
7301
+ arg_types = {
7302
+ "this": True,
7303
+ "expression": True,
7304
+ "position": False,
7305
+ "parameters": False,
7306
+ }
7307
+
7308
+
7252
7309
  class Repeat(Func):
7253
7310
  arg_types = {"this": True, "times": True}
7254
7311
 
@@ -7712,10 +7769,6 @@ class TableColumn(Expression):
7712
7769
  pass
7713
7770
 
7714
7771
 
7715
- def _norm_arg(arg):
7716
- return arg.lower() if type(arg) is str else arg
7717
-
7718
-
7719
7772
  ALL_FUNCTIONS = subclasses(__name__, Func, (AggFunc, Anonymous, Func))
7720
7773
  FUNCTION_BY_NAME = {name: func for func in ALL_FUNCTIONS for name in func.sql_names()}
7721
7774
 
sqlglot/generator.py CHANGED
@@ -5334,3 +5334,6 @@ class Generator(metaclass=_Generator):
5334
5334
  def modelattribute_sql(self, expression: exp.ModelAttribute) -> str:
5335
5335
  self.unsupported("The model!attribute syntax is not supported")
5336
5336
  return ""
5337
+
5338
+ def directorystage_sql(self, expression: exp.DirectoryStage) -> str:
5339
+ return self.func("DIRECTORY", expression.this)
sqlglot/helper.py CHANGED
@@ -226,31 +226,13 @@ def while_changing(expression: Expression, func: t.Callable[[Expression], E]) ->
226
226
  Returns:
227
227
  The transformed expression.
228
228
  """
229
- end_hash: t.Optional[int] = None
230
229
 
231
230
  while True:
232
- # No need to walk the AST– we've already cached the hashes in the previous iteration
233
- if end_hash is None:
234
- for n in reversed(tuple(expression.walk())):
235
- n._hash = hash(n)
236
-
237
231
  start_hash = hash(expression)
238
232
  expression = func(expression)
239
-
240
- expression_nodes = tuple(expression.walk())
241
-
242
- # Uncache previous caches so we can recompute them
243
- for n in reversed(expression_nodes):
244
- n._hash = None
245
- n._hash = hash(n)
246
-
247
233
  end_hash = hash(expression)
248
234
 
249
235
  if start_hash == end_hash:
250
- # ... and reset the hash so we don't risk it becoming out of date if a mutation happens
251
- for n in expression_nodes:
252
- n._hash = None
253
-
254
236
  break
255
237
 
256
238
  return expression
sqlglot/parser.py CHANGED
@@ -1411,7 +1411,7 @@ class Parser(metaclass=_Parser):
1411
1411
 
1412
1412
  VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1413
1413
 
1414
- WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1414
+ WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.RANGE, TokenType.ROWS}
1415
1415
  WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1416
1416
  WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1417
1417
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.19.0
3
+ Version: 27.20.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
@@ -89,12 +89,14 @@ pip3 install "sqlglot[rs]"
89
89
  Or with a local checkout:
90
90
 
91
91
  ```
92
+ # Optionally prefix with UV=1 to use uv for the installation
92
93
  make install
93
94
  ```
94
95
 
95
96
  Requirements for development (optional):
96
97
 
97
98
  ```
99
+ # Optionally prefix with UV=1 to use uv for the installation
98
100
  make install-dev
99
101
  ```
100
102
 
@@ -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=wVbD9GMknBXDREyMG-Yx-Nw3OZVxyzYGofDpSiCozV4,708
4
+ sqlglot/_version.py,sha256=W-gB5oTd5rWsYZXOhmfTMtDc_wY3Dl-VUjAJOtLX5qo,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=gR0XWI066giI1oStYhmswO7FY_pA0twxmc1P2XTo1tU,258468
8
- sqlglot/generator.py,sha256=ZHFzi6_EOJl5V-dnz71QJOIwtxj66oJdF6tUQoxBpck,226436
9
- sqlglot/helper.py,sha256=9nZjFVRBtMKFC3EdzpDQ6jkazFO19po6BF8xHiNGZIo,15111
7
+ sqlglot/expressions.py,sha256=jQs1lR1Nh5nmXYEjaYVakXgMijNgaWmh1fsOOZ10imE,260181
8
+ sqlglot/generator.py,sha256=KyFuqWQpawTj3rWV7ONKO4euqVTzV8aFU3desDu8fso,226565
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=4UXHIDwR9mdbN5C7PVMffheR-cj3ipVJqIIK8W-o5ac,337436
12
+ sqlglot/parser.py,sha256=bVpU72Ace-vGXkiqoojKXFGRpXxProri31Q3WP1TQuE,337453
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
@@ -42,12 +42,12 @@ sqlglot/dialects/prql.py,sha256=fwN-SPEGx-drwf1K0U2MByN-PkW3C_rOgQ3xeJeychg,7908
42
42
  sqlglot/dialects/redshift.py,sha256=FIwtP3yEg-way9pa32kxCJc6IaFkHVIvgYKZA-Ilmi0,15919
43
43
  sqlglot/dialects/risingwave.py,sha256=BqWwW1iT_OIVMwfRamaww79snnBwIgCfr22Go-ggO68,3289
44
44
  sqlglot/dialects/singlestore.py,sha256=0QqNYOucNklPQuyeGcsisLI97qPGx_RfWKOFarJz2qw,61711
45
- sqlglot/dialects/snowflake.py,sha256=D9GlZtIDLU_aqHWvGQUC8AS-U94WPBS_qEzErIJIoWY,78746
45
+ sqlglot/dialects/snowflake.py,sha256=_SXsdDPNopi78MT7R_YHZHoY6WDB_tZ6pVvk5VcJaYQ,79485
46
46
  sqlglot/dialects/solr.py,sha256=pydnl4ml-3M1Fc4ALm6cMVO9h-5EtqZxPZH_91Nz1Ss,617
47
47
  sqlglot/dialects/spark.py,sha256=PzyhkelDzbCMgJ3RVHD6yyzLIFp9NdZfwVas5IymowM,10147
48
48
  sqlglot/dialects/spark2.py,sha256=qz36FT9k4iuiqboRpyG4VpKGkPR0P2fifmqgZ9gNUEU,14851
49
- sqlglot/dialects/sqlite.py,sha256=zzXEbnaLjJeg6hPLHricjpfSkuf8tpXECnjcHtoqIbw,13263
50
- sqlglot/dialects/starrocks.py,sha256=2gav0PSNgRdAGXzawdznZliBpglJoQ0wBxPI7ZIMsRw,11314
49
+ sqlglot/dialects/sqlite.py,sha256=FuEDDyKZeeWVblknhFSMX7dNoS-ci5ktXpSXZeBK5xA,13592
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
@@ -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.19.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
81
- sqlglot-27.19.0.dist-info/METADATA,sha256=yaLkwFBKI3tGRmU2ayVsF3uEDoRgBLryVjdzeePUW4M,20703
82
- sqlglot-27.19.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
83
- sqlglot-27.19.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
84
- sqlglot-27.19.0.dist-info/RECORD,,
80
+ sqlglot-27.20.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
81
+ sqlglot-27.20.0.dist-info/METADATA,sha256=nO_Q85ybayInmXwdQV_wFMHF4kQSA0ujLlWo-H5r0I8,20825
82
+ sqlglot-27.20.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
83
+ sqlglot-27.20.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
84
+ sqlglot-27.20.0.dist-info/RECORD,,