Skip to content

Commit c03f441

Browse files
committed
Merge remote-tracking branch 'u/master' into HEAD
2 parents fc13bb0 + 984db6b commit c03f441

File tree

527 files changed

+4614
-2368
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

527 files changed

+4614
-2368
lines changed

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,6 @@
296296
[submodule "contrib/aws-c-compression"]
297297
path = contrib/aws-c-compression
298298
url = https://github.com/awslabs/aws-c-compression
299-
[submodule "contrib/aws-s2n-tls"]
300-
path = contrib/aws-s2n-tls
301-
url = https://github.com/ClickHouse/s2n-tls
302299
[submodule "contrib/crc32-vpmsum"]
303300
path = contrib/crc32-vpmsum
304301
url = https://github.com/antonblanchard/crc32-vpmsum.git

CHANGELOG.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,31 @@
1818
### <a id="255"></a> ClickHouse release 25.5, 2025-05-22
1919

2020
#### Backward Incompatible Change
21-
* Function `geoToH3` now accepts the input in the order (lat, lon, res) (which is common for other geometric functions). Users who wish to retain the previous result order (lon, lat, res) can set setting `geotoh3_lon_lat_input_order = true`. [#78852](https://github.com/ClickHouse/ClickHouse/pull/78852) ([Pratima Patel](https://github.com/pratimapatel2008)).
21+
* Function `geoToH3` now accepts the input in the order (lat, lon, res) (which is common for other geometric functions). Users who wish to retain the previous result order (lon, lat, res) can set setting `geotoh3_argument_order = 'lon_lat'`. [#78852](https://github.com/ClickHouse/ClickHouse/pull/78852) ([Pratima Patel](https://github.com/pratimapatel2008)).
2222
* Add a filesystem cache setting `allow_dynamic_cache_resize`, by default `false`, to allow dynamic resize of filesystem cache. Why: in certain environments (ClickHouse Cloud) all the scaling events happen through the restart of the process and we would love this feature to be explicitly disabled to have more control over the behaviour + as a safety measure. This PR is marked as backward incompatible, because in older versions dynamic cache resize worked by default without special setting. [#79148](https://github.com/ClickHouse/ClickHouse/pull/79148) ([Kseniia Sumarokova](https://github.com/kssenii)).
2323
* Removed support for legacy index types `annoy` and `usearch`. Both have been stubs for a long time, i.e. every attempt to use the legacy indexes returned an error anyways. If you still have `annoy` and `usearch` indexes, please drop them. [#79802](https://github.com/ClickHouse/ClickHouse/pull/79802) ([Robert Schulze](https://github.com/rschu1ze)).
2424
* Remove `format_alter_commands_with_parentheses` server setting. The setting was introduced and disabled by default in 24.2. It was enabled by default in 25.2. As there are no LTS versions that don't support the new format, we can remove the setting. [#79970](https://github.com/ClickHouse/ClickHouse/pull/79970) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)).
2525
* Enable `DeltaLake` storage `delta-kernel-rs` implementation by default. [#79541](https://github.com/ClickHouse/ClickHouse/pull/79541) ([Kseniia Sumarokova](https://github.com/kssenii)).
2626
* If reading from an `URL` involves multiple redirects, setting `enable_url_encoding` is correctly applied across all redirects in the chain. [#79563](https://github.com/ClickHouse/ClickHouse/pull/79563) ([Shankar Iyer](https://github.com/shankar-iyer)). Setting `enble_url_encoding` default value is now set to `false`. [#80088](https://github.com/ClickHouse/ClickHouse/pull/80088) ([Shankar Iyer](https://github.com/shankar-iyer)).
2727

2828
#### New Feature
29-
* New `Time`/`Time64` data types: `Time` (HHH:MM:SS) and `Time64` (HHH:MM:SS.`<fractional>`) and some basic cast functions and functions to interact with other data types. Also, changed the existing function's name toTime to toTimeWithFixedDate because the function toTime is required for the cast function. [#75735](https://github.com/ClickHouse/ClickHouse/pull/75735) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
30-
72459). [#76078](https://github.com/ClickHouse/ClickHouse/pull/76078) ([Dmitry Novik](https://github.com/novikd)).
31-
* Support scalar correlated subqueries in the WHERE clause. Closes [#6697](https://github.com/ClickHouse/ClickHouse/issues/6697). [#79600](https://github.com/ClickHouse/ClickHouse/pull/79600) ([Dmitry Novik](https://github.com/novikd)). Support correlated subqueries in the projection list in simple cases. [#79925](https://github.com/ClickHouse/ClickHouse/pull/79925) ([Dmitry Novik](https://github.com/novikd)). Now it covers 100% of TPC-H test suite.
29+
* Support scalar correlated subqueries in the WHERE clause. Closes [#6697](https://github.com/ClickHouse/ClickHouse/issues/6697). [#79600](https://github.com/ClickHouse/ClickHouse/pull/79600) ([Dmitry Novik](https://github.com/novikd)). Support correlated subqueries in the projection list in simple cases. [#79925](https://github.com/ClickHouse/ClickHouse/pull/79925) ([Dmitry Novik](https://github.com/novikd)). [#76078](https://github.com/ClickHouse/ClickHouse/pull/76078) ([Dmitry Novik](https://github.com/novikd)). Now it covers 100% of TPC-H test suite.
3230
* Vector search using the vector similarity index is now beta (from previously experimental). [#80164](https://github.com/ClickHouse/ClickHouse/pull/80164) ([Robert Schulze](https://github.com/rschu1ze)).
3331
* Support geo types in `Parquet` format. This closes [#75317](https://github.com/ClickHouse/ClickHouse/issues/75317). [#79777](https://github.com/ClickHouse/ClickHouse/pull/79777) ([scanhex12](https://github.com/scanhex12)).
3432
* New functions `sparseGrams`, `sparseGramsHashes`, `sparseGramsHashesUTF8`, `sparseGramsUTF8` for calculating "sparse-ngrams" - a robust algorithm for extracting substrings for indexing and search. [#79517](https://github.com/ClickHouse/ClickHouse/pull/79517) ([scanhex12](https://github.com/scanhex12)).
3533
* `clickhouse-local` (and its shorthand alias, `ch`) now use an implicit `FROM table` when there is input data for processing. This closes [#65023](https://github.com/ClickHouse/ClickHouse/issues/65023). Also enabled format inference in clickhouse-local if `--input-format` is not specified and it processes a regular file. [#79085](https://github.com/ClickHouse/ClickHouse/pull/79085) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
3634
* Add `stringBytesUniq` and `stringBytesEntropy` functions to search for possibly random or encrypted data. [#79350](https://github.com/ClickHouse/ClickHouse/pull/79350) ([Sachin Kumar Singh](https://github.com/sachinkumarsingh092)).
3735
* Added functions for encoding and decoding base32. [#79809](https://github.com/ClickHouse/ClickHouse/pull/79809) ([Joanna Hulboj](https://github.com/jh0x)).
3836
* Add `getServerSetting` and `getMergeTreeSetting` function. Closes #78318. [#78439](https://github.com/ClickHouse/ClickHouse/pull/78439) ([NamNguyenHoai](https://github.com/NamHoaiNguyen)).
39-
* Add `system.iceberg_history` table. [#78244](https://github.com/ClickHouse/ClickHouse/pull/78244) ([Smita Kulkarni](https://github.com/SmitaRKulkarni)).
4037
* Add new `iceberg_enable_version_hint` setting to leverage `version-hint.text` file. [#78594](https://github.com/ClickHouse/ClickHouse/pull/78594) ([Arnaud Briche](https://github.com/arnaudbriche)).
4138
* Gives the possibility to truncate specific tables from a database, filtered with the `LIKE` keyword. [#78597](https://github.com/ClickHouse/ClickHouse/pull/78597) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
4239
* Support `_part_starting_offset` virtual column in `MergeTree`-family tables. This column represents the cumulative row count of all preceding parts, calculated at query time based on the current part list. The cumulative values are retained throughout query execution and remain effective even after part pruning. Related internal logic has been refactored to support this behavior. [#79417](https://github.com/ClickHouse/ClickHouse/pull/79417) ([Amos Bird](https://github.com/amosbird)).
4340
* Add functions `divideOrNull`,`moduloOrNull`, `intDivOrNull`,`positiveModuloOrNull` to return NULL when right argument is zero. [#78276](https://github.com/ClickHouse/ClickHouse/pull/78276) ([kevinyhzou](https://github.com/KevinyhZou)).
44-
* TODO: WTF is that? Explain it in a way your gradma will understand. Support for Iceberg partition pruning bucket transform. [#79262](https://github.com/ClickHouse/ClickHouse/pull/79262) ([Daniil Ivanik](https://github.com/divanik)).
41+
* Add [`icebergHash`](https://iceberg.apache.org/spec/#appendix-b-32-bit-hash-requirements) and [`icebergBucket`](https://iceberg.apache.org/spec/#bucket-transform-details) functions. Support data files pruning in `Iceberg` tables partitioned with [`bucket transfom`](https://iceberg.apache.org/spec/#partitioning). [#79262](https://github.com/ClickHouse/ClickHouse/pull/79262) ([Daniil Ivanik](https://github.com/divanik)).
4542

4643
#### Experimental Feature
44+
* New `Time`/`Time64` data types: `Time` (HHH:MM:SS) and `Time64` (HHH:MM:SS.`<fractional>`) and some basic cast functions and functions to interact with other data types. Also, changed the existing function's name toTime to toTimeWithFixedDate because the function toTime is required for the cast function. [#75735](https://github.com/ClickHouse/ClickHouse/pull/75735) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
45+
72459).
4746
* Hive metastore catalog for Iceberg datalake. [#77677](https://github.com/ClickHouse/ClickHouse/pull/77677) ([scanhex12](https://github.com/scanhex12)).
4847
* Indexes of type `full_text` were renamed to `gin`. This follows the more familiar terminology of PostgreSQL and other databases. Existing indexes of type `full_text` remain loadable but they will throw an exception (suggesting `gin` indexes instead) when one tries to use them in searches. [#79024](https://github.com/ClickHouse/ClickHouse/pull/79024) ([Robert Schulze](https://github.com/rschu1ze)).
4948

@@ -60,7 +59,6 @@
6059
* Allow parallel merging of `uniqExact` states during the final stage of distributed aggregation. [#78703](https://github.com/ClickHouse/ClickHouse/pull/78703) ([Nikita Taranov](https://github.com/nickitat)).
6160
* Fix possible performance degradation of the parallel merging of `uniqExact` states for aggregation with key. [#78724](https://github.com/ClickHouse/ClickHouse/pull/78724) ([Nikita Taranov](https://github.com/nickitat)).
6261
* Reduce the number of List Blobs API calls to Azure storage. [#78860](https://github.com/ClickHouse/ClickHouse/pull/78860) ([Julia Kartseva](https://github.com/jkartseva)).
63-
* Merge equality conditions from filter query plan step into JOIN condition if possible to allow using them as hash table keys. [#78877](https://github.com/ClickHouse/ClickHouse/pull/78877) ([Dmitry Novik](https://github.com/novikd)).
6462
* Fix performance of the distributed INSERT SELECT with parallel replicas. [#79441](https://github.com/ClickHouse/ClickHouse/pull/79441) ([Azat Khuzhin](https://github.com/azat)).
6563
* Prevent `LogSeriesLimiter` from doing cleanup on every construction, avoiding lock contention and performance regressions in high-concurrency scenarios. [#79864](https://github.com/ClickHouse/ClickHouse/pull/79864) ([filimonov](https://github.com/filimonov)).
6664
* Speedup queries with trivial count optimization. [#79945](https://github.com/ClickHouse/ClickHouse/pull/79945) ([Raúl Marín](https://github.com/Algunenano)).
@@ -73,7 +71,6 @@
7371
* Lazy Materialization with parallel replicas. [#79401](https://github.com/ClickHouse/ClickHouse/pull/79401) ([Igor Nikonov](https://github.com/devcrafter)).
7472

7573
#### Improvement
76-
* Add table settings for `SASL` configuration and credentials to the `Kafka` table engine. This allows configuring SASL-based authentication to Kafka and Kafka-compatible systems directly in the CREATE TABLE statement rather than having to use configuration files or named collections. [#78810](https://github.com/ClickHouse/ClickHouse/pull/78810) ([Christoph Wurm](https://github.com/cwurm)).
7774
* Added an ability to apply lightweight deletes on the fly (with settings `lightweight_deletes_sync = 0`, `apply_mutations_on_fly = 1`. [#79281](https://github.com/ClickHouse/ClickHouse/pull/79281) ([Anton Popov](https://github.com/CurtizJ)).
7875
* If data in the pretty format is displayed in the terminal, and a subsequent block has the same column widths, it can continue from the previous block, glue it to the previous block by moving the cursor up. This closes [#79333](https://github.com/ClickHouse/ClickHouse/issues/79333). The feature is controlled by the new setting, `output_format_pretty_glue_chunks`. [#79339](https://github.com/ClickHouse/ClickHouse/pull/79339) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
7976
* Extend the `isIPAddressInRange` function to `String`, `IPv4`, `IPv6`, `Nullable(String)`, `Nullable(IPv4)`, and `Nullable(IPv6)` data types. [#78364](https://github.com/ClickHouse/ClickHouse/pull/78364) ([YjyJeff](https://github.com/YjyJeff)).

base/poco/NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,21 +236,16 @@ namespace Net
236236
/// to be able to re-use it again.
237237

238238
private:
239-
using MutexT = Poco::FastMutex;
240-
using LockT = MutexT::ScopedLock;
241-
using UnLockT = Poco::ScopedLockWithUnlock<MutexT>;
242-
243239
SecureSocketImpl(const SecureSocketImpl &);
244240
SecureSocketImpl & operator=(const SecureSocketImpl &);
245241

246242
mutable std::recursive_mutex _mutex;
247-
std::atomic<SSL *> _pSSL;
243+
SSL * _pSSL; // GUARDED_BY _mutex
248244
Poco::AutoPtr<SocketImpl> _pSocket;
249245
Context::Ptr _pContext;
250246
bool _needHandshake;
251247
std::string _peerHostName;
252248
Session::Ptr _pSession;
253-
mutable MutexT _ssl_mutex;
254249

255250
friend class SecureStreamSocketImpl;
256251

base/poco/NetSSL_OpenSSL/src/SecureSocketImpl.cpp

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ void SecureSocketImpl::acceptSSL()
103103
std::lock_guard<std::recursive_mutex> lock(_mutex);
104104
poco_assert (!_pSSL);
105105

106-
LockT l(_ssl_mutex);
107-
108106
BIO* pBIO = BIO_new(BIO_s_socket());
109107
if (!pBIO) throw SSLException("Cannot create BIO object");
110108
BIO_set_fd(pBIO, static_cast<int>(_pSocket->sockfd()), BIO_NOCLOSE);
@@ -171,8 +169,6 @@ void SecureSocketImpl::connectSSL(bool performHandshake)
171169
poco_assert (!_pSSL);
172170
poco_assert (_pSocket->initialized());
173171

174-
LockT l(_ssl_mutex);
175-
176172
BIO* pBIO = BIO_new(BIO_s_socket());
177173
if (!pBIO) throw SSLException("Cannot create SSL BIO object");
178174
BIO_set_fd(pBIO, static_cast<int>(_pSocket->sockfd()), BIO_NOCLOSE);
@@ -250,8 +246,6 @@ void SecureSocketImpl::shutdown()
250246
std::lock_guard<std::recursive_mutex> lock(_mutex);
251247
if (_pSSL)
252248
{
253-
UnLockT l(_ssl_mutex);
254-
255249
// Don't shut down the socket more than once.
256250
int shutdownState = SSL_get_shutdown(_pSSL);
257251
bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
@@ -266,7 +260,6 @@ void SecureSocketImpl::shutdown()
266260
// done with it.
267261
int rc = SSL_shutdown(_pSSL);
268262
if (rc < 0) handleError(rc);
269-
l.unlock();
270263
if (_pSocket->getBlocking())
271264
{
272265
_pSocket->shutdown();
@@ -297,9 +290,6 @@ int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags)
297290
poco_check_ptr (_pSSL);
298291

299292
int rc;
300-
301-
LockT l(_ssl_mutex);
302-
303293
if (_needHandshake)
304294
{
305295
rc = completeHandshake();
@@ -341,8 +331,6 @@ int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
341331
poco_assert (_pSocket->initialized());
342332
poco_check_ptr (_pSSL);
343333

344-
LockT l(_ssl_mutex);
345-
346334
/// Special case: just check that we can read from socket
347335
if ((flags & MSG_DONTWAIT) && (flags & MSG_PEEK))
348336
return _pSocket->receiveBytes(buffer, length, flags);
@@ -380,8 +368,6 @@ int SecureSocketImpl::available() const
380368
std::lock_guard<std::recursive_mutex> lock(_mutex);
381369
poco_check_ptr (_pSSL);
382370

383-
LockT l(_ssl_mutex);
384-
385371
return SSL_pending(_pSSL);
386372
}
387373

@@ -478,20 +464,10 @@ bool SecureSocketImpl::isLocalHost(const std::string& hostName)
478464
X509* SecureSocketImpl::peerCertificate() const
479465
{
480466
std::lock_guard<std::recursive_mutex> lock(_mutex);
481-
LockT l(_ssl_mutex);
482-
483-
X509* pCert = nullptr;
484-
485467
if (_pSSL)
486-
{
487-
pCert = ::SSL_get_peer_certificate(_pSSL);
488-
489-
if (X509_V_OK != SSL_get_verify_result(_pSSL))
490-
throw CertificateValidationException("SecureSocketImpl::peerCertificate(): "
491-
"Certificate verification error " + Utility::getLastError());
492-
}
493-
494-
return pCert;
468+
return SSL_get1_peer_certificate(_pSSL);
469+
else
470+
return 0;
495471
}
496472

497473
Poco::Timespan SecureSocketImpl::getMaxTimeoutOrLimit()
@@ -632,8 +608,6 @@ void SecureSocketImpl::reset()
632608
close();
633609
if (_pSSL)
634610
{
635-
LockT l(_ssl_mutex);
636-
637611
SSL_free(_pSSL);
638612
_pSSL = nullptr;
639613
}
@@ -678,12 +652,9 @@ bool SecureSocketImpl::sessionWasReused()
678652
{
679653
std::lock_guard<std::recursive_mutex> lock(_mutex);
680654
if (_pSSL)
681-
{
682-
LockT l(_ssl_mutex);
683-
return ::SSL_session_reused(_pSSL) != 0;
684-
}
685-
686-
return false;
655+
return SSL_session_reused(_pSSL) != 0;
656+
else
657+
return false;
687658
}
688659

689660
void SecureSocketImpl::setBlocking(bool flag)

ci/docker/integration/integration-test/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pycurl==7.45.3
1818
PyJWT==2.3.0
1919
pyparsing==2.4.7
2020
SecretStorage==3.3.1
21-
setuptools==59.6.0
21+
setuptools==78.1.1
2222
six==1.16.0
2323
wadllib==1.3.6
24-
wheel==0.37.1
24+
wheel==0.46.1
2525
zipp==1.0.0

ci/jobs/performance_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def run_test(
165165
--profile-seconds 10 \
166166
{test_file}",
167167
verbose=True,
168+
strip=False,
168169
)
169170
duration = sw.duration
170171
if res != 0:

ci/jobs/scripts/check_style/aspell-ignore/en/aspell-dict.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,7 @@ bitmaskToArray
14311431
bitmaskToList
14321432
bitov
14331433
blake
1434+
blobpath
14341435
blockNumber
14351436
blockSerializedSize
14361437
blockSize

ci/jobs/scripts/check_style/check_cpp.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,32 @@ find $ROOT_PATH/{src,base,programs,utils} -name '*.h' -or -name '*.cpp' | grep -
341341
do
342342
echo "Found the usage of std::format in '${file}'. Please use fmt::format instead"
343343
done
344+
345+
# Context.h (and a few similar headers) is included in many parts of the
346+
# codebase, so any modifications to it trigger a large-scale recompilation.
347+
# Therefore, it is crucial to avoid unnecessary inclusion of Context.h in
348+
# headers.
349+
#
350+
# In most cases, we can include Context_fwd.h instead, as we usually do not
351+
# need the full definition of the Context structure in headers - only declaration.
352+
CONTEXT_H_EXCLUDES=(
353+
# For now we have few exceptions (somewhere due to templated code, in other
354+
# places just because for now it does not worth it, i.e. the header is not
355+
# too generic):
356+
--exclude "$ROOT_PATH/src/BridgeHelper/XDBCBridgeHelper.h"
357+
--exclude "$ROOT_PATH/src/Interpreters/AddDefaultDatabaseVisitor.h"
358+
--exclude "$ROOT_PATH/src/TableFunctions/ITableFunctionCluster.h"
359+
--exclude "$ROOT_PATH/src/Core/PostgreSQLProtocol.h"
360+
--exclude "$ROOT_PATH/src/Client/ClientBase.h"
361+
--exclude "$ROOT_PATH/src/Common/tests/gtest_global_context.h"
362+
--exclude "$ROOT_PATH/src/Analyzer/InDepthQueryTreeVisitor.h"
363+
364+
# For functions we allow it for regular functions (due to lots of
365+
# templates), but forbid it in interface (IFunction) part.
366+
--exclude "$ROOT_PATH/src/Functions/*"
367+
--include "$ROOT_PATH/src/Functions/IFunction*"
368+
)
369+
find $ROOT_PATH/src -name '*.h' -print0 | xargs -0 grep -P '#include[\s]*(<|")Interpreters/Context.h(>|")' "${CONTEXT_H_EXCLUDES[@]}" | \
370+
grep . && echo '^ Too broad Context.h usage. Consider using Context_fwd.h and Context.h out from .h into .cpp'
371+
372+
exit 0

ci/jobs/scripts/workflow_hooks/trusted.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
e.lower()
88
for e in [
99
"amosbird",
10-
"azat",
1110
"den-crane", # Documentation contributor
1211
"taiyang-li",
1312
"ucasFL", # Amos Bird's friend

ci/praktika/utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def get_output(cls, command, strict=False, verbose=False):
182182
return res.stdout.strip()
183183

184184
@classmethod
185-
def get_res_stdout_stderr(cls, command, verbose=True):
185+
def get_res_stdout_stderr(cls, command, verbose=True, strip=True):
186186
if verbose:
187187
print(f"Run command [{command}]")
188188
res = subprocess.run(
@@ -192,7 +192,10 @@ def get_res_stdout_stderr(cls, command, verbose=True):
192192
stderr=subprocess.PIPE,
193193
text=True,
194194
)
195-
return res.returncode, res.stdout.strip(), res.stderr.strip()
195+
if strip:
196+
return res.returncode, res.stdout.strip(), res.stderr.strip()
197+
else:
198+
return res.returncode, res.stdout, res.stderr
196199

197200
@classmethod
198201
def check(

0 commit comments

Comments
 (0)