mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-20 05:05:38 +00:00
Merge branch 'master' into table-names-as-string-literal
This commit is contained in:
commit
320b2015d1
176
CHANGELOG.md
176
CHANGELOG.md
@ -1,4 +1,5 @@
|
||||
### Table of Contents
|
||||
**[ClickHouse release v23.7, 2023-07-27](#237)**<br/>
|
||||
**[ClickHouse release v23.6, 2023-06-30](#236)**<br/>
|
||||
**[ClickHouse release v23.5, 2023-06-08](#235)**<br/>
|
||||
**[ClickHouse release v23.4, 2023-04-26](#234)**<br/>
|
||||
@ -9,6 +10,181 @@
|
||||
|
||||
# 2023 Changelog
|
||||
|
||||
### <a id="237"></a> ClickHouse release 23.7, 2023-07-27
|
||||
|
||||
#### Backward Incompatible Change
|
||||
* Add `NAMED COLLECTION` access type (aliases `USE NAMED COLLECTION`, `NAMED COLLECTION USAGE`). This PR is backward incompatible because this access type is disabled by default (because a parent access type `NAMED COLLECTION ADMIN` is disabled by default as well). Proposed in [#50277](https://github.com/ClickHouse/ClickHouse/issues/50277). To grant use `GRANT NAMED COLLECTION ON collection_name TO user` or `GRANT NAMED COLLECTION ON * TO user`, to be able to give these grants `named_collection_admin` is required in config (previously it was named `named_collection_control`, so will remain as an alias). [#50625](https://github.com/ClickHouse/ClickHouse/pull/50625) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fixing a typo in the `system.parts` column name `last_removal_attemp_time`. Now it is named `last_removal_attempt_time`. [#52104](https://github.com/ClickHouse/ClickHouse/pull/52104) ([filimonov](https://github.com/filimonov)).
|
||||
* Bump version of the distributed_ddl_entry_format_version to 5 by default (enables opentelemetry and initial_query_idd pass through). This will not allow to process existing entries for distributed DDL after *downgrade* (but note, that usually there should be no such unprocessed entries). [#52128](https://github.com/ClickHouse/ClickHouse/pull/52128) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Check projection metadata the same way we check ordinary metadata. This change may prevent the server from starting in case there was a table with an invalid projection. An example is a projection that created positional columns in PK (e.g. `projection p (select * order by 1, 4)` which is not allowed in table PK and can cause a crash during insert/merge). Drop such projections before the update. Fixes [#52353](https://github.com/ClickHouse/ClickHouse/issues/52353). [#52361](https://github.com/ClickHouse/ClickHouse/pull/52361) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* The experimental feature `hashid` is removed due to a bug. The quality of implementation was questionable at the start, and it didn't get through the experimental status. This closes [#52406](https://github.com/ClickHouse/ClickHouse/issues/52406). [#52449](https://github.com/ClickHouse/ClickHouse/pull/52449) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
|
||||
#### New Feature
|
||||
* Added `Overlay` database engine to combine multiple databases into one. Added `Filesystem` database engine to represent a directory in the filesystem as a set of implicitly available tables with auto-detected formats and structures. A new `S3` database engine allows to read-only interact with s3 storage by representing a prefix as a set of tables. A new `HDFS` database engine allows to interact with HDFS storage in the same way. [#48821](https://github.com/ClickHouse/ClickHouse/pull/48821) ([alekseygolub](https://github.com/alekseygolub)).
|
||||
* Add support for external disks in Keeper for storing snapshots and logs. [#50098](https://github.com/ClickHouse/ClickHouse/pull/50098) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Add support for multi-directory selection (`{}`) globs. [#50559](https://github.com/ClickHouse/ClickHouse/pull/50559) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Support ZooKeeper `reconfig` command for ClickHouse Keeper with incremental reconfiguration which can be enabled via `keeper_server.enable_reconfiguration` setting. Support adding servers, removing servers, and changing server priorities. [#49450](https://github.com/ClickHouse/ClickHouse/pull/49450) ([Mike Kot](https://github.com/myrrc)).
|
||||
* Kafka connector can fetch Avro schema from schema registry with basic authentication using url-encoded credentials. [#49664](https://github.com/ClickHouse/ClickHouse/pull/49664) ([Ilya Golshtein](https://github.com/ilejn)).
|
||||
* Add function `arrayJaccardIndex` which computes the Jaccard similarity between two arrays. [#50076](https://github.com/ClickHouse/ClickHouse/pull/50076) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||
* Add a column `is_obsolete` to `system.settings` and similar tables. Closes [#50819](https://github.com/ClickHouse/ClickHouse/issues/50819). [#50826](https://github.com/ClickHouse/ClickHouse/pull/50826) ([flynn](https://github.com/ucasfl)).
|
||||
* Implement support of encrypted elements in configuration file. Added possibility to use encrypted text in leaf elements of configuration file. The text is encrypted using encryption codecs from `<encryption_codecs>` section. [#50986](https://github.com/ClickHouse/ClickHouse/pull/50986) ([Roman Vasin](https://github.com/rvasin)).
|
||||
* Grace Hash Join algorithm is now applicable to FULL and RIGHT JOINs. [#49483](https://github.com/ClickHouse/ClickHouse/issues/49483). [#51013](https://github.com/ClickHouse/ClickHouse/pull/51013) ([lgbo](https://github.com/lgbo-ustc)).
|
||||
* Add `SYSTEM STOP LISTEN` query for more graceful termination. Closes [#47972](https://github.com/ClickHouse/ClickHouse/issues/47972). [#51016](https://github.com/ClickHouse/ClickHouse/pull/51016) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Add `input_format_csv_allow_variable_number_of_columns` options. [#51273](https://github.com/ClickHouse/ClickHouse/pull/51273) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Another boring feature: add function `substring_index`, as in Spark or MySQL. [#51472](https://github.com/ClickHouse/ClickHouse/pull/51472) ([李扬](https://github.com/taiyang-li)).
|
||||
* A system table `jemalloc_bins` to show stats for jemalloc bins. Example `SELECT *, size * (nmalloc - ndalloc) AS allocated_bytes FROM system.jemalloc_bins WHERE allocated_bytes > 0 ORDER BY allocated_bytes DESC LIMIT 10`. Enjoy. [#51674](https://github.com/ClickHouse/ClickHouse/pull/51674) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Add `RowBinaryWithDefaults` format with extra byte before each column as a flag for using the column's default value. Closes [#50854](https://github.com/ClickHouse/ClickHouse/issues/50854). [#51695](https://github.com/ClickHouse/ClickHouse/pull/51695) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Added `default_temporary_table_engine` setting. Same as `default_table_engine` but for temporary tables. [#51292](https://github.com/ClickHouse/ClickHouse/issues/51292). [#51708](https://github.com/ClickHouse/ClickHouse/pull/51708) ([velavokr](https://github.com/velavokr)).
|
||||
* Added new `initcap` / `initcapUTF8` functions which convert the first letter of each word to upper case and the rest to lower case. [#51735](https://github.com/ClickHouse/ClickHouse/pull/51735) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Create table now supports `PRIMARY KEY` syntax in column definition. Columns are added to primary index in the same order columns are defined. [#51881](https://github.com/ClickHouse/ClickHouse/pull/51881) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Added the possibility to use date and time format specifiers in log and error log file names, either in config files (`log` and `errorlog` tags) or command line arguments (`--log-file` and `--errorlog-file`). [#51945](https://github.com/ClickHouse/ClickHouse/pull/51945) ([Victor Krasnov](https://github.com/sirvickr)).
|
||||
* Added Peak Memory Usage statistic to HTTP headers. [#51946](https://github.com/ClickHouse/ClickHouse/pull/51946) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Added new `hasSubsequence` (+`CaseInsensitive` and `UTF8` versions) functions to match subsequences in strings. [#52050](https://github.com/ClickHouse/ClickHouse/pull/52050) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Add `array_agg` as alias of `groupArray` for PostgreSQL compatibility. Closes [#52100](https://github.com/ClickHouse/ClickHouse/issues/52100). ### Documentation entry for user-facing changes. [#52135](https://github.com/ClickHouse/ClickHouse/pull/52135) ([flynn](https://github.com/ucasfl)).
|
||||
* Add `any_value` as a compatibility alias for `any` aggregate function. Closes [#52140](https://github.com/ClickHouse/ClickHouse/issues/52140). [#52147](https://github.com/ClickHouse/ClickHouse/pull/52147) ([flynn](https://github.com/ucasfl)).
|
||||
* Add aggregate function `array_concat_agg` for compatibility with BigQuery, it's alias of `groupArrayArray`. Closes [#52139](https://github.com/ClickHouse/ClickHouse/issues/52139). [#52149](https://github.com/ClickHouse/ClickHouse/pull/52149) ([flynn](https://github.com/ucasfl)).
|
||||
* Add `OCTET_LENGTH` as an alias to `length`. Closes [#52153](https://github.com/ClickHouse/ClickHouse/issues/52153). [#52176](https://github.com/ClickHouse/ClickHouse/pull/52176) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||
* Added `firstLine` function to extract the first line from the multi-line string. This closes [#51172](https://github.com/ClickHouse/ClickHouse/issues/51172). [#52209](https://github.com/ClickHouse/ClickHouse/pull/52209) ([Mikhail Koviazin](https://github.com/mkmkme)).
|
||||
* Implement KQL-style formatting for the `Interval` data type. This is only needed for compatibility with the `Kusto` query language. [#45671](https://github.com/ClickHouse/ClickHouse/pull/45671) ([ltrk2](https://github.com/ltrk2)).
|
||||
* Added query `SYSTEM FLUSH ASYNC INSERT QUEUE` which flushes all pending asynchronous inserts to the destination tables. Added a server-side setting `async_insert_queue_flush_on_shutdown` (`true` by default) which determines whether to flush queue of asynchronous inserts on graceful shutdown. Setting `async_insert_threads` is now a server-side setting. [#49160](https://github.com/ClickHouse/ClickHouse/pull/49160) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* Aliases `current_database` and a new function `current_schemas` for compatibility with PostgreSQL. [#51076](https://github.com/ClickHouse/ClickHouse/pull/51076) ([Pedro Riera](https://github.com/priera)).
|
||||
* Add alias for functions `today` (now available under the `curdate`/`current_date` names) and `now` (`current_timestamp`). [#52106](https://github.com/ClickHouse/ClickHouse/pull/52106) ([Lloyd-Pottiger](https://github.com/Lloyd-Pottiger)).
|
||||
* Support `async_deduplication_token` for async insert. [#52136](https://github.com/ClickHouse/ClickHouse/pull/52136) ([Han Fei](https://github.com/hanfei1991)).
|
||||
* Add new setting `disable_url_encoding` that allows to disable decoding/encoding path in uri in URL engine. [#52337](https://github.com/ClickHouse/ClickHouse/pull/52337) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
|
||||
#### Performance Improvement
|
||||
* Writing parquet files is 10x faster, it's multi-threaded now. Almost the same speed as reading. [#49367](https://github.com/ClickHouse/ClickHouse/pull/49367) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Enable automatic selection of the sparse serialization format by default. It improves performance. The format is supported since version 22.1. After this change, downgrading to versions older than 22.1 might not be possible. You can turn off the usage of the sparse serialization format by providing the `ratio_of_defaults_for_sparse_serialization = 1` setting for your MergeTree tables. [#49631](https://github.com/ClickHouse/ClickHouse/pull/49631) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Enable `move_all_conditions_to_prewhere` and `enable_multiple_prewhere_read_steps` settings by default. [#46365](https://github.com/ClickHouse/ClickHouse/pull/46365) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Improves performance of some queries by tuning allocator. [#46416](https://github.com/ClickHouse/ClickHouse/pull/46416) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Now we use fixed-size tasks in `MergeTreePrefetchedReadPool` as in `MergeTreeReadPool`. Also from now we use connection pool for S3 requests. [#49732](https://github.com/ClickHouse/ClickHouse/pull/49732) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* More pushdown to the right side of join. [#50532](https://github.com/ClickHouse/ClickHouse/pull/50532) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Improve grace_hash join by reserving hash table's size (resubmit). [#50875](https://github.com/ClickHouse/ClickHouse/pull/50875) ([lgbo](https://github.com/lgbo-ustc)).
|
||||
* Waiting on lock in `OpenedFileCache` could be noticeable sometimes. We sharded it into multiple sub-maps (each with its own lock) to avoid contention. [#51341](https://github.com/ClickHouse/ClickHouse/pull/51341) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Move conditions with primary key columns to the end of PREWHERE chain. The idea is that conditions with PK columns are likely to be used in PK analysis and will not contribute much more to PREWHERE filtering. [#51958](https://github.com/ClickHouse/ClickHouse/pull/51958) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Speed up `COUNT(DISTINCT)` for String types by inlining SipHash. The performance experiments of *OnTime* on the ICX device (Intel Xeon Platinum 8380 CPU, 80 cores, 160 threads) show that this change could bring an improvement of *11.6%* to the QPS of the query *Q8* while having no impact on others. [#52036](https://github.com/ClickHouse/ClickHouse/pull/52036) ([Zhiguo Zhou](https://github.com/ZhiguoZh)).
|
||||
* Enable `allow_vertical_merges_from_compact_to_wide_parts` by default. It will save memory usage during merges. [#52295](https://github.com/ClickHouse/ClickHouse/pull/52295) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix incorrect projection analysis which invalidates primary keys. This issue only exists when `query_plan_optimize_primary_key = 1, query_plan_optimize_projection = 1`. This fixes [#48823](https://github.com/ClickHouse/ClickHouse/issues/48823). This fixes [#51173](https://github.com/ClickHouse/ClickHouse/issues/51173). [#52308](https://github.com/ClickHouse/ClickHouse/pull/52308) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Reduce the number of syscalls in `FileCache::loadMetadata` - this speeds up server startup if the filesystem cache is configured. [#52435](https://github.com/ClickHouse/ClickHouse/pull/52435) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Allow to have strict lower boundary for file segment size by downloading remaining data in the background. Minimum size of file segment (if actual file size is bigger) is configured as cache configuration setting `boundary_alignment`, by default `4Mi`. Number of background threads are configured as cache configuration setting `background_download_threads`, by default `2`. Also `max_file_segment_size` was increased from `8Mi` to `32Mi` in this PR. [#51000](https://github.com/ClickHouse/ClickHouse/pull/51000) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Decreased default timeouts for S3 from 30 seconds to 3 seconds, and for other HTTP from 180 seconds to 30 seconds. [#51171](https://github.com/ClickHouse/ClickHouse/pull/51171) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* New setting `merge_tree_determine_task_size_by_prewhere_columns` added. If set to `true` only sizes of the columns from `PREWHERE` section will be considered to determine reading task size. Otherwise all the columns from query are considered. [#52606](https://github.com/ClickHouse/ClickHouse/pull/52606) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
|
||||
#### Improvement
|
||||
* Use read_bytes/total_bytes_to_read for progress bar in s3/file/url/... table functions for better progress indication. [#51286](https://github.com/ClickHouse/ClickHouse/pull/51286) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Introduce a table setting `wait_for_unique_parts_send_before_shutdown_ms` which specify the amount of time replica will wait before closing interserver handler for replicated sends. Also fix inconsistency with shutdown of tables and interserver handlers: now server shutdown tables first and only after it shut down interserver handlers. [#51851](https://github.com/ClickHouse/ClickHouse/pull/51851) ([alesapin](https://github.com/alesapin)).
|
||||
* Allow SQL standard `FETCH` without `OFFSET`. See https://antonz.org/sql-fetch/. [#51293](https://github.com/ClickHouse/ClickHouse/pull/51293) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Allow filtering HTTP headers for the URL/S3 table functions with the new `http_forbid_headers` section in config. Both exact matching and regexp filters are available. [#51038](https://github.com/ClickHouse/ClickHouse/pull/51038) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Don't show messages about `16 EiB` free space in logs, as they don't make sense. This closes [#49320](https://github.com/ClickHouse/ClickHouse/issues/49320). [#49342](https://github.com/ClickHouse/ClickHouse/pull/49342) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Properly check the limit for the `sleepEachRow` function. Add a setting `function_sleep_max_microseconds_per_block`. This is needed for generic query fuzzer. [#49343](https://github.com/ClickHouse/ClickHouse/pull/49343) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix two issues in `geoHash` functions. [#50066](https://github.com/ClickHouse/ClickHouse/pull/50066) ([李扬](https://github.com/taiyang-li)).
|
||||
* Log async insert flush queries into `system.query_log`. [#51160](https://github.com/ClickHouse/ClickHouse/pull/51160) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Functions `date_diff` and `age` now support millisecond/microsecond unit and work with microsecond precision. [#51291](https://github.com/ClickHouse/ClickHouse/pull/51291) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Improve parsing of path in clickhouse-keeper-client. [#51359](https://github.com/ClickHouse/ClickHouse/pull/51359) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* A third-party product depending on ClickHouse (Gluten: a Plugin to Double SparkSQL's Performance) had a bug. This fix avoids heap overflow in that third-party product while reading from HDFS. [#51386](https://github.com/ClickHouse/ClickHouse/pull/51386) ([李扬](https://github.com/taiyang-li)).
|
||||
* Add ability to disable native copy for S3 (setting for BACKUP/RESTORE `allow_s3_native_copy`, and `s3_allow_native_copy` for `s3`/`s3_plain` disks). [#51448](https://github.com/ClickHouse/ClickHouse/pull/51448) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Add column `primary_key_size` to `system.parts` table to show compressed primary key size on disk. Closes [#51400](https://github.com/ClickHouse/ClickHouse/issues/51400). [#51496](https://github.com/ClickHouse/ClickHouse/pull/51496) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
|
||||
* Allow running `clickhouse-local` without procfs, without home directory existing, and without name resolution plugins from glibc. [#51518](https://github.com/ClickHouse/ClickHouse/pull/51518) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add placeholder `%a` for rull filename in rename_files_after_processing setting. [#51603](https://github.com/ClickHouse/ClickHouse/pull/51603) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Add column `modification_time` into `system.parts_columns`. [#51685](https://github.com/ClickHouse/ClickHouse/pull/51685) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Add new setting `input_format_csv_use_default_on_bad_values` to CSV format that allows to insert default value when parsing of a single field failed. [#51716](https://github.com/ClickHouse/ClickHouse/pull/51716) ([KevinyhZou](https://github.com/KevinyhZou)).
|
||||
* Added a crash log flush to the disk after the unexpected crash. [#51720](https://github.com/ClickHouse/ClickHouse/pull/51720) ([Alexey Gerasimchuck](https://github.com/Demilivor)).
|
||||
* Fix behavior in dashboard page where errors unrelated to authentication are not shown. Also fix 'overlapping' chart behavior. [#51744](https://github.com/ClickHouse/ClickHouse/pull/51744) ([Zach Naimon](https://github.com/ArctypeZach)).
|
||||
* Allow UUID to UInt128 conversion. [#51765](https://github.com/ClickHouse/ClickHouse/pull/51765) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Added support for function `range` of Nullable arguments. [#51767](https://github.com/ClickHouse/ClickHouse/pull/51767) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Convert condition like `toyear(x) = c` to `c1 <= x < c2`. [#51795](https://github.com/ClickHouse/ClickHouse/pull/51795) ([Han Fei](https://github.com/hanfei1991)).
|
||||
* Improve MySQL compatibility of the statement `SHOW INDEX`. [#51796](https://github.com/ClickHouse/ClickHouse/pull/51796) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Fix `use_structure_from_insertion_table_in_table_functions` does not work with `MATERIALIZED` and `ALIAS` columns. Closes [#51817](https://github.com/ClickHouse/ClickHouse/issues/51817). Closes [#51019](https://github.com/ClickHouse/ClickHouse/issues/51019). [#51825](https://github.com/ClickHouse/ClickHouse/pull/51825) ([flynn](https://github.com/ucasfl)).
|
||||
* Cache dictionary now requests only unique keys from source. Closes [#51762](https://github.com/ClickHouse/ClickHouse/issues/51762). [#51853](https://github.com/ClickHouse/ClickHouse/pull/51853) ([Maksim Kita](https://github.com/kitaisreal)).
|
||||
* Fixed the case when settings were not applied for EXPLAIN query when FORMAT was provided. [#51859](https://github.com/ClickHouse/ClickHouse/pull/51859) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Allow SETTINGS before FORMAT in DESCRIBE TABLE query for compatibility with SELECT query. Closes [#51544](https://github.com/ClickHouse/ClickHouse/issues/51544). [#51899](https://github.com/ClickHouse/ClickHouse/pull/51899) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Var-Int encoded integers (e.g. used by the native protocol) can now use the full 64-bit range. 3rd party clients are advised to update their var-int code accordingly. [#51905](https://github.com/ClickHouse/ClickHouse/pull/51905) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Update certificates when they change without the need to manually SYSTEM RELOAD CONFIG. [#52030](https://github.com/ClickHouse/ClickHouse/pull/52030) ([Mike Kot](https://github.com/myrrc)).
|
||||
* Added `allow_create_index_without_type` setting that allow to ignore `ADD INDEX` queries without specified `TYPE`. Standard SQL queries will just succeed without changing table schema. [#52056](https://github.com/ClickHouse/ClickHouse/pull/52056) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Log messages are written to the `system.text_log` from the server startup. [#52113](https://github.com/ClickHouse/ClickHouse/pull/52113) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* In cases where the HTTP endpoint has multiple IP addresses and the first of them is unreachable, a timeout exception was thrown. Made session creation with handling all resolved endpoints. [#52116](https://github.com/ClickHouse/ClickHouse/pull/52116) ([Aleksei Filatov](https://github.com/aalexfvk)).
|
||||
* Avro input format now supports Union even if it contains only a single type. Closes [#52131](https://github.com/ClickHouse/ClickHouse/issues/52131). [#52137](https://github.com/ClickHouse/ClickHouse/pull/52137) ([flynn](https://github.com/ucasfl)).
|
||||
* Add setting `optimize_use_implicit_projections` to disable implicit projections (currently only `min_max_count` projection). [#52152](https://github.com/ClickHouse/ClickHouse/pull/52152) ([Amos Bird](https://github.com/amosbird)).
|
||||
* It was possible to use the function `hasToken` for infinite loop. Now this possibility is removed. This closes [#52156](https://github.com/ClickHouse/ClickHouse/issues/52156). [#52160](https://github.com/ClickHouse/ClickHouse/pull/52160) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Create ZK ancestors optimistically. [#52195](https://github.com/ClickHouse/ClickHouse/pull/52195) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Fix [#50582](https://github.com/ClickHouse/ClickHouse/issues/50582). Avoid the `Not found column ... in block` error in some cases of reading in-order and constants. [#52259](https://github.com/ClickHouse/ClickHouse/pull/52259) ([Chen768959](https://github.com/Chen768959)).
|
||||
* Check whether S2 geo primitives are invalid as early as possible on ClickHouse side. This closes: [#27090](https://github.com/ClickHouse/ClickHouse/issues/27090). [#52260](https://github.com/ClickHouse/ClickHouse/pull/52260) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* Add back missing projection QueryAccessInfo when `query_plan_optimize_projection = 1`. This fixes [#50183](https://github.com/ClickHouse/ClickHouse/issues/50183) . This fixes [#50093](https://github.com/ClickHouse/ClickHouse/issues/50093). [#52327](https://github.com/ClickHouse/ClickHouse/pull/52327) ([Amos Bird](https://github.com/amosbird)).
|
||||
* When `ZooKeeperRetriesControl` rethrows an error, it's more useful to see its original stack trace, not the one from `ZooKeeperRetriesControl` itself. [#52347](https://github.com/ClickHouse/ClickHouse/pull/52347) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||
* Wait for zero copy replication lock even if some disks don't support it. [#52376](https://github.com/ClickHouse/ClickHouse/pull/52376) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Now interserver port will be closed only after tables are shut down. [#52498](https://github.com/ClickHouse/ClickHouse/pull/52498) ([alesapin](https://github.com/alesapin)).
|
||||
|
||||
#### Experimental Feature
|
||||
* Added support for [PRQL](https://prql-lang.org/) as a query language. [#50686](https://github.com/ClickHouse/ClickHouse/pull/50686) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)).
|
||||
* Allow to add disk name for custom disks. Previously custom disks would use an internal generated disk name. Now it will be possible with `disk = disk_<name>(...)` (e.g. disk will have name `name`) . [#51552](https://github.com/ClickHouse/ClickHouse/pull/51552) ([Kseniia Sumarokova](https://github.com/kssenii)). This syntax can be changed in this release.
|
||||
* (experimental MaterializedMySQL) Fixed crash when `mysqlxx::Pool::Entry` is used after it was disconnected. [#52063](https://github.com/ClickHouse/ClickHouse/pull/52063) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* (experimental MaterializedMySQL) `CREATE TABLE ... AS SELECT` .. is now supported in MaterializedMySQL. [#52067](https://github.com/ClickHouse/ClickHouse/pull/52067) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* (experimental MaterializedMySQL) Introduced automatic conversion of text types to utf8 for MaterializedMySQL. [#52084](https://github.com/ClickHouse/ClickHouse/pull/52084) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* (experimental MaterializedMySQL) Now unquoted UTF-8 strings are supported in DDL for MaterializedMySQL. [#52318](https://github.com/ClickHouse/ClickHouse/pull/52318) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* (experimental MaterializedMySQL) Now double quoted comments are supported in MaterializedMySQL. [#52355](https://github.com/ClickHouse/ClickHouse/pull/52355) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Upgrade Intel QPL from v1.1.0 to v1.2.0 2. Upgrade Intel accel-config from v3.5 to v4.0 3. Fixed issue that Device IOTLB miss has big perf. impact for IAA accelerators. [#52180](https://github.com/ClickHouse/ClickHouse/pull/52180) ([jasperzhu](https://github.com/jinjunzh)).
|
||||
* The `session_timezone` setting (new in version 23.6) is demoted to experimental. [#52445](https://github.com/ClickHouse/ClickHouse/pull/52445) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
|
||||
#### Build/Testing/Packaging Improvement
|
||||
* Add experimental ClickHouse builds for Linux RISC-V 64 to CI. [#31398](https://github.com/ClickHouse/ClickHouse/pull/31398) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add integration test check with the enabled Analyzer. [#50926](https://github.com/ClickHouse/ClickHouse/pull/50926) [#52210](https://github.com/ClickHouse/ClickHouse/pull/52210) ([Dmitry Novik](https://github.com/novikd)).
|
||||
* Reproducible builds for Rust. [#52395](https://github.com/ClickHouse/ClickHouse/pull/52395) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update Cargo dependencies. [#51721](https://github.com/ClickHouse/ClickHouse/pull/51721) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Make the function `CHColumnToArrowColumn::fillArrowArrayWithArrayColumnData` to work with nullable arrays, which are not possible in ClickHouse, but needed for Gluten. [#52112](https://github.com/ClickHouse/ClickHouse/pull/52112) ([李扬](https://github.com/taiyang-li)).
|
||||
* We've updated the CCTZ library to master, but there are no user-visible changes. [#52124](https://github.com/ClickHouse/ClickHouse/pull/52124) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* The `system.licenses` table now includes the hard-forked library Poco. This closes [#52066](https://github.com/ClickHouse/ClickHouse/issues/52066). [#52127](https://github.com/ClickHouse/ClickHouse/pull/52127) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Check that there are no cases of bad punctuation: whitespace before a comma like `Hello ,world` instead of `Hello, world`. [#52549](https://github.com/ClickHouse/ClickHouse/pull/52549) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
|
||||
#### Bug Fix (user-visible misbehavior in an official stable release)
|
||||
* Fix MaterializedPostgreSQL syncTables [#49698](https://github.com/ClickHouse/ClickHouse/pull/49698) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix projection with optimize_aggregators_of_group_by_keys [#49709](https://github.com/ClickHouse/ClickHouse/pull/49709) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix optimize_skip_unused_shards with JOINs [#51037](https://github.com/ClickHouse/ClickHouse/pull/51037) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix formatDateTime() with fractional negative datetime64 [#51290](https://github.com/ClickHouse/ClickHouse/pull/51290) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Functions `hasToken*` were totally wrong. Add a test for [#43358](https://github.com/ClickHouse/ClickHouse/issues/43358) [#51378](https://github.com/ClickHouse/ClickHouse/pull/51378) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix optimization to move functions before sorting. [#51481](https://github.com/ClickHouse/ClickHouse/pull/51481) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* Fix Block structure mismatch in Pipe::unitePipes for FINAL [#51492](https://github.com/ClickHouse/ClickHouse/pull/51492) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fix SIGSEGV for clusters with zero weight across all shards (fixes INSERT INTO FUNCTION clusterAllReplicas()) [#51545](https://github.com/ClickHouse/ClickHouse/pull/51545) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix timeout for hedged requests [#51582](https://github.com/ClickHouse/ClickHouse/pull/51582) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix logical error in ANTI join with NULL [#51601](https://github.com/ClickHouse/ClickHouse/pull/51601) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix for moving 'IN' conditions to PREWHERE [#51610](https://github.com/ClickHouse/ClickHouse/pull/51610) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Do not apply PredicateExpressionsOptimizer for ASOF/ANTI join [#51633](https://github.com/ClickHouse/ClickHouse/pull/51633) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix async insert with deduplication for ReplicatedMergeTree using merging algorithms [#51676](https://github.com/ClickHouse/ClickHouse/pull/51676) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix reading from empty column in `parseSipHashKey` [#51804](https://github.com/ClickHouse/ClickHouse/pull/51804) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fix segfault when create invalid EmbeddedRocksdb table [#51847](https://github.com/ClickHouse/ClickHouse/pull/51847) ([Duc Canh Le](https://github.com/canhld94)).
|
||||
* Fix inserts into MongoDB tables [#51876](https://github.com/ClickHouse/ClickHouse/pull/51876) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Fix deadlock on DatabaseCatalog shutdown [#51908](https://github.com/ClickHouse/ClickHouse/pull/51908) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix error in subquery operators [#51922](https://github.com/ClickHouse/ClickHouse/pull/51922) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix async connect to hosts with multiple ips [#51934](https://github.com/ClickHouse/ClickHouse/pull/51934) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Do not remove inputs after ActionsDAG::merge [#51947](https://github.com/ClickHouse/ClickHouse/pull/51947) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* Check refcount in `RemoveManyObjectStorageOperation::finalize` instead of `execute` [#51954](https://github.com/ClickHouse/ClickHouse/pull/51954) ([vdimir](https://github.com/vdimir)).
|
||||
* Allow parametric UDFs [#51964](https://github.com/ClickHouse/ClickHouse/pull/51964) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Small fix for toDateTime64() for dates after 2283-12-31 [#52130](https://github.com/ClickHouse/ClickHouse/pull/52130) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Fix ORDER BY tuple of WINDOW functions [#52145](https://github.com/ClickHouse/ClickHouse/pull/52145) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix incorrect projection analysis when aggregation expression contains monotonic functions [#52151](https://github.com/ClickHouse/ClickHouse/pull/52151) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix error in `groupArrayMoving` functions [#52161](https://github.com/ClickHouse/ClickHouse/pull/52161) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Disable direct join for range dictionary [#52187](https://github.com/ClickHouse/ClickHouse/pull/52187) ([Duc Canh Le](https://github.com/canhld94)).
|
||||
* Fix sticky mutations test (and extremely rare race condition) [#52197](https://github.com/ClickHouse/ClickHouse/pull/52197) ([alesapin](https://github.com/alesapin)).
|
||||
* Fix race in Web disk [#52211](https://github.com/ClickHouse/ClickHouse/pull/52211) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix data race in Connection::setAsyncCallback on unknown packet from server [#52219](https://github.com/ClickHouse/ClickHouse/pull/52219) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Fix temp data deletion on startup, add test [#52275](https://github.com/ClickHouse/ClickHouse/pull/52275) ([vdimir](https://github.com/vdimir)).
|
||||
* Don't use minmax_count projections when counting nullable columns [#52297](https://github.com/ClickHouse/ClickHouse/pull/52297) ([Amos Bird](https://github.com/amosbird)).
|
||||
* MergeTree/ReplicatedMergeTree should use server timezone for log entries [#52325](https://github.com/ClickHouse/ClickHouse/pull/52325) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix parameterized view with cte and multiple usage [#52328](https://github.com/ClickHouse/ClickHouse/pull/52328) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||
* Disable expression templates for time intervals [#52335](https://github.com/ClickHouse/ClickHouse/pull/52335) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix `apply_snapshot` in Keeper [#52358](https://github.com/ClickHouse/ClickHouse/pull/52358) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Update build-osx.md [#52377](https://github.com/ClickHouse/ClickHouse/pull/52377) ([AlexBykovski](https://github.com/AlexBykovski)).
|
||||
* Fix `countSubstrings()` hang with empty needle and a column haystack [#52409](https://github.com/ClickHouse/ClickHouse/pull/52409) ([Sergei Trifonov](https://github.com/serxa)).
|
||||
* Fix normal projection with merge table [#52432](https://github.com/ClickHouse/ClickHouse/pull/52432) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix possible double-free in Aggregator [#52439](https://github.com/ClickHouse/ClickHouse/pull/52439) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fixed inserting into Buffer engine [#52440](https://github.com/ClickHouse/ClickHouse/pull/52440) ([Vasily Nemkov](https://github.com/Enmk)).
|
||||
* The implementation of AnyHash was non-conformant. [#52448](https://github.com/ClickHouse/ClickHouse/pull/52448) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Check recursion depth in OptimizedRegularExpression [#52451](https://github.com/ClickHouse/ClickHouse/pull/52451) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix data-race DatabaseReplicated::startupTables()/canExecuteReplicatedMetadataAlter() [#52490](https://github.com/ClickHouse/ClickHouse/pull/52490) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix abort in function `transform` [#52513](https://github.com/ClickHouse/ClickHouse/pull/52513) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix lightweight delete after drop of projection [#52517](https://github.com/ClickHouse/ClickHouse/pull/52517) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* Fix possible error "Cannot drain connections: cancel first" [#52585](https://github.com/ClickHouse/ClickHouse/pull/52585) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
|
||||
|
||||
### <a id="236"></a> ClickHouse release 23.6, 2023-06-29
|
||||
|
||||
#### Backward Incompatible Change
|
||||
|
@ -13,9 +13,10 @@ The following versions of ClickHouse server are currently being supported with s
|
||||
|
||||
| Version | Supported |
|
||||
|:-|:-|
|
||||
| 23.7 | ✔️ |
|
||||
| 23.6 | ✔️ |
|
||||
| 23.5 | ✔️ |
|
||||
| 23.4 | ✔️ |
|
||||
| 23.4 | ❌ |
|
||||
| 23.3 | ✔️ |
|
||||
| 23.2 | ❌ |
|
||||
| 23.1 | ❌ |
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
# NOTE: has nothing common with DBMS_TCP_PROTOCOL_VERSION,
|
||||
# only DBMS_TCP_PROTOCOL_VERSION should be incremented on protocol changes.
|
||||
SET(VERSION_REVISION 54476)
|
||||
SET(VERSION_REVISION 54477)
|
||||
SET(VERSION_MAJOR 23)
|
||||
SET(VERSION_MINOR 7)
|
||||
SET(VERSION_MINOR 8)
|
||||
SET(VERSION_PATCH 1)
|
||||
SET(VERSION_GITHASH d1c7e13d08868cb04d3562dcced704dd577cb1df)
|
||||
SET(VERSION_DESCRIBE v23.7.1.1-testing)
|
||||
SET(VERSION_STRING 23.7.1.1)
|
||||
SET(VERSION_GITHASH a70127baecc451f1f7073bad7b6198f6703441d8)
|
||||
SET(VERSION_DESCRIBE v23.8.1.1-testing)
|
||||
SET(VERSION_STRING 23.8.1.1)
|
||||
# end of autochange
|
||||
|
@ -502,9 +502,10 @@ target_include_directories(_parquet SYSTEM BEFORE
|
||||
"${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cpp/src")
|
||||
target_link_libraries(_parquet
|
||||
PUBLIC _arrow
|
||||
PRIVATE
|
||||
PUBLIC
|
||||
_arrow
|
||||
ch_contrib::thrift
|
||||
PRIVATE
|
||||
boost::headers_only
|
||||
boost::regex
|
||||
OpenSSL::Crypto OpenSSL::SSL)
|
||||
|
@ -32,7 +32,7 @@ RUN arch=${TARGETARCH:-amd64} \
|
||||
esac
|
||||
|
||||
ARG REPOSITORY="https://s3.amazonaws.com/clickhouse-builds/22.4/31c367d3cd3aefd316778601ff6565119fe36682/package_release"
|
||||
ARG VERSION="23.6.2.18"
|
||||
ARG VERSION="23.7.1.2470"
|
||||
ARG PACKAGES="clickhouse-keeper"
|
||||
|
||||
# user/group precreated explicitly with fixed uid/gid on purpose.
|
||||
|
@ -33,7 +33,7 @@ RUN arch=${TARGETARCH:-amd64} \
|
||||
# lts / testing / prestable / etc
|
||||
ARG REPO_CHANNEL="stable"
|
||||
ARG REPOSITORY="https://packages.clickhouse.com/tgz/${REPO_CHANNEL}"
|
||||
ARG VERSION="23.6.2.18"
|
||||
ARG VERSION="23.7.1.2470"
|
||||
ARG PACKAGES="clickhouse-client clickhouse-server clickhouse-common-static"
|
||||
|
||||
# user/group precreated explicitly with fixed uid/gid on purpose.
|
||||
|
@ -23,7 +23,7 @@ RUN sed -i "s|http://archive.ubuntu.com|${apt_archive}|g" /etc/apt/sources.list
|
||||
|
||||
ARG REPO_CHANNEL="stable"
|
||||
ARG REPOSITORY="deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb ${REPO_CHANNEL} main"
|
||||
ARG VERSION="23.6.2.18"
|
||||
ARG VERSION="23.7.1.2470"
|
||||
ARG PACKAGES="clickhouse-client clickhouse-server clickhouse-common-static"
|
||||
|
||||
# set non-empty deb_location_url url to create a docker image
|
||||
|
452
docs/changelogs/v23.7.1.2470-stable.md
Normal file
452
docs/changelogs/v23.7.1.2470-stable.md
Normal file
@ -0,0 +1,452 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_label: 2023
|
||||
---
|
||||
|
||||
# 2023 Changelog
|
||||
|
||||
### ClickHouse release v23.7.1.2470-stable (a70127baecc) FIXME as compared to v23.6.1.1524-stable (d1c7e13d088)
|
||||
|
||||
#### Backward Incompatible Change
|
||||
* Add ` NAMED COLLECTION` access type (aliases `USE NAMED COLLECTION`, `NAMED COLLECTION USAGE`). This PR is backward incompatible because this access type is disabled by default (because a parent access type `NAMED COLLECTION ADMIN` is disabled by default as well). Proposed in [#50277](https://github.com/ClickHouse/ClickHouse/issues/50277). To grant use `GRANT NAMED COLLECTION ON collection_name TO user` or `GRANT NAMED COLLECTION ON * TO user`, to be able to give these grants `named_collection_admin` is required in config (previously it was named `named_collection_control`, so will remain as an alias). [#50625](https://github.com/ClickHouse/ClickHouse/pull/50625) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fixing a typo in the `system.parts` column name `last_removal_attemp_time`. Now it is named `last_removal_attempt_time`. [#52104](https://github.com/ClickHouse/ClickHouse/pull/52104) ([filimonov](https://github.com/filimonov)).
|
||||
* Bump version of the distributed_ddl_entry_format_version to 5 by default (enables opentelemetry and initial_query_idd pass through). This will not allow to process existing entries for distributed DDL after **downgrade** (but note, that usually there should be no such unprocessed entries). [#52128](https://github.com/ClickHouse/ClickHouse/pull/52128) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Check projection metadata the same way we check ordinary metadata. This change may prevent the server from starting in case there was a table with an invalid projection. An example is a projection that created positional columns in PK (e.g. `projection p (select * order by 1, 4)` which is not allowed in table PK and can cause a crash during insert/merge). Drop such projections before the update. Fixes [#52353](https://github.com/ClickHouse/ClickHouse/issues/52353). [#52361](https://github.com/ClickHouse/ClickHouse/pull/52361) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* The experimental feature `hashid` is removed due to a bug. The quality of implementation was questionable at the start, and it didn't get through the experimental status. This closes [#52406](https://github.com/ClickHouse/ClickHouse/issues/52406). [#52449](https://github.com/ClickHouse/ClickHouse/pull/52449) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* The function `toDecimalString` is removed due to subpar implementation quality. This closes [#52407](https://github.com/ClickHouse/ClickHouse/issues/52407). [#52450](https://github.com/ClickHouse/ClickHouse/pull/52450) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
|
||||
#### New Feature
|
||||
* Implement KQL-style formatting for Interval. [#45671](https://github.com/ClickHouse/ClickHouse/pull/45671) ([ltrk2](https://github.com/ltrk2)).
|
||||
* Support ZooKeeper `reconfig` command for CH Keeper with incremental reconfiguration which can be enabled via `keeper_server.enable_reconfiguration` setting. Support adding servers, removing servers, and changing server priorities. [#49450](https://github.com/ClickHouse/ClickHouse/pull/49450) ([Mike Kot](https://github.com/myrrc)).
|
||||
* Kafka connector can fetch avro schema from schema registry with basic authentication using url-encoded credentials. [#49664](https://github.com/ClickHouse/ClickHouse/pull/49664) ([Ilya Golshtein](https://github.com/ilejn)).
|
||||
* Add function `arrayJaccardIndex` which computes the Jaccard similarity between two arrays. [#50076](https://github.com/ClickHouse/ClickHouse/pull/50076) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||
* Added support for prql as a query language. [#50686](https://github.com/ClickHouse/ClickHouse/pull/50686) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)).
|
||||
* Add a column is_obsolete to system.settings and similar tables. Closes [#50819](https://github.com/ClickHouse/ClickHouse/issues/50819). [#50826](https://github.com/ClickHouse/ClickHouse/pull/50826) ([flynn](https://github.com/ucasfl)).
|
||||
* Implement support of encrypted elements in configuration file Added possibility to use encrypted text in leaf elements of configuration file. The text is encrypted using encryption codecs from <encryption_codecs> section. [#50986](https://github.com/ClickHouse/ClickHouse/pull/50986) ([Roman Vasin](https://github.com/rvasin)).
|
||||
* Just a new request of [#49483](https://github.com/ClickHouse/ClickHouse/issues/49483). [#51013](https://github.com/ClickHouse/ClickHouse/pull/51013) ([lgbo](https://github.com/lgbo-ustc)).
|
||||
* Add SYSTEM STOP LISTEN query. Closes [#47972](https://github.com/ClickHouse/ClickHouse/issues/47972). [#51016](https://github.com/ClickHouse/ClickHouse/pull/51016) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Add input_format_csv_allow_variable_number_of_columns options. [#51273](https://github.com/ClickHouse/ClickHouse/pull/51273) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Another boring feature: add function substring_index, as in spark or mysql. [#51472](https://github.com/ClickHouse/ClickHouse/pull/51472) ([李扬](https://github.com/taiyang-li)).
|
||||
* Show stats for jemalloc bins. Example ``` SELECT *, size * (nmalloc - ndalloc) AS allocated_bytes FROM system.jemalloc_bins WHERE allocated_bytes > 0 ORDER BY allocated_bytes DESC LIMIT 10. [#51674](https://github.com/ClickHouse/ClickHouse/pull/51674) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Add RowBinaryWithDefaults format with extra byte before each column for using column default value. Closes [#50854](https://github.com/ClickHouse/ClickHouse/issues/50854). [#51695](https://github.com/ClickHouse/ClickHouse/pull/51695) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Added `default_temporary_table_engine` setting. Same as `default_table_engine` but for temporary tables. [#51292](https://github.com/ClickHouse/ClickHouse/issues/51292). [#51708](https://github.com/ClickHouse/ClickHouse/pull/51708) ([velavokr](https://github.com/velavokr)).
|
||||
* Added new initcap / initcapUTF8 functions which convert the first letter of each word to upper case and the rest to lower case. [#51735](https://github.com/ClickHouse/ClickHouse/pull/51735) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Create table now supports `PRIMARY KEY` syntax in column definition. Columns are added to primary index in the same order columns are defined. [#51881](https://github.com/ClickHouse/ClickHouse/pull/51881) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Added the possibility to use date and time format specifiers in log and error log file names, either in config files (`log` and `errorlog` tags) or command line arguments (`--log-file` and `--errorlog-file`). [#51945](https://github.com/ClickHouse/ClickHouse/pull/51945) ([Victor Krasnov](https://github.com/sirvickr)).
|
||||
* Added Peak Memory Usage (for query) to client final statistics, and to http header. [#51946](https://github.com/ClickHouse/ClickHouse/pull/51946) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Added new hasSubsequence() (+CaseInsensitive + UTF8 versions) functions. [#52050](https://github.com/ClickHouse/ClickHouse/pull/52050) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Add `array_agg` as alias of `groupArray` for PostgreSQL compatibility. Closes [#52100](https://github.com/ClickHouse/ClickHouse/issues/52100). ### Documentation entry for user-facing changes. [#52135](https://github.com/ClickHouse/ClickHouse/pull/52135) ([flynn](https://github.com/ucasfl)).
|
||||
* Add `any_value` as a compatibility alias for `any` aggregate function. Closes [#52140](https://github.com/ClickHouse/ClickHouse/issues/52140). [#52147](https://github.com/ClickHouse/ClickHouse/pull/52147) ([flynn](https://github.com/ucasfl)).
|
||||
* Add aggregate function `array_concat_agg` for compatibility with BigQuery, it's alias of `groupArrayArray`. Closes [#52139](https://github.com/ClickHouse/ClickHouse/issues/52139). [#52149](https://github.com/ClickHouse/ClickHouse/pull/52149) ([flynn](https://github.com/ucasfl)).
|
||||
* Add `OCTET_LENGTH` as an alias to `length`. Closes [#52153](https://github.com/ClickHouse/ClickHouse/issues/52153). [#52176](https://github.com/ClickHouse/ClickHouse/pull/52176) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||
* Re-add SipHash keyed functions. [#52206](https://github.com/ClickHouse/ClickHouse/pull/52206) ([Salvatore Mesoraca](https://github.com/aiven-sal)).
|
||||
* Added `firstLine` function to extract the first line from the multi-line string. This closes [#51172](https://github.com/ClickHouse/ClickHouse/issues/51172). [#52209](https://github.com/ClickHouse/ClickHouse/pull/52209) ([Mikhail Koviazin](https://github.com/mkmkme)).
|
||||
|
||||
#### Performance Improvement
|
||||
* Enable `move_all_conditions_to_prewhere` and `enable_multiple_prewhere_read_steps` settings by default. [#46365](https://github.com/ClickHouse/ClickHouse/pull/46365) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Improves performance of some queries by tuning allocator. [#46416](https://github.com/ClickHouse/ClickHouse/pull/46416) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Writing parquet files is 10x faster, it's multi-threaded now. Almost the same speed as reading. [#49367](https://github.com/ClickHouse/ClickHouse/pull/49367) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Enable automatic selection of the sparse serialization format by default. It improves performance. The format is supported since version 22.1. After this change, downgrading to versions older than 22.1 might not be possible. You can turn off the usage of the sparse serialization format by providing the `ratio_of_defaults_for_sparse_serialization = 1` setting for your MergeTree tables. [#49631](https://github.com/ClickHouse/ClickHouse/pull/49631) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Now we use fixed-size tasks in `MergeTreePrefetchedReadPool` as in `MergeTreeReadPool`. Also from now we use connection pool for S3 requests. [#49732](https://github.com/ClickHouse/ClickHouse/pull/49732) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* More pushdown to the right side of join. [#50532](https://github.com/ClickHouse/ClickHouse/pull/50532) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Improve grace_hash join by reserving hash table's size (resubmit). [#50875](https://github.com/ClickHouse/ClickHouse/pull/50875) ([lgbo](https://github.com/lgbo-ustc)).
|
||||
* Waiting on lock in `OpenedFileCache` could be noticeable sometimes. We sharded it into multiple sub-maps (each with its own lock) to avoid contention. [#51341](https://github.com/ClickHouse/ClickHouse/pull/51341) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Remove duplicate condition in functionunixtimestamp64.h. [#51857](https://github.com/ClickHouse/ClickHouse/pull/51857) ([lcjh](https://github.com/ljhcage)).
|
||||
* The idea is that conditions with PK columns are likely to be used in PK analysis and will not contribute much more to PREWHERE filtering. [#51958](https://github.com/ClickHouse/ClickHouse/pull/51958) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* 1. Add rewriter for both old and new analyzer. 2. Add settings `optimize_uniq_to_count` which default is 0. [#52004](https://github.com/ClickHouse/ClickHouse/pull/52004) ([JackyWoo](https://github.com/JackyWoo)).
|
||||
* The performance experiments of **OnTime** on the ICX device (Intel Xeon Platinum 8380 CPU, 80 cores, 160 threads) show that this change could bring an improvement of **11.6%** to the QPS of the query **Q8** while having no impact on others. [#52036](https://github.com/ClickHouse/ClickHouse/pull/52036) ([Zhiguo Zhou](https://github.com/ZhiguoZh)).
|
||||
* Enable `allow_vertical_merges_from_compact_to_wide_parts` by default. It will save memory usage during merges. [#52295](https://github.com/ClickHouse/ClickHouse/pull/52295) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix incorrect projection analysis which invalidates primary keys. This issue only exists when `query_plan_optimize_primary_key = 1, query_plan_optimize_projection = 1` . This fixes [#48823](https://github.com/ClickHouse/ClickHouse/issues/48823) . This fixes [#51173](https://github.com/ClickHouse/ClickHouse/issues/51173) . [#52308](https://github.com/ClickHouse/ClickHouse/pull/52308) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Reduce the number of syscalls in FileCache::loadMetadata. [#52435](https://github.com/ClickHouse/ClickHouse/pull/52435) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
|
||||
#### Improvement
|
||||
* Added query `SYSTEM FLUSH ASYNC INSERT QUEUE` which flushes all pending asynchronous inserts to the destination tables. Added a server-side setting `async_insert_queue_flush_on_shutdown` (`true` by default) which determines whether to flush queue of asynchronous inserts on graceful shutdown. Setting `async_insert_threads` is now a server-side setting. [#49160](https://github.com/ClickHouse/ClickHouse/pull/49160) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* Don't show messages about `16 EiB` free space in logs, as they don't make sense. This closes [#49320](https://github.com/ClickHouse/ClickHouse/issues/49320). [#49342](https://github.com/ClickHouse/ClickHouse/pull/49342) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Properly check the limit for the `sleepEachRow` function. Add a setting `function_sleep_max_microseconds_per_block`. This is needed for generic query fuzzer. [#49343](https://github.com/ClickHouse/ClickHouse/pull/49343) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix two issues: ``` select geohashEncode(120.2, number::Float64) from numbers(10);. [#50066](https://github.com/ClickHouse/ClickHouse/pull/50066) ([李扬](https://github.com/taiyang-li)).
|
||||
* Add support for external disks in Keeper for storing snapshots and logs. [#50098](https://github.com/ClickHouse/ClickHouse/pull/50098) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Add support for multi-directory selection (`{}`) globs. [#50559](https://github.com/ClickHouse/ClickHouse/pull/50559) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Allow to have strict lower boundary for file segment size by downloading remaining data in the background. Minimum size of file segment (if actual file size is bigger) is configured as cache configuration setting `boundary_alignment`, by default `4Mi`. Number of background threads are configured as cache configuration setting `background_download_threads`, by default `2`. Also `max_file_segment_size` was increased from `8Mi` to `32Mi` in this PR. [#51000](https://github.com/ClickHouse/ClickHouse/pull/51000) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Allow filtering HTTP headers with `http_forbid_headers` section in config. Both exact matching and regexp filters are available. [#51038](https://github.com/ClickHouse/ClickHouse/pull/51038) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* #50727 new alias for function current_database and added new function current_schemas. [#51076](https://github.com/ClickHouse/ClickHouse/pull/51076) ([Pedro Riera](https://github.com/priera)).
|
||||
* Log async insert flush queries into to system.query_log. [#51160](https://github.com/ClickHouse/ClickHouse/pull/51160) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Decreased default timeouts for S3 from 30 seconds to 3 seconds, and for other HTTP from 180 seconds to 30 seconds. [#51171](https://github.com/ClickHouse/ClickHouse/pull/51171) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Use read_bytes/total_bytes_to_read for progress bar in s3/file/url/... table functions for better progress indication. [#51286](https://github.com/ClickHouse/ClickHouse/pull/51286) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Functions "date_diff() and age()" now support millisecond/microsecond unit and work with microsecond precision. [#51291](https://github.com/ClickHouse/ClickHouse/pull/51291) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Allow SQL standard `FETCH` without `OFFSET`. See https://antonz.org/sql-fetch/. [#51293](https://github.com/ClickHouse/ClickHouse/pull/51293) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Improve parsing of path in clickhouse-keeper-client. [#51359](https://github.com/ClickHouse/ClickHouse/pull/51359) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* A third-party product depending on ClickHouse (Gluten: Plugin to Double SparkSQL's Performance) had a bug. This fix avoids heap overflow in that third-party product while reading from HDFS. [#51386](https://github.com/ClickHouse/ClickHouse/pull/51386) ([李扬](https://github.com/taiyang-li)).
|
||||
* Fix checking error caused by uninitialized class members. [#51418](https://github.com/ClickHouse/ClickHouse/pull/51418) ([李扬](https://github.com/taiyang-li)).
|
||||
* Add ability to disable native copy for S3 (setting for BACKUP/RESTORE `allow_s3_native_copy`, and `s3_allow_native_copy` for `s3`/`s3_plain` disks). [#51448](https://github.com/ClickHouse/ClickHouse/pull/51448) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Add column `primary_key_size` to `system.parts` table to show compressed primary key size on disk. Closes [#51400](https://github.com/ClickHouse/ClickHouse/issues/51400). [#51496](https://github.com/ClickHouse/ClickHouse/pull/51496) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
|
||||
* Allow running `clickhouse-local` without procfs, without home directory existing, and without name resolution plugins from glibc. [#51518](https://github.com/ClickHouse/ClickHouse/pull/51518) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Correcting the message of modify storage policy https://github.com/clickhouse/clickhouse/issues/51516 ### documentation entry for user-facing changes. [#51519](https://github.com/ClickHouse/ClickHouse/pull/51519) ([xiaolei565](https://github.com/xiaolei565)).
|
||||
* Support `DROP FILESYSTEM CACHE <cache_name> KEY <key> [ OFFSET <offset>]`. [#51547](https://github.com/ClickHouse/ClickHouse/pull/51547) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Allow to add disk name for custom disks. Previously custom disks would use an internal generated disk name. Now it will be possible with `disk = disk_<name>(...)` (e.g. disk will have name `name`) . [#51552](https://github.com/ClickHouse/ClickHouse/pull/51552) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Add placeholder `%a` for rull filename in rename_files_after_processing setting. [#51603](https://github.com/ClickHouse/ClickHouse/pull/51603) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Add column modification time into system.parts_columns. [#51685](https://github.com/ClickHouse/ClickHouse/pull/51685) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Add new setting `input_format_csv_use_default_on_bad_values` to CSV format that allows to insert default value when parsing of a single field failed. [#51716](https://github.com/ClickHouse/ClickHouse/pull/51716) ([KevinyhZou](https://github.com/KevinyhZou)).
|
||||
* Added a crash log flush to the disk after the unexpected crash. [#51720](https://github.com/ClickHouse/ClickHouse/pull/51720) ([Alexey Gerasimchuck](https://github.com/Demilivor)).
|
||||
* Fix behavior in dashboard page where errors unrelated to authentication are not shown. Also fix 'overlapping' chart behavior. [#51744](https://github.com/ClickHouse/ClickHouse/pull/51744) ([Zach Naimon](https://github.com/ArctypeZach)).
|
||||
* Allow UUID to UInt128 conversion. [#51765](https://github.com/ClickHouse/ClickHouse/pull/51765) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Added support for function range of Nullable arguments. [#51767](https://github.com/ClickHouse/ClickHouse/pull/51767) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Convert condition like `toyear(x) = c` to `c1 <= x < c2`. [#51795](https://github.com/ClickHouse/ClickHouse/pull/51795) ([Han Fei](https://github.com/hanfei1991)).
|
||||
* Improve MySQL compatibility of statement SHOW INDEX. [#51796](https://github.com/ClickHouse/ClickHouse/pull/51796) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Fix `use_structure_from_insertion_table_in_table_functions` does not work with `MATERIALIZED` and `ALIAS` columns. Closes [#51817](https://github.com/ClickHouse/ClickHouse/issues/51817). Closes [#51019](https://github.com/ClickHouse/ClickHouse/issues/51019). [#51825](https://github.com/ClickHouse/ClickHouse/pull/51825) ([flynn](https://github.com/ucasfl)).
|
||||
* Introduce a table setting `wait_for_unique_parts_send_before_shutdown_ms` which specify the amount of time replica will wait before closing interserver handler for replicated sends. Also fix inconsistency with shutdown of tables and interserver handlers: now server shutdown tables first and only after it shut down interserver handlers. [#51851](https://github.com/ClickHouse/ClickHouse/pull/51851) ([alesapin](https://github.com/alesapin)).
|
||||
* CacheDictionary request only unique keys from source. Closes [#51762](https://github.com/ClickHouse/ClickHouse/issues/51762). [#51853](https://github.com/ClickHouse/ClickHouse/pull/51853) ([Maksim Kita](https://github.com/kitaisreal)).
|
||||
* Fixed settings not applied for explain query when format provided. [#51859](https://github.com/ClickHouse/ClickHouse/pull/51859) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Allow SETTINGS before FORMAT in DESCRIBE TABLE query for compatibility with SELECT query. Closes [#51544](https://github.com/ClickHouse/ClickHouse/issues/51544). [#51899](https://github.com/ClickHouse/ClickHouse/pull/51899) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Var-int encoded integers (e.g. used by the native protocol) can now use the full 64-bit range. 3rd party clients are advised to update their var-int code accordingly. [#51905](https://github.com/ClickHouse/ClickHouse/pull/51905) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Update certificates when they change without the need to manually SYSTEM RELOAD CONFIG. [#52030](https://github.com/ClickHouse/ClickHouse/pull/52030) ([Mike Kot](https://github.com/myrrc)).
|
||||
* Added `allow_create_index_without_type` setting that allow to ignore `ADD INDEX` queries without specified `TYPE`. Standard SQL queries will just succeed without changing table schema. [#52056](https://github.com/ClickHouse/ClickHouse/pull/52056) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Fixed crash when mysqlxx::Pool::Entry is used after it was disconnected. [#52063](https://github.com/ClickHouse/ClickHouse/pull/52063) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* CREATE TABLE ... AS SELECT .. is now supported in MaterializedMySQL. [#52067](https://github.com/ClickHouse/ClickHouse/pull/52067) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Introduced automatic conversion of text types to utf8 for MaterializedMySQL. [#52084](https://github.com/ClickHouse/ClickHouse/pull/52084) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Add alias for functions `today` (now available under the `curdate`/`current_date` names) and `now` (`current_timestamp`). [#52106](https://github.com/ClickHouse/ClickHouse/pull/52106) ([Lloyd-Pottiger](https://github.com/Lloyd-Pottiger)).
|
||||
* Log messages are written to text_log from the beginning. [#52113](https://github.com/ClickHouse/ClickHouse/pull/52113) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* In cases where the HTTP endpoint has multiple IP addresses and the first of them is unreachable, a timeout exception will be thrown. Made session creation with handling all resolved endpoints. [#52116](https://github.com/ClickHouse/ClickHouse/pull/52116) ([Aleksei Filatov](https://github.com/aalexfvk)).
|
||||
* Support async_deduplication_token for async insert. [#52136](https://github.com/ClickHouse/ClickHouse/pull/52136) ([Han Fei](https://github.com/hanfei1991)).
|
||||
* Avro input format support Union with single type. Closes [#52131](https://github.com/ClickHouse/ClickHouse/issues/52131). [#52137](https://github.com/ClickHouse/ClickHouse/pull/52137) ([flynn](https://github.com/ucasfl)).
|
||||
* Add setting `optimize_use_implicit_projections` to disable implicit projections (currently only `min_max_count` projection). This is defaulted to false until [#52075](https://github.com/ClickHouse/ClickHouse/issues/52075) is fixed. [#52152](https://github.com/ClickHouse/ClickHouse/pull/52152) ([Amos Bird](https://github.com/amosbird)).
|
||||
* It was possible to use the function `hasToken` for infinite loop. Now this possibility is removed. This closes [#52156](https://github.com/ClickHouse/ClickHouse/issues/52156). [#52160](https://github.com/ClickHouse/ClickHouse/pull/52160) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* 1. Upgrade Intel QPL from v1.1.0 to v1.2.0 2. Upgrade Intel accel-config from v3.5 to v4.0 3. Fixed issue that Device IOTLB miss has big perf. impact for IAA accelerators. [#52180](https://github.com/ClickHouse/ClickHouse/pull/52180) ([jasperzhu](https://github.com/jinjunzh)).
|
||||
* Functions "date_diff() and age()" now support millisecond/microsecond unit and work with microsecond precision. [#52181](https://github.com/ClickHouse/ClickHouse/pull/52181) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Create ZK ancestors optimistically. [#52195](https://github.com/ClickHouse/ClickHouse/pull/52195) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Fix [#50582](https://github.com/ClickHouse/ClickHouse/issues/50582). Avoid the `Not found column ... in block` error in some cases of reading in-order and constants. [#52259](https://github.com/ClickHouse/ClickHouse/pull/52259) ([Chen768959](https://github.com/Chen768959)).
|
||||
* Check whether S2 geo primitives are invalid as early as possible on ClickHouse side. This closes: [#27090](https://github.com/ClickHouse/ClickHouse/issues/27090). [#52260](https://github.com/ClickHouse/ClickHouse/pull/52260) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* Now unquoted utf-8 strings are supported in DDL for MaterializedMySQL. [#52318](https://github.com/ClickHouse/ClickHouse/pull/52318) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Add back missing projection QueryAccessInfo when `query_plan_optimize_projection = 1`. This fixes [#50183](https://github.com/ClickHouse/ClickHouse/issues/50183) . This fixes [#50093](https://github.com/ClickHouse/ClickHouse/issues/50093) . [#52327](https://github.com/ClickHouse/ClickHouse/pull/52327) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Add new setting `disable_url_encoding` that allows to disable decoding/encoding path in uri in URL engine. [#52337](https://github.com/ClickHouse/ClickHouse/pull/52337) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* When `ZooKeeperRetriesControl` rethrows an error, it's more useful to see its original stack trace, not the one from `ZooKeeperRetriesControl` itself. [#52347](https://github.com/ClickHouse/ClickHouse/pull/52347) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||
* Now double quoted comments are supported in MaterializedMySQL. [#52355](https://github.com/ClickHouse/ClickHouse/pull/52355) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Wait for zero copy replication lock even if some disks don't support it. [#52376](https://github.com/ClickHouse/ClickHouse/pull/52376) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Now it's possible to specify min (`memory_profiler_sample_min_allocation_size`) and max (`memory_profiler_sample_max_allocation_size`) size for allocations to be tracked with sampling memory profiler. [#52419](https://github.com/ClickHouse/ClickHouse/pull/52419) ([alesapin](https://github.com/alesapin)).
|
||||
* The `session_timezone` setting is demoted to experimental. [#52445](https://github.com/ClickHouse/ClickHouse/pull/52445) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Now interserver port will be closed only after tables are shut down. [#52498](https://github.com/ClickHouse/ClickHouse/pull/52498) ([alesapin](https://github.com/alesapin)).
|
||||
* Added field `refcount` to `system.remote_data_paths` table. [#52518](https://github.com/ClickHouse/ClickHouse/pull/52518) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* New setting `merge_tree_determine_task_size_by_prewhere_columns` added. If set to `true` only sizes of the columns from `PREWHERE` section will be considered to determine reading task size. Otherwise all the columns from query are considered. [#52606](https://github.com/ClickHouse/ClickHouse/pull/52606) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
|
||||
#### Build/Testing/Packaging Improvement
|
||||
* Add experimental ClickHouse builds for Linux RISC-V 64 to CI. [#31398](https://github.com/ClickHouse/ClickHouse/pull/31398) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fixed CRC32(WeakHash32) issue for s390x. [#50365](https://github.com/ClickHouse/ClickHouse/pull/50365) ([Harry Lee](https://github.com/HarryLeeIBM)).
|
||||
* Add integration test check with the enabled analyzer. [#50926](https://github.com/ClickHouse/ClickHouse/pull/50926) ([Dmitry Novik](https://github.com/novikd)).
|
||||
* Update cargo dependencies. [#51721](https://github.com/ClickHouse/ClickHouse/pull/51721) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Fixed several issues found by OSS-Fuzz. [#51736](https://github.com/ClickHouse/ClickHouse/pull/51736) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* There were a couple of failures because of (?) S3 availability. The sccache has a feature of failing over to local compilation. [#51893](https://github.com/ClickHouse/ClickHouse/pull/51893) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
* 02242_delete_user_race and 02243_drop_user_grant_race tests have been corrected. [#51923](https://github.com/ClickHouse/ClickHouse/pull/51923) ([Alexey Gerasimchuck](https://github.com/Demilivor)).
|
||||
* Make the function `CHColumnToArrowColumn::fillArrowArrayWithArrayColumnData` to work with nullable arrays, which are not possible in ClickHouse, but needed for Gluten. [#52112](https://github.com/ClickHouse/ClickHouse/pull/52112) ([李扬](https://github.com/taiyang-li)).
|
||||
* We've updated the CCTZ library to master, but there are no user-visible changes. [#52124](https://github.com/ClickHouse/ClickHouse/pull/52124) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* The `system.licenses` table now includes the hard-forked library Poco. This closes [#52066](https://github.com/ClickHouse/ClickHouse/issues/52066). [#52127](https://github.com/ClickHouse/ClickHouse/pull/52127) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Follow up [#50926](https://github.com/ClickHouse/ClickHouse/issues/50926). Add integration tests check with enabled analyzer to master. [#52210](https://github.com/ClickHouse/ClickHouse/pull/52210) ([Dmitry Novik](https://github.com/novikd)).
|
||||
* Reproducible builds for Rust. [#52395](https://github.com/ClickHouse/ClickHouse/pull/52395) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Improve the startup time of `clickhouse-client` and `clickhouse-local` in debug and sanitizer builds. This closes [#52228](https://github.com/ClickHouse/ClickHouse/issues/52228). [#52489](https://github.com/ClickHouse/ClickHouse/pull/52489) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Check that there are no cases of bad punctuation: whitespace before a comma like `Hello ,world` instead of `Hello, world`. [#52549](https://github.com/ClickHouse/ClickHouse/pull/52549) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
|
||||
#### Bug Fix (user-visible misbehavior in an official stable release)
|
||||
|
||||
* Fix materialised pg syncTables [#49698](https://github.com/ClickHouse/ClickHouse/pull/49698) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix projection with optimize_aggregators_of_group_by_keys [#49709](https://github.com/ClickHouse/ClickHouse/pull/49709) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix optimize_skip_unused_shards with JOINs [#51037](https://github.com/ClickHouse/ClickHouse/pull/51037) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix formatDateTime() with fractional negative datetime64 [#51290](https://github.com/ClickHouse/ClickHouse/pull/51290) ([Dmitry Kardymon](https://github.com/kardymonds)).
|
||||
* Functions `hasToken*` were totally wrong. Add a test for [#43358](https://github.com/ClickHouse/ClickHouse/issues/43358) [#51378](https://github.com/ClickHouse/ClickHouse/pull/51378) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix optimization to move functions before sorting. [#51481](https://github.com/ClickHouse/ClickHouse/pull/51481) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* Fix Block structure mismatch in Pipe::unitePipes for FINAL [#51492](https://github.com/ClickHouse/ClickHouse/pull/51492) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fix SIGSEGV for clusters with zero weight across all shards (fixes INSERT INTO FUNCTION clusterAllReplicas()) [#51545](https://github.com/ClickHouse/ClickHouse/pull/51545) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix timeout for hedged requests [#51582](https://github.com/ClickHouse/ClickHouse/pull/51582) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix logical error in ANTI join with NULL [#51601](https://github.com/ClickHouse/ClickHouse/pull/51601) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix for moving 'IN' conditions to PREWHERE [#51610](https://github.com/ClickHouse/ClickHouse/pull/51610) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Do not apply PredicateExpressionsOptimizer for ASOF/ANTI join [#51633](https://github.com/ClickHouse/ClickHouse/pull/51633) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix async insert with deduplication for ReplicatedMergeTree using merging algorithms [#51676](https://github.com/ClickHouse/ClickHouse/pull/51676) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix reading from empty column in `parseSipHashKey` [#51804](https://github.com/ClickHouse/ClickHouse/pull/51804) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fix segfault when create invalid EmbeddedRocksdb table [#51847](https://github.com/ClickHouse/ClickHouse/pull/51847) ([Duc Canh Le](https://github.com/canhld94)).
|
||||
* Fix inserts into MongoDB tables [#51876](https://github.com/ClickHouse/ClickHouse/pull/51876) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Fix deadlock on DatabaseCatalog shutdown [#51908](https://github.com/ClickHouse/ClickHouse/pull/51908) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix error in subquery operators [#51922](https://github.com/ClickHouse/ClickHouse/pull/51922) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix async connect to hosts with multiple ips [#51934](https://github.com/ClickHouse/ClickHouse/pull/51934) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Do not remove inputs after ActionsDAG::merge [#51947](https://github.com/ClickHouse/ClickHouse/pull/51947) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* Check refcount in `RemoveManyObjectStorageOperation::finalize` instead of `execute` [#51954](https://github.com/ClickHouse/ClickHouse/pull/51954) ([vdimir](https://github.com/vdimir)).
|
||||
* Allow parametric UDFs [#51964](https://github.com/ClickHouse/ClickHouse/pull/51964) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Small fix for toDateTime64() for dates after 2283-12-31 [#52130](https://github.com/ClickHouse/ClickHouse/pull/52130) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Fix ORDER BY tuple of WINDOW functions [#52145](https://github.com/ClickHouse/ClickHouse/pull/52145) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix incorrect projection analysis when aggregation expression contains monotonic functions [#52151](https://github.com/ClickHouse/ClickHouse/pull/52151) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix error in `groupArrayMoving` functions [#52161](https://github.com/ClickHouse/ClickHouse/pull/52161) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Disable direct join for range dictionary [#52187](https://github.com/ClickHouse/ClickHouse/pull/52187) ([Duc Canh Le](https://github.com/canhld94)).
|
||||
* Fix sticky mutations test (and extremely rare race condition) [#52197](https://github.com/ClickHouse/ClickHouse/pull/52197) ([alesapin](https://github.com/alesapin)).
|
||||
* Fix race in Web disk [#52211](https://github.com/ClickHouse/ClickHouse/pull/52211) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix data race in Connection::setAsyncCallback on unknown packet from server [#52219](https://github.com/ClickHouse/ClickHouse/pull/52219) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Fix temp data deletion on startup, add test [#52275](https://github.com/ClickHouse/ClickHouse/pull/52275) ([vdimir](https://github.com/vdimir)).
|
||||
* Don't use minmax_count projections when counting nullable columns [#52297](https://github.com/ClickHouse/ClickHouse/pull/52297) ([Amos Bird](https://github.com/amosbird)).
|
||||
* MergeTree/ReplicatedMergeTree should use server timezone for log entries [#52325](https://github.com/ClickHouse/ClickHouse/pull/52325) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix parameterized view with cte and multiple usage [#52328](https://github.com/ClickHouse/ClickHouse/pull/52328) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||
* Disable expression templates for time intervals [#52335](https://github.com/ClickHouse/ClickHouse/pull/52335) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix `apply_snapshot` in Keeper [#52358](https://github.com/ClickHouse/ClickHouse/pull/52358) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Update build-osx.md [#52377](https://github.com/ClickHouse/ClickHouse/pull/52377) ([AlexBykovski](https://github.com/AlexBykovski)).
|
||||
* Fix `countSubstrings()` hang with empty needle and a column haystack [#52409](https://github.com/ClickHouse/ClickHouse/pull/52409) ([Sergei Trifonov](https://github.com/serxa)).
|
||||
* Fix normal projection with merge table [#52432](https://github.com/ClickHouse/ClickHouse/pull/52432) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Fix possible double-free in Aggregator [#52439](https://github.com/ClickHouse/ClickHouse/pull/52439) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Fixed inserting into Buffer engine [#52440](https://github.com/ClickHouse/ClickHouse/pull/52440) ([Vasily Nemkov](https://github.com/Enmk)).
|
||||
* The implementation of AnyHash was non-conformant. [#52448](https://github.com/ClickHouse/ClickHouse/pull/52448) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Check recursion depth in OptimizedRegularExpression [#52451](https://github.com/ClickHouse/ClickHouse/pull/52451) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix data-race DatabaseReplicated::startupTables()/canExecuteReplicatedMetadataAlter() [#52490](https://github.com/ClickHouse/ClickHouse/pull/52490) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix abort in function `transform` [#52513](https://github.com/ClickHouse/ClickHouse/pull/52513) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix lightweight delete after drop of projection [#52517](https://github.com/ClickHouse/ClickHouse/pull/52517) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* Fix possible error "Cannot drain connections: cancel first" [#52585](https://github.com/ClickHouse/ClickHouse/pull/52585) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
|
||||
#### NO CL ENTRY
|
||||
|
||||
* NO CL ENTRY: 'Revert "Add documentation for building in docker"'. [#51773](https://github.com/ClickHouse/ClickHouse/pull/51773) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* NO CL ENTRY: 'Revert "Fix build"'. [#51911](https://github.com/ClickHouse/ClickHouse/pull/51911) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* NO CL ENTRY: 'Revert "Millisecond and microsecond support in date_diff / age functions"'. [#52129](https://github.com/ClickHouse/ClickHouse/pull/52129) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* NO CL ENTRY: 'Revert "Re-add SipHash keyed functions"'. [#52466](https://github.com/ClickHouse/ClickHouse/pull/52466) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* NO CL ENTRY: 'Revert "Add an ability to specify allocations size for sampling memory profiler"'. [#52496](https://github.com/ClickHouse/ClickHouse/pull/52496) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* NO CL ENTRY: 'Revert "Rewrite uniq to count"'. [#52576](https://github.com/ClickHouse/ClickHouse/pull/52576) ([Yarik Briukhovetskyi](https://github.com/yariks5s)).
|
||||
|
||||
#### NOT FOR CHANGELOG / INSIGNIFICANT
|
||||
|
||||
* Remove duplicate_order_by_and_distinct optimization [#47135](https://github.com/ClickHouse/ClickHouse/pull/47135) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Update sort desc in ReadFromMergeTree after applying PREWHERE info [#48669](https://github.com/ClickHouse/ClickHouse/pull/48669) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Fix `BindException: Address already in use` in HDFS integration tests [#49428](https://github.com/ClickHouse/ClickHouse/pull/49428) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Force libunwind usage (removes gcc_eh support) [#49438](https://github.com/ClickHouse/ClickHouse/pull/49438) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Cleanup `storage_conf.xml` [#49557](https://github.com/ClickHouse/ClickHouse/pull/49557) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix flaky tests caused by OPTIMIZE FINAL failing memory budget check [#49764](https://github.com/ClickHouse/ClickHouse/pull/49764) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Remove unstable queries from performance/join_set_filter [#50235](https://github.com/ClickHouse/ClickHouse/pull/50235) ([vdimir](https://github.com/vdimir)).
|
||||
* More accurate DNS resolve for the keeper connection [#50738](https://github.com/ClickHouse/ClickHouse/pull/50738) ([pufit](https://github.com/pufit)).
|
||||
* Try to fix some trash in Disks and part moves [#51135](https://github.com/ClickHouse/ClickHouse/pull/51135) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Add jemalloc support fro s390x [#51186](https://github.com/ClickHouse/ClickHouse/pull/51186) ([Boris Kuschel](https://github.com/bkuschel)).
|
||||
* Resubmit [#48821](https://github.com/ClickHouse/ClickHouse/issues/48821) [#51208](https://github.com/ClickHouse/ClickHouse/pull/51208) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* test for [#36894](https://github.com/ClickHouse/ClickHouse/issues/36894) [#51274](https://github.com/ClickHouse/ClickHouse/pull/51274) ([Denny Crane](https://github.com/den-crane)).
|
||||
* external_aggregation_fix for big endian machines [#51280](https://github.com/ClickHouse/ClickHouse/pull/51280) ([Sanjam Panda](https://github.com/saitama951)).
|
||||
* Fix: Invalid number of rows in Chunk column Object [#51296](https://github.com/ClickHouse/ClickHouse/pull/51296) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Add a test for [#44816](https://github.com/ClickHouse/ClickHouse/issues/44816) [#51305](https://github.com/ClickHouse/ClickHouse/pull/51305) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a test for `calculate_text_stack_trace` setting [#51311](https://github.com/ClickHouse/ClickHouse/pull/51311) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* decrease log level, make logs shorter [#51320](https://github.com/ClickHouse/ClickHouse/pull/51320) ([Sema Checherinda](https://github.com/CheSema)).
|
||||
* Collect stack traces from job's scheduling and print along with exception's stack trace. [#51349](https://github.com/ClickHouse/ClickHouse/pull/51349) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||
* Add a test for [#42691](https://github.com/ClickHouse/ClickHouse/issues/42691) [#51352](https://github.com/ClickHouse/ClickHouse/pull/51352) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a test for [#32474](https://github.com/ClickHouse/ClickHouse/issues/32474) [#51354](https://github.com/ClickHouse/ClickHouse/pull/51354) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a test for [#41727](https://github.com/ClickHouse/ClickHouse/issues/41727) [#51355](https://github.com/ClickHouse/ClickHouse/pull/51355) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a test for [#35801](https://github.com/ClickHouse/ClickHouse/issues/35801) [#51356](https://github.com/ClickHouse/ClickHouse/pull/51356) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a test for [#34626](https://github.com/ClickHouse/ClickHouse/issues/34626) [#51357](https://github.com/ClickHouse/ClickHouse/pull/51357) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Initialize text_log earlier to capture table startup messages [#51360](https://github.com/ClickHouse/ClickHouse/pull/51360) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Use separate default settings for clickhouse-local [#51363](https://github.com/ClickHouse/ClickHouse/pull/51363) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Attempt to remove wrong code (catch/throw in Functions) [#51367](https://github.com/ClickHouse/ClickHouse/pull/51367) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Remove suspicious code [#51383](https://github.com/ClickHouse/ClickHouse/pull/51383) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Disable hedged requests under TSan [#51392](https://github.com/ClickHouse/ClickHouse/pull/51392) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* no finalize in d-tor WriteBufferFromOStream [#51404](https://github.com/ClickHouse/ClickHouse/pull/51404) ([Sema Checherinda](https://github.com/CheSema)).
|
||||
* Better diagnostics for 01193_metadata_loading [#51414](https://github.com/ClickHouse/ClickHouse/pull/51414) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix attaching gdb in stress tests [#51445](https://github.com/ClickHouse/ClickHouse/pull/51445) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Merging [#36384](https://github.com/ClickHouse/ClickHouse/issues/36384) [#51458](https://github.com/ClickHouse/ClickHouse/pull/51458) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix possible race on shutdown wait [#51497](https://github.com/ClickHouse/ClickHouse/pull/51497) ([Sergei Trifonov](https://github.com/serxa)).
|
||||
* Fix `test_alter_moving_garbage`: lock between getActiveContainingPart and swapActivePart in parts mover [#51498](https://github.com/ClickHouse/ClickHouse/pull/51498) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix a logical error on mutation [#51502](https://github.com/ClickHouse/ClickHouse/pull/51502) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix running integration tests with spaces in it's names [#51514](https://github.com/ClickHouse/ClickHouse/pull/51514) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix flaky test 00417_kill_query [#51522](https://github.com/ClickHouse/ClickHouse/pull/51522) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* fs cache: add some checks [#51536](https://github.com/ClickHouse/ClickHouse/pull/51536) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Don't run 02782_uniq_exact_parallel_merging_bug in parallel with other tests [#51549](https://github.com/ClickHouse/ClickHouse/pull/51549) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* 00900_orc_load: lift kill timeout [#51559](https://github.com/ClickHouse/ClickHouse/pull/51559) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Add retries to 00416_pocopatch_progress_in_http_headers [#51575](https://github.com/ClickHouse/ClickHouse/pull/51575) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||
* Remove the usage of Analyzer setting in the client [#51578](https://github.com/ClickHouse/ClickHouse/pull/51578) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix merge_selecting_task scheduling [#51591](https://github.com/ClickHouse/ClickHouse/pull/51591) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Add hex functions for cityhash [#51595](https://github.com/ClickHouse/ClickHouse/pull/51595) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||
* Remove `unset CLICKHOUSE_LOG_COMMENT` from tests [#51623](https://github.com/ClickHouse/ClickHouse/pull/51623) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Implement endianness-independent serialization [#51637](https://github.com/ClickHouse/ClickHouse/pull/51637) ([ltrk2](https://github.com/ltrk2)).
|
||||
* Ignore APPEND and TRUNCATE modifiers if file does not exist. [#51640](https://github.com/ClickHouse/ClickHouse/pull/51640) ([alekar](https://github.com/alekar)).
|
||||
* Try to fix flaky 02210_processors_profile_log [#51641](https://github.com/ClickHouse/ClickHouse/pull/51641) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Make common macros extendable [#51646](https://github.com/ClickHouse/ClickHouse/pull/51646) ([Amos Bird](https://github.com/amosbird)).
|
||||
* Correct an exception message in src/Functions/nested.cpp [#51651](https://github.com/ClickHouse/ClickHouse/pull/51651) ([Alex Cheng](https://github.com/Alex-Cheng)).
|
||||
* tests: fix 02050_client_profile_events flakiness [#51653](https://github.com/ClickHouse/ClickHouse/pull/51653) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Minor follow-up to re2 update to 2023-06-02 ([#50949](https://github.com/ClickHouse/ClickHouse/issues/50949)) [#51655](https://github.com/ClickHouse/ClickHouse/pull/51655) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Fix 02116_tuple_element with Analyzer [#51669](https://github.com/ClickHouse/ClickHouse/pull/51669) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Update timeouts in tests for transactions [#51683](https://github.com/ClickHouse/ClickHouse/pull/51683) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Remove unused code [#51684](https://github.com/ClickHouse/ClickHouse/pull/51684) ([Sergei Trifonov](https://github.com/serxa)).
|
||||
* Remove `mmap/mremap/munmap` from Allocator.h [#51686](https://github.com/ClickHouse/ClickHouse/pull/51686) ([alesapin](https://github.com/alesapin)).
|
||||
* SonarCloud: Add C++23 Experimental Flag [#51687](https://github.com/ClickHouse/ClickHouse/pull/51687) ([Julio Jimenez](https://github.com/juliojimenez)).
|
||||
* Wait with retries when attaching GDB in tests [#51688](https://github.com/ClickHouse/ClickHouse/pull/51688) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Update version_date.tsv and changelogs after v23.6.1.1524-stable [#51691](https://github.com/ClickHouse/ClickHouse/pull/51691) ([robot-clickhouse](https://github.com/robot-clickhouse)).
|
||||
* fix write to finalized buffer [#51696](https://github.com/ClickHouse/ClickHouse/pull/51696) ([Sema Checherinda](https://github.com/CheSema)).
|
||||
* do not log exception aborted for pending mutate/merge entries when shutdown [#51697](https://github.com/ClickHouse/ClickHouse/pull/51697) ([Sema Checherinda](https://github.com/CheSema)).
|
||||
* Fix race in ContextAccess [#51704](https://github.com/ClickHouse/ClickHouse/pull/51704) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||
* Make test scripts backwards compatible [#51707](https://github.com/ClickHouse/ClickHouse/pull/51707) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* test for full join and null predicate [#51709](https://github.com/ClickHouse/ClickHouse/pull/51709) ([Denny Crane](https://github.com/den-crane)).
|
||||
* A cmake warning on job limits underutilizing CPU [#51710](https://github.com/ClickHouse/ClickHouse/pull/51710) ([velavokr](https://github.com/velavokr)).
|
||||
* Fix SQLLogic docker images [#51719](https://github.com/ClickHouse/ClickHouse/pull/51719) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Added ASK_PASSWORD client constant instead of hardcoded '\n' [#51723](https://github.com/ClickHouse/ClickHouse/pull/51723) ([Alexey Gerasimchuck](https://github.com/Demilivor)).
|
||||
* Update README.md [#51726](https://github.com/ClickHouse/ClickHouse/pull/51726) ([Tyler Hannan](https://github.com/tylerhannan)).
|
||||
* Fix source image for sqllogic [#51728](https://github.com/ClickHouse/ClickHouse/pull/51728) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
* Remove MemoryPool from Poco because it's useless [#51732](https://github.com/ClickHouse/ClickHouse/pull/51732) ([alesapin](https://github.com/alesapin)).
|
||||
* Fix: logical error in grace hash join [#51737](https://github.com/ClickHouse/ClickHouse/pull/51737) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Update 01320_create_sync_race_condition_zookeeper.sh [#51742](https://github.com/ClickHouse/ClickHouse/pull/51742) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Pin for docker-ce [#51743](https://github.com/ClickHouse/ClickHouse/pull/51743) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
* Revert "Fix: Invalid number of rows in Chunk column Object" [#51750](https://github.com/ClickHouse/ClickHouse/pull/51750) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Add SonarCloud to README [#51751](https://github.com/ClickHouse/ClickHouse/pull/51751) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Fix test `02789_object_type_invalid_num_of_rows` [#51754](https://github.com/ClickHouse/ClickHouse/pull/51754) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix (benign) data race in `transform` [#51755](https://github.com/ClickHouse/ClickHouse/pull/51755) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix flaky KeeperMap test [#51764](https://github.com/ClickHouse/ClickHouse/pull/51764) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Version mypy=1.4.1 falsly reports unused ignore comment [#51769](https://github.com/ClickHouse/ClickHouse/pull/51769) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
* Avoid keeping lock Context::getLock() while calculating access rights [#51772](https://github.com/ClickHouse/ClickHouse/pull/51772) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||
* Making stateless tests with timeout less flaky [#51774](https://github.com/ClickHouse/ClickHouse/pull/51774) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix after [#51000](https://github.com/ClickHouse/ClickHouse/issues/51000) [#51790](https://github.com/ClickHouse/ClickHouse/pull/51790) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Add assert in ThreadStatus destructor for correct current_thread [#51800](https://github.com/ClickHouse/ClickHouse/pull/51800) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Fix broken parts handling in `ReplicatedMergeTree` [#51801](https://github.com/ClickHouse/ClickHouse/pull/51801) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix tsan signal-unsafe call [#51802](https://github.com/ClickHouse/ClickHouse/pull/51802) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||
* Fix for parallel replicas not completely disabled by granule count threshold [#51805](https://github.com/ClickHouse/ClickHouse/pull/51805) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Make sure that we don't attempt to serialize/deserialize block with 0 columns and non-zero rows [#51807](https://github.com/ClickHouse/ClickHouse/pull/51807) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Fix rare bug in `DROP COLUMN` and enabled sparse columns [#51809](https://github.com/ClickHouse/ClickHouse/pull/51809) ([Anton Popov](https://github.com/CurtizJ)).
|
||||
* Fix flaky `test_multiple_disks` [#51821](https://github.com/ClickHouse/ClickHouse/pull/51821) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Follow up to [#51547](https://github.com/ClickHouse/ClickHouse/issues/51547) [#51822](https://github.com/ClickHouse/ClickHouse/pull/51822) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Correctly grep archives in stress tests [#51824](https://github.com/ClickHouse/ClickHouse/pull/51824) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Update analyzer_tech_debt.txt [#51836](https://github.com/ClickHouse/ClickHouse/pull/51836) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* remove unused code [#51837](https://github.com/ClickHouse/ClickHouse/pull/51837) ([flynn](https://github.com/ucasfl)).
|
||||
* Fix disk config for upgrade tests [#51839](https://github.com/ClickHouse/ClickHouse/pull/51839) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Remove Coverity from workflows, but leave in the code [#51842](https://github.com/ClickHouse/ClickHouse/pull/51842) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Many fixes [3] [#51848](https://github.com/ClickHouse/ClickHouse/pull/51848) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Change misleading name in joins: addJoinedBlock -> addBlockToJoin [#51852](https://github.com/ClickHouse/ClickHouse/pull/51852) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* fix: correct exception messages on policies comparison [#51854](https://github.com/ClickHouse/ClickHouse/pull/51854) ([Feng Kaiyu](https://github.com/fky2015)).
|
||||
* Update 02439_merge_selecting_partitions.sql [#51862](https://github.com/ClickHouse/ClickHouse/pull/51862) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Remove useless packages [#51863](https://github.com/ClickHouse/ClickHouse/pull/51863) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Remove useless logs [#51865](https://github.com/ClickHouse/ClickHouse/pull/51865) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix incorrect log level = warning [#51867](https://github.com/ClickHouse/ClickHouse/pull/51867) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix test_replicated_table_attach [#51868](https://github.com/ClickHouse/ClickHouse/pull/51868) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Better usability of a test [#51869](https://github.com/ClickHouse/ClickHouse/pull/51869) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Remove useless code [#51873](https://github.com/ClickHouse/ClickHouse/pull/51873) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Another fix upgrade check script [#51878](https://github.com/ClickHouse/ClickHouse/pull/51878) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Sqlloogic improvements [#51883](https://github.com/ClickHouse/ClickHouse/pull/51883) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Disable ThinLTO on non-Linux [#51897](https://github.com/ClickHouse/ClickHouse/pull/51897) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Pin rust nightly (to make it stable) [#51903](https://github.com/ClickHouse/ClickHouse/pull/51903) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix build [#51909](https://github.com/ClickHouse/ClickHouse/pull/51909) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix build [#51910](https://github.com/ClickHouse/ClickHouse/pull/51910) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix flaky test `00175_partition_by_ignore` and move it to correct location [#51913](https://github.com/ClickHouse/ClickHouse/pull/51913) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix flaky test 02360_send_logs_level_colors: avoid usage of `file` tool [#51914](https://github.com/ClickHouse/ClickHouse/pull/51914) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Maybe better tests [#51916](https://github.com/ClickHouse/ClickHouse/pull/51916) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Revert system drop filesystem cache by key [#51917](https://github.com/ClickHouse/ClickHouse/pull/51917) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix flaky test `detach_attach_partition_race` [#51920](https://github.com/ClickHouse/ClickHouse/pull/51920) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Another fix for `02481_async_insert_race_long` [#51925](https://github.com/ClickHouse/ClickHouse/pull/51925) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix segfault caused by `ThreadStatus` [#51931](https://github.com/ClickHouse/ClickHouse/pull/51931) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Print short fault info only from safe fields [#51932](https://github.com/ClickHouse/ClickHouse/pull/51932) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Fix typo in integration tests [#51944](https://github.com/ClickHouse/ClickHouse/pull/51944) ([Ilya Yatsishin](https://github.com/qoega)).
|
||||
* Better logs on shutdown [#51951](https://github.com/ClickHouse/ClickHouse/pull/51951) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Filter databases list before querying potentially slow fields [#51955](https://github.com/ClickHouse/ClickHouse/pull/51955) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Fix some issues with transactions [#51959](https://github.com/ClickHouse/ClickHouse/pull/51959) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix unrelated messages from LSan in clickhouse-client [#51966](https://github.com/ClickHouse/ClickHouse/pull/51966) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Allow OOM in AST Fuzzer with Sanitizers [#51967](https://github.com/ClickHouse/ClickHouse/pull/51967) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Disable one test under Analyzer [#51968](https://github.com/ClickHouse/ClickHouse/pull/51968) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix Docker [#51969](https://github.com/ClickHouse/ClickHouse/pull/51969) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix test `01825_type_json_from_map` [#51970](https://github.com/ClickHouse/ClickHouse/pull/51970) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix test `02354_distributed_with_external_aggregation_memory_usage` [#51971](https://github.com/ClickHouse/ClickHouse/pull/51971) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix disaster in integration tests, part 2 [#51973](https://github.com/ClickHouse/ClickHouse/pull/51973) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* [RFC] Cleanup remote_servers in dist config.xml [#51985](https://github.com/ClickHouse/ClickHouse/pull/51985) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update version_date.tsv and changelogs after v23.6.2.18-stable [#51986](https://github.com/ClickHouse/ClickHouse/pull/51986) ([robot-clickhouse](https://github.com/robot-clickhouse)).
|
||||
* Update version_date.tsv and changelogs after v22.8.20.11-lts [#51987](https://github.com/ClickHouse/ClickHouse/pull/51987) ([robot-clickhouse](https://github.com/robot-clickhouse)).
|
||||
* Fix performance test for regexp cache [#51988](https://github.com/ClickHouse/ClickHouse/pull/51988) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Move a test to the right place [#51989](https://github.com/ClickHouse/ClickHouse/pull/51989) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add a check to validate that the stateful tests are stateful [#51990](https://github.com/ClickHouse/ClickHouse/pull/51990) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Check that functional tests cleanup their tables [#51991](https://github.com/ClickHouse/ClickHouse/pull/51991) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix test_extreme_deduplication [#51992](https://github.com/ClickHouse/ClickHouse/pull/51992) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Cleanup SymbolIndex after reload got removed [#51993](https://github.com/ClickHouse/ClickHouse/pull/51993) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update CompletedPipelineExecutor exception log name [#52028](https://github.com/ClickHouse/ClickHouse/pull/52028) ([xiao](https://github.com/nicelulu)).
|
||||
* Fix `00502_custom_partitioning_replicated_zookeeper_long` [#52032](https://github.com/ClickHouse/ClickHouse/pull/52032) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Prohibit send_metadata for s3_plain disks [#52038](https://github.com/ClickHouse/ClickHouse/pull/52038) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update version_date.tsv and changelogs after v23.4.6.25-stable [#52061](https://github.com/ClickHouse/ClickHouse/pull/52061) ([robot-clickhouse](https://github.com/robot-clickhouse)).
|
||||
* Preparations for Trivial Support For Resharding (part1) [#52068](https://github.com/ClickHouse/ClickHouse/pull/52068) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update version_date.tsv and changelogs after v23.3.8.21-lts [#52077](https://github.com/ClickHouse/ClickHouse/pull/52077) ([robot-clickhouse](https://github.com/robot-clickhouse)).
|
||||
* Fix flakiness of test_keeper_s3_snapshot flakiness [#52083](https://github.com/ClickHouse/ClickHouse/pull/52083) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix test_extreme_deduplication flakiness [#52085](https://github.com/ClickHouse/ClickHouse/pull/52085) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Small docs update for toYearWeek() function [#52090](https://github.com/ClickHouse/ClickHouse/pull/52090) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Small docs update for DateTime, DateTime64 [#52094](https://github.com/ClickHouse/ClickHouse/pull/52094) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Add missing --force for docker network prune (otherwise it is noop on CI) [#52095](https://github.com/ClickHouse/ClickHouse/pull/52095) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* tests: drop existing view in test_materialized_mysql_database [#52103](https://github.com/ClickHouse/ClickHouse/pull/52103) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update README.md [#52115](https://github.com/ClickHouse/ClickHouse/pull/52115) ([Tyler Hannan](https://github.com/tylerhannan)).
|
||||
* Print Zxid in keeper stat command in hex (so as ZooKeeper) [#52122](https://github.com/ClickHouse/ClickHouse/pull/52122) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Skip protection from double decompression if inode from maps cannot be obtained [#52138](https://github.com/ClickHouse/ClickHouse/pull/52138) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* There is no point in detecting flaky tests [#52142](https://github.com/ClickHouse/ClickHouse/pull/52142) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Remove default argument value [#52143](https://github.com/ClickHouse/ClickHouse/pull/52143) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix the "kill_mutation" test [#52144](https://github.com/ClickHouse/ClickHouse/pull/52144) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix ORDER BY tuple of WINDOW functions (and slightly more changes) [#52146](https://github.com/ClickHouse/ClickHouse/pull/52146) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix possible EADDRINUSE ("Address already in use") in integration tests [#52148](https://github.com/ClickHouse/ClickHouse/pull/52148) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix test 02497_storage_file_reader_selection [#52154](https://github.com/ClickHouse/ClickHouse/pull/52154) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix unexpected AST Set [#52158](https://github.com/ClickHouse/ClickHouse/pull/52158) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix crash in comparison functions due to incorrect query analysis [#52172](https://github.com/ClickHouse/ClickHouse/pull/52172) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix slow test `02317_distinct_in_order_optimization` [#52173](https://github.com/ClickHouse/ClickHouse/pull/52173) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add comments for https://github.com/ClickHouse/ClickHouse/pull/52112 [#52175](https://github.com/ClickHouse/ClickHouse/pull/52175) ([李扬](https://github.com/taiyang-li)).
|
||||
* Randomize timezone in tests across non-deterministic around 1970 and default [#52184](https://github.com/ClickHouse/ClickHouse/pull/52184) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix `test_multiple_disks/test.py::test_start_stop_moves` [#52189](https://github.com/ClickHouse/ClickHouse/pull/52189) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* CMake: Simplify job limiting [#52196](https://github.com/ClickHouse/ClickHouse/pull/52196) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Fix self extracting binaries under qemu linux-user (qemu-$ARCH-static) [#52198](https://github.com/ClickHouse/ClickHouse/pull/52198) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix `Integration tests flaky check (asan)` [#52201](https://github.com/ClickHouse/ClickHouse/pull/52201) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix flaky test test_lost_part [#52202](https://github.com/ClickHouse/ClickHouse/pull/52202) ([alesapin](https://github.com/alesapin)).
|
||||
* MaterializedMySQL: Replace to_string by magic_enum::enum_name [#52204](https://github.com/ClickHouse/ClickHouse/pull/52204) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* MaterializedMySQL: Add tests to parse db and table names from DDL [#52208](https://github.com/ClickHouse/ClickHouse/pull/52208) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Revert "Fixed several issues found by OSS-Fuzz" [#52216](https://github.com/ClickHouse/ClickHouse/pull/52216) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* Use one copy replication more agressively [#52218](https://github.com/ClickHouse/ClickHouse/pull/52218) ([alesapin](https://github.com/alesapin)).
|
||||
* Fix flaky test `01076_parallel_alter_replicated_zookeeper` [#52221](https://github.com/ClickHouse/ClickHouse/pull/52221) ([alesapin](https://github.com/alesapin)).
|
||||
* Fix 01889_key_condition_function_chains for analyzer. [#52223](https://github.com/ClickHouse/ClickHouse/pull/52223) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* Inhibit settings randomization in the test `json_ghdata` [#52226](https://github.com/ClickHouse/ClickHouse/pull/52226) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Slightly better diagnostics in a test [#52227](https://github.com/ClickHouse/ClickHouse/pull/52227) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Enable no-upgrade-check for 02273_full_sort_join [#52235](https://github.com/ClickHouse/ClickHouse/pull/52235) ([vdimir](https://github.com/vdimir)).
|
||||
* Fix network manager for integration tests [#52237](https://github.com/ClickHouse/ClickHouse/pull/52237) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* List replication queue only for current test database [#52238](https://github.com/ClickHouse/ClickHouse/pull/52238) ([Alexander Gololobov](https://github.com/davenger)).
|
||||
* Attempt to fix assert in tsan with fibers [#52241](https://github.com/ClickHouse/ClickHouse/pull/52241) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Fix undefined behaviour in fuzzer [#52256](https://github.com/ClickHouse/ClickHouse/pull/52256) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Follow-up to [#51959](https://github.com/ClickHouse/ClickHouse/issues/51959) [#52261](https://github.com/ClickHouse/ClickHouse/pull/52261) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* More fair queue for `drop table sync` [#52276](https://github.com/ClickHouse/ClickHouse/pull/52276) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix `02497_trace_events_stress_long` [#52279](https://github.com/ClickHouse/ClickHouse/pull/52279) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix test `01111_create_drop_replicated_db_stress` [#52283](https://github.com/ClickHouse/ClickHouse/pull/52283) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Fix ugly code [#52284](https://github.com/ClickHouse/ClickHouse/pull/52284) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* Add missing replica syncs in test_backup_restore_on_cluster [#52306](https://github.com/ClickHouse/ClickHouse/pull/52306) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Fix test_replicated_database 'node doesn't exist' flakiness [#52307](https://github.com/ClickHouse/ClickHouse/pull/52307) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||
* Minor: Update description of events "QueryCacheHits/Misses" [#52309](https://github.com/ClickHouse/ClickHouse/pull/52309) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Beautify pretty-printing of the query string in SYSTEM.QUERY_CACHE [#52312](https://github.com/ClickHouse/ClickHouse/pull/52312) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Reduce dependencies for skim by avoid using default features [#52316](https://github.com/ClickHouse/ClickHouse/pull/52316) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix 02725_memory-for-merges [#52317](https://github.com/ClickHouse/ClickHouse/pull/52317) ([alesapin](https://github.com/alesapin)).
|
||||
* Skip unsupported disks in Keeper [#52321](https://github.com/ClickHouse/ClickHouse/pull/52321) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Revert "Improve CSVInputFormat to check and set default value to column if deserialize failed" [#52322](https://github.com/ClickHouse/ClickHouse/pull/52322) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Resubmit [#51716](https://github.com/ClickHouse/ClickHouse/issues/51716) [#52323](https://github.com/ClickHouse/ClickHouse/pull/52323) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Add logging about all found workflows for merge_pr.py [#52324](https://github.com/ClickHouse/ClickHouse/pull/52324) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||
* Minor: Less awkward IAST::FormatSettings [#52332](https://github.com/ClickHouse/ClickHouse/pull/52332) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||
* Mark test 02125_many_mutations_2 as no-parallel to avoid flakiness [#52338](https://github.com/ClickHouse/ClickHouse/pull/52338) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Fix capabilities installed via systemd service (fixes netlink/IO priorities) [#52357](https://github.com/ClickHouse/ClickHouse/pull/52357) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Update 01606_git_import.sh [#52360](https://github.com/ClickHouse/ClickHouse/pull/52360) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Update ci-slack-bot.py [#52372](https://github.com/ClickHouse/ClickHouse/pull/52372) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix `test_keeper_session` [#52373](https://github.com/ClickHouse/ClickHouse/pull/52373) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Update ci-slack-bot.py [#52374](https://github.com/ClickHouse/ClickHouse/pull/52374) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Disable analyzer setting in backward_compatibility integration tests. [#52375](https://github.com/ClickHouse/ClickHouse/pull/52375) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||
* New metric - Filesystem cache size limit [#52378](https://github.com/ClickHouse/ClickHouse/pull/52378) ([Krzysztof Góralski](https://github.com/kgoralski)).
|
||||
* Fix `test_replicated_merge_tree_encrypted_disk ` [#52379](https://github.com/ClickHouse/ClickHouse/pull/52379) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* Fix `02122_parallel_formatting_XML ` [#52380](https://github.com/ClickHouse/ClickHouse/pull/52380) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||
* Follow up to [#49698](https://github.com/ClickHouse/ClickHouse/issues/49698) [#52381](https://github.com/ClickHouse/ClickHouse/pull/52381) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Less replication errors [#52382](https://github.com/ClickHouse/ClickHouse/pull/52382) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Rename TaskStatsInfoGetter into NetlinkMetricsProvider [#52392](https://github.com/ClickHouse/ClickHouse/pull/52392) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix `test_keeper_force_recovery` [#52408](https://github.com/ClickHouse/ClickHouse/pull/52408) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix flaky gtest_lru_file_cache.cpp [#52418](https://github.com/ClickHouse/ClickHouse/pull/52418) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||
* Fix: remove redundant distinct with views [#52438](https://github.com/ClickHouse/ClickHouse/pull/52438) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Add 02815_range_dict_no_direct_join to analyzer_tech_debt.txt [#52464](https://github.com/ClickHouse/ClickHouse/pull/52464) ([vdimir](https://github.com/vdimir)).
|
||||
* do not throw exception in OptimizedRegularExpressionImpl::analyze [#52467](https://github.com/ClickHouse/ClickHouse/pull/52467) ([Han Fei](https://github.com/hanfei1991)).
|
||||
* Remove skip_startup_tables from IDatabase::loadStoredObjects() [#52491](https://github.com/ClickHouse/ClickHouse/pull/52491) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix test_insert_same_partition_and_merge by increasing wait time [#52497](https://github.com/ClickHouse/ClickHouse/pull/52497) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||
* Try to fix asan wanring in HashJoin [#52499](https://github.com/ClickHouse/ClickHouse/pull/52499) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Replace with three way comparison [#52509](https://github.com/ClickHouse/ClickHouse/pull/52509) ([flynn](https://github.com/ucasfl)).
|
||||
* Fix flakiness of test_version_update_after_mutation by enabling force_remove_data_recursively_on_drop [#52514](https://github.com/ClickHouse/ClickHouse/pull/52514) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix `test_throttling` [#52515](https://github.com/ClickHouse/ClickHouse/pull/52515) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Improve logging macros [#52519](https://github.com/ClickHouse/ClickHouse/pull/52519) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix `toDecimalString` function [#52520](https://github.com/ClickHouse/ClickHouse/pull/52520) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||
* Remove unused code [#52527](https://github.com/ClickHouse/ClickHouse/pull/52527) ([Raúl Marín](https://github.com/Algunenano)).
|
||||
* Cancel execution in PipelineExecutor in case of exception in graph->updateNode [#52533](https://github.com/ClickHouse/ClickHouse/pull/52533) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||
* Make 01951_distributed_push_down_limit analyzer agnostic [#52534](https://github.com/ClickHouse/ClickHouse/pull/52534) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||
* Fix disallow_concurrency test for backup and restore [#52536](https://github.com/ClickHouse/ClickHouse/pull/52536) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||
* Update 02136_scalar_subquery_metrics.sql [#52537](https://github.com/ClickHouse/ClickHouse/pull/52537) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* tests: fix 01035_avg_weighted_long flakiness [#52556](https://github.com/ClickHouse/ClickHouse/pull/52556) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* tests: increase throttling for 01923_network_receive_time_metric_insert [#52557](https://github.com/ClickHouse/ClickHouse/pull/52557) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* tests: fix 00719_parallel_ddl_table flakiness in debug builds [#52558](https://github.com/ClickHouse/ClickHouse/pull/52558) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* tests: fix 01821_join_table_race_long flakiness [#52559](https://github.com/ClickHouse/ClickHouse/pull/52559) ([Azat Khuzhin](https://github.com/azat)).
|
||||
* Fix flaky `00995_exception_while_insert` [#52568](https://github.com/ClickHouse/ClickHouse/pull/52568) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* MaterializedMySQL: Fix typos in tests [#52575](https://github.com/ClickHouse/ClickHouse/pull/52575) ([Val Doroshchuk](https://github.com/valbok)).
|
||||
* Fix `02497_trace_events_stress_long` again [#52587](https://github.com/ClickHouse/ClickHouse/pull/52587) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Revert "Remove `mmap/mremap/munmap` from Allocator.h" [#52589](https://github.com/ClickHouse/ClickHouse/pull/52589) ([Nikita Taranov](https://github.com/nickitat)).
|
||||
* Remove peak memory usage from the final message in the client [#52598](https://github.com/ClickHouse/ClickHouse/pull/52598) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||
* GinIndexStore: fix a bug when files are finalizated after first write, [#52602](https://github.com/ClickHouse/ClickHouse/pull/52602) ([Sema Checherinda](https://github.com/CheSema)).
|
||||
* Fix deadlocks in StorageTableFunctionProxy [#52626](https://github.com/ClickHouse/ClickHouse/pull/52626) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix build with clang-15 [#52627](https://github.com/ClickHouse/ClickHouse/pull/52627) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Fix style [#52647](https://github.com/ClickHouse/ClickHouse/pull/52647) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||
* Fix logging level of a noisy message [#52648](https://github.com/ClickHouse/ClickHouse/pull/52648) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
* Revert "Added field `refcount` to `system.remote_data_paths` table" [#52657](https://github.com/ClickHouse/ClickHouse/pull/52657) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||
|
@ -62,8 +62,10 @@ may return cached results then.
|
||||
|
||||
The query cache can be cleared using statement `SYSTEM DROP QUERY CACHE`. The content of the query cache is displayed in system table
|
||||
`system.query_cache`. The number of query cache hits and misses are shown as events "QueryCacheHits" and "QueryCacheMisses" in system table
|
||||
`system.events`. Both counters are only updated for `SELECT` queries which run with setting "use_query_cache = true". Other queries do not
|
||||
affect the cache miss counter.
|
||||
[system.events](system-tables/events.md). Both counters are only updated for `SELECT` queries which run with setting "use_query_cache =
|
||||
true". Other queries do not affect the cache miss counter. Field `query_log_usage` in system table
|
||||
[system.query_log](system-tables/query_log.md) shows for each ran query whether the query result was written into or read from the query
|
||||
cache.
|
||||
|
||||
The query cache exists once per ClickHouse server process. However, cache results are by default not shared between users. This can be
|
||||
changed (see below) but doing so is not recommended for security reasons.
|
||||
|
@ -111,6 +111,11 @@ Columns:
|
||||
- `used_functions` ([Array(String)](../../sql-reference/data-types/array.md)) — Canonical names of `functions`, which were used during query execution.
|
||||
- `used_storages` ([Array(String)](../../sql-reference/data-types/array.md)) — Canonical names of `storages`, which were used during query execution.
|
||||
- `used_table_functions` ([Array(String)](../../sql-reference/data-types/array.md)) — Canonical names of `table functions`, which were used during query execution.
|
||||
- `query_cache_usage` ([Enum8](../../sql-reference/data-types/enum.md)) — Usage of the [query cache](../query-cache.md) during query execution. Values:
|
||||
- `'Unknown'` = Status unknown.
|
||||
- `'None'` = The query result was neither written into nor read from the query cache.
|
||||
- `'Write'` = The query result was written into the query cache.
|
||||
- `'Read'` = The query result was read from the query cache.
|
||||
|
||||
**Example**
|
||||
|
||||
@ -186,6 +191,7 @@ used_formats: []
|
||||
used_functions: []
|
||||
used_storages: []
|
||||
used_table_functions: []
|
||||
query_cache_usage: None
|
||||
```
|
||||
|
||||
**See Also**
|
||||
|
@ -945,6 +945,44 @@ Result:
|
||||
└────────────┴───────┘
|
||||
```
|
||||
|
||||
## toDecimalString
|
||||
|
||||
Converts a numeric value to String with the number of fractional digits in the output specified by the user.
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
toDecimalString(number, scale)
|
||||
```
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `number` — Value to be represented as String, [Int, UInt](/docs/en/sql-reference/data-types/int-uint.md), [Float](/docs/en/sql-reference/data-types/float.md), [Decimal](/docs/en/sql-reference/data-types/decimal.md),
|
||||
- `scale` — Number of fractional digits, [UInt8](/docs/en/sql-reference/data-types/int-uint.md).
|
||||
* Maximum scale for [Decimal](/docs/en/sql-reference/data-types/decimal.md) and [Int, UInt](/docs/en/sql-reference/data-types/int-uint.md) types is 77 (it is the maximum possible number of significant digits for Decimal),
|
||||
* Maximum scale for [Float](/docs/en/sql-reference/data-types/float.md) is 60.
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Input value represented as [String](/docs/en/sql-reference/data-types/string.md) with given number of fractional digits (scale).
|
||||
The number is rounded up or down according to common arithmetic in case requested scale is smaller than original number's scale.
|
||||
|
||||
**Example**
|
||||
|
||||
Query:
|
||||
|
||||
``` sql
|
||||
SELECT toDecimalString(CAST('64.32', 'Float64'), 5);
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌toDecimalString(CAST('64.32', 'Float64'), 5)─┐
|
||||
│ 64.32000 │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## reinterpretAsUInt(8\|16\|32\|64)
|
||||
|
||||
## reinterpretAsInt(8\|16\|32\|64)
|
||||
|
@ -762,6 +762,44 @@ SELECT toFixedString('foo\0bar', 8) AS s, toStringCutToZero(s) AS s_cut;
|
||||
└────────────┴───────┘
|
||||
```
|
||||
|
||||
## toDecimalString
|
||||
|
||||
Принимает любой численный тип первым аргументом, возвращает строковое десятичное представление числа с точностью, заданной вторым аргументом.
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
``` sql
|
||||
toDecimalString(number, scale)
|
||||
```
|
||||
|
||||
**Параметры**
|
||||
|
||||
- `number` — Значение любого числового типа: [Int, UInt](/docs/ru/sql-reference/data-types/int-uint.md), [Float](/docs/ru/sql-reference/data-types/float.md), [Decimal](/docs/ru/sql-reference/data-types/decimal.md),
|
||||
- `scale` — Требуемое количество десятичных знаков после запятой, [UInt8](/docs/ru/sql-reference/data-types/int-uint.md).
|
||||
* Значение `scale` для типов [Decimal](/docs/ru/sql-reference/data-types/decimal.md) и [Int, UInt](/docs/ru/sql-reference/data-types/int-uint.md) должно не превышать 77 (так как это наибольшее количество значимых символов для этих типов),
|
||||
* Значение `scale` для типа [Float](/docs/ru/sql-reference/data-types/float.md) не должно превышать 60.
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
- Строка ([String](/docs/en/sql-reference/data-types/string.md)), представляющая собой десятичное представление входного числа с заданной длиной дробной части.
|
||||
При необходимости число округляется по стандартным правилам арифметики.
|
||||
|
||||
**Пример использования**
|
||||
|
||||
Запрос:
|
||||
|
||||
``` sql
|
||||
SELECT toDecimalString(CAST('64.32', 'Float64'), 5);
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```response
|
||||
┌─toDecimalString(CAST('64.32', 'Float64'), 5)┐
|
||||
│ 64.32000 │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## reinterpretAsUInt(8\|16\|32\|64) {#reinterpretasuint8163264}
|
||||
|
||||
## reinterpretAsInt(8\|16\|32\|64) {#reinterpretasint8163264}
|
||||
|
@ -812,6 +812,11 @@ bool Client::processWithFuzzing(const String & full_query)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (!ast_to_process)
|
||||
fmt::print(stderr,
|
||||
"Error while forming new query: {}\n",
|
||||
getCurrentExceptionMessage(true));
|
||||
|
||||
// Some functions (e.g. protocol parsers) don't throw, but
|
||||
// set last_exception instead, so we'll also do it here for
|
||||
// uniformity.
|
||||
|
@ -29,6 +29,10 @@
|
||||
#include <AggregateFunctions/UniqVariadicHash.h>
|
||||
#include <AggregateFunctions/UniquesHashSet.h>
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -42,6 +46,7 @@ struct AggregateFunctionUniqUniquesHashSetData
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniq"; }
|
||||
@ -55,6 +60,7 @@ struct AggregateFunctionUniqUniquesHashSetDataForVariadic
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = true;
|
||||
constexpr static bool is_exact = is_exact_;
|
||||
constexpr static bool argument_is_tuple = argument_is_tuple_;
|
||||
@ -72,6 +78,7 @@ struct AggregateFunctionUniqHLL12Data
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqHLL12"; }
|
||||
@ -84,6 +91,7 @@ struct AggregateFunctionUniqHLL12Data<String, false>
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqHLL12"; }
|
||||
@ -96,6 +104,7 @@ struct AggregateFunctionUniqHLL12Data<UUID, false>
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqHLL12"; }
|
||||
@ -108,6 +117,7 @@ struct AggregateFunctionUniqHLL12Data<IPv6, false>
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqHLL12"; }
|
||||
@ -120,6 +130,7 @@ struct AggregateFunctionUniqHLL12DataForVariadic
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = true;
|
||||
constexpr static bool is_exact = is_exact_;
|
||||
constexpr static bool argument_is_tuple = argument_is_tuple_;
|
||||
@ -143,6 +154,7 @@ struct AggregateFunctionUniqExactData
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = true;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqExact"; }
|
||||
@ -162,6 +174,7 @@ struct AggregateFunctionUniqExactData<String, is_able_to_parallelize_merge_>
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = true;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqExact"; }
|
||||
@ -181,6 +194,7 @@ struct AggregateFunctionUniqExactData<IPv6, is_able_to_parallelize_merge_>
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = true;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqExact"; }
|
||||
@ -190,6 +204,7 @@ template <bool is_exact_, bool argument_is_tuple_, bool is_able_to_parallelize_m
|
||||
struct AggregateFunctionUniqExactDataForVariadic : AggregateFunctionUniqExactData<String, is_able_to_parallelize_merge_>
|
||||
{
|
||||
constexpr static bool is_able_to_parallelize_merge = is_able_to_parallelize_merge_;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = true;
|
||||
constexpr static bool is_variadic = true;
|
||||
constexpr static bool is_exact = is_exact_;
|
||||
constexpr static bool argument_is_tuple = argument_is_tuple_;
|
||||
@ -204,6 +219,7 @@ struct AggregateFunctionUniqThetaData
|
||||
Set set;
|
||||
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = false;
|
||||
|
||||
static String getName() { return "uniqTheta"; }
|
||||
@ -213,6 +229,7 @@ template <bool is_exact_, bool argument_is_tuple_>
|
||||
struct AggregateFunctionUniqThetaDataForVariadic : AggregateFunctionUniqThetaData
|
||||
{
|
||||
constexpr static bool is_able_to_parallelize_merge = false;
|
||||
constexpr static bool is_parallelize_merge_prepare_needed = false;
|
||||
constexpr static bool is_variadic = true;
|
||||
constexpr static bool is_exact = is_exact_;
|
||||
constexpr static bool argument_is_tuple = argument_is_tuple_;
|
||||
@ -384,8 +401,10 @@ template <typename T, typename Data>
|
||||
class AggregateFunctionUniq final : public IAggregateFunctionDataHelper<Data, AggregateFunctionUniq<T, Data>>
|
||||
{
|
||||
private:
|
||||
using DataSet = typename Data::Set;
|
||||
static constexpr size_t num_args = 1;
|
||||
static constexpr bool is_able_to_parallelize_merge = Data::is_able_to_parallelize_merge;
|
||||
static constexpr bool is_parallelize_merge_prepare_needed = Data::is_parallelize_merge_prepare_needed;
|
||||
|
||||
public:
|
||||
explicit AggregateFunctionUniq(const DataTypes & argument_types_)
|
||||
@ -439,6 +458,26 @@ public:
|
||||
detail::Adder<T, Data>::add(this->data(place), columns, num_args, row_begin, row_end, flags, null_map);
|
||||
}
|
||||
|
||||
bool isParallelizeMergePrepareNeeded() const override { return is_parallelize_merge_prepare_needed;}
|
||||
|
||||
void parallelizeMergePrepare(AggregateDataPtrs & places, ThreadPool & thread_pool) const override
|
||||
{
|
||||
if constexpr (is_parallelize_merge_prepare_needed)
|
||||
{
|
||||
std::vector<DataSet *> data_vec;
|
||||
data_vec.resize(places.size());
|
||||
|
||||
for (unsigned long i = 0; i < data_vec.size(); i++)
|
||||
data_vec[i] = &this->data(places[i]).set;
|
||||
|
||||
DataSet::parallelizeMergePrepare(data_vec, thread_pool);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "parallelizeMergePrepare() is only implemented when is_parallelize_merge_prepare_needed is true for {} ", getName());
|
||||
}
|
||||
}
|
||||
|
||||
void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena *) const override
|
||||
{
|
||||
this->data(place).set.merge(this->data(rhs).set);
|
||||
|
@ -47,6 +47,7 @@ using DataTypePtr = std::shared_ptr<const IDataType>;
|
||||
using DataTypes = std::vector<DataTypePtr>;
|
||||
|
||||
using AggregateDataPtr = char *;
|
||||
using AggregateDataPtrs = std::vector<AggregateDataPtr>;
|
||||
using ConstAggregateDataPtr = const char *;
|
||||
|
||||
class IAggregateFunction;
|
||||
@ -148,6 +149,13 @@ public:
|
||||
/// Default values must be a the 0-th positions in columns.
|
||||
virtual void addManyDefaults(AggregateDataPtr __restrict place, const IColumn ** columns, size_t length, Arena * arena) const = 0;
|
||||
|
||||
virtual bool isParallelizeMergePrepareNeeded() const { return false; }
|
||||
|
||||
virtual void parallelizeMergePrepare(AggregateDataPtrs & /*places*/, ThreadPool & /*thread_pool*/) const
|
||||
{
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "parallelizeMergePrepare() with thread pool parameter isn't implemented for {} ", getName());
|
||||
}
|
||||
|
||||
/// Merges state (on which place points to) with other state of current aggregation function.
|
||||
virtual void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena * arena) const = 0;
|
||||
|
||||
|
@ -28,6 +28,57 @@ public:
|
||||
asTwoLevel().insert(std::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
/// In merge, if one of the lhs and rhs is twolevelset and the other is singlelevelset, then the singlelevelset will need to convertToTwoLevel().
|
||||
/// It's not in parallel and will cost extra large time if the thread_num is large.
|
||||
/// This method will convert all the SingleLevelSet to TwoLevelSet in parallel if the hashsets are not all singlelevel or not all twolevel.
|
||||
static void parallelizeMergePrepare(const std::vector<UniqExactSet *> & data_vec, ThreadPool & thread_pool)
|
||||
{
|
||||
unsigned long single_level_set_num = 0;
|
||||
|
||||
for (auto ele : data_vec)
|
||||
{
|
||||
if (ele->isSingleLevel())
|
||||
single_level_set_num ++;
|
||||
}
|
||||
|
||||
if (single_level_set_num > 0 && single_level_set_num < data_vec.size())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto data_vec_atomic_index = std::make_shared<std::atomic_uint32_t>(0);
|
||||
auto thread_func = [data_vec, data_vec_atomic_index, thread_group = CurrentThread::getGroup()]()
|
||||
{
|
||||
SCOPE_EXIT_SAFE(
|
||||
if (thread_group)
|
||||
CurrentThread::detachFromGroupIfNotDetached();
|
||||
);
|
||||
if (thread_group)
|
||||
CurrentThread::attachToGroupIfDetached(thread_group);
|
||||
|
||||
setThreadName("UniqExaConvert");
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto i = data_vec_atomic_index->fetch_add(1);
|
||||
if (i >= data_vec.size())
|
||||
return;
|
||||
if (data_vec[i]->isSingleLevel())
|
||||
data_vec[i]->convertToTwoLevel();
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < std::min<size_t>(thread_pool.getMaxThreads(), single_level_set_num); ++i)
|
||||
thread_pool.scheduleOrThrowOnError(thread_func);
|
||||
|
||||
thread_pool.wait();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
thread_pool.wait();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto merge(const UniqExactSet & other, ThreadPool * thread_pool = nullptr)
|
||||
{
|
||||
if (isSingleLevel() && other.isTwoLevel())
|
||||
|
@ -267,6 +267,10 @@ add_object_library(clickhouse_processors_queryplan Processors/QueryPlan)
|
||||
add_object_library(clickhouse_processors_queryplan_optimizations Processors/QueryPlan/Optimizations)
|
||||
add_object_library(clickhouse_user_defined_functions Functions/UserDefined)
|
||||
|
||||
if (USE_PARQUET)
|
||||
add_object_library(clickhouse_processors_formats_impl_parquet Processors/Formats/Impl/Parquet)
|
||||
endif()
|
||||
|
||||
if (TARGET ch_contrib::nuraft)
|
||||
add_object_library(clickhouse_coordination Coordination)
|
||||
endif()
|
||||
|
@ -149,8 +149,10 @@
|
||||
M(RestartReplicaThreadsActive, "Number of threads in the RESTART REPLICA thread pool running a task.") \
|
||||
M(QueryPipelineExecutorThreads, "Number of threads in the PipelineExecutor thread pool.") \
|
||||
M(QueryPipelineExecutorThreadsActive, "Number of threads in the PipelineExecutor thread pool running a task.") \
|
||||
M(ParquetDecoderThreads, "Number of threads in the ParquetBlockInputFormat thread pool running a task.") \
|
||||
M(ParquetDecoderThreadsActive, "Number of threads in the ParquetBlockInputFormat thread pool.") \
|
||||
M(ParquetDecoderThreads, "Number of threads in the ParquetBlockInputFormat thread pool.") \
|
||||
M(ParquetDecoderThreadsActive, "Number of threads in the ParquetBlockInputFormat thread pool running a task.") \
|
||||
M(ParquetEncoderThreads, "Number of threads in ParquetBlockOutputFormat thread pool.") \
|
||||
M(ParquetEncoderThreadsActive, "Number of threads in ParquetBlockOutputFormat thread pool running a task.") \
|
||||
M(OutdatedPartsLoadingThreads, "Number of threads in the threadpool for loading Outdated data parts.") \
|
||||
M(OutdatedPartsLoadingThreadsActive, "Number of active threads in the threadpool for loading Outdated data parts.") \
|
||||
M(DistributedBytesToInsert, "Number of pending bytes to process for asynchronous insertion into Distributed tables. Number of bytes for every shard is summed.") \
|
||||
|
@ -15,4 +15,14 @@ template class PODArray<Int8, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADD
|
||||
template class PODArray<Int16, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
template class PODArray<Int32, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
template class PODArray<Int64, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
|
||||
template class PODArray<UInt8, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<UInt16, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<UInt32, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<UInt64, 4096, Allocator<false>, 0, 0>;
|
||||
|
||||
template class PODArray<Int8, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<Int16, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<Int32, 4096, Allocator<false>, 0, 0>;
|
||||
template class PODArray<Int64, 4096, Allocator<false>, 0, 0>;
|
||||
}
|
||||
|
@ -783,4 +783,15 @@ extern template class PODArray<Int8, 4096, Allocator<false>, PADDING_FOR_SIMD -
|
||||
extern template class PODArray<Int16, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
extern template class PODArray<Int32, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
extern template class PODArray<Int64, 4096, Allocator<false>, PADDING_FOR_SIMD - 1, PADDING_FOR_SIMD>;
|
||||
|
||||
extern template class PODArray<UInt8, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<UInt16, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<UInt32, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<UInt64, 4096, Allocator<false>, 0, 0>;
|
||||
|
||||
extern template class PODArray<Int8, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<Int16, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<Int32, 4096, Allocator<false>, 0, 0>;
|
||||
extern template class PODArray<Int64, 4096, Allocator<false>, 0, 0>;
|
||||
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ void SystemLogQueue<LogElement>::confirm(uint64_t to_flush_end)
|
||||
}
|
||||
|
||||
template <typename LogElement>
|
||||
SystemLogQueue<LogElement>::Index SystemLogQueue<LogElement>::pop(std::vector<LogElement>& output, bool& should_prepare_tables_anyway, bool& exit_this_thread)
|
||||
typename SystemLogQueue<LogElement>::Index SystemLogQueue<LogElement>::pop(std::vector<LogElement>& output, bool& should_prepare_tables_anyway, bool& exit_this_thread)
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
flush_event.wait_for(lock,
|
||||
|
@ -674,6 +674,7 @@ class IColumn;
|
||||
M(UInt64, remote_read_min_bytes_for_seek, 4 * DBMS_DEFAULT_BUFFER_SIZE, "Min bytes required for remote read (url, s3) to do seek, instead of read with ignore.", 0) \
|
||||
M(UInt64, merge_tree_min_bytes_per_task_for_remote_reading, 4 * DBMS_DEFAULT_BUFFER_SIZE, "Min bytes to read per task.", 0) \
|
||||
M(Bool, merge_tree_use_const_size_tasks_for_remote_reading, true, "Whether to use constant size tasks for reading from a remote table.", 0) \
|
||||
M(Bool, merge_tree_determine_task_size_by_prewhere_columns, true, "Whether to use only prewhere columns size to determine reading task size.", 0) \
|
||||
\
|
||||
M(Bool, async_insert, false, "If true, data from INSERT query is stored in queue and later flushed to table in background. If wait_for_async_insert is false, INSERT query is processed almost instantly, otherwise client will wait until data will be flushed to table", 0) \
|
||||
M(Bool, wait_for_async_insert, true, "If true wait for processing of asynchronous insertion", 0) \
|
||||
@ -953,6 +954,10 @@ class IColumn;
|
||||
M(ParquetVersion, output_format_parquet_version, "2.latest", "Parquet format version for output format. Supported versions: 1.0, 2.4, 2.6 and 2.latest (default)", 0) \
|
||||
M(ParquetCompression, output_format_parquet_compression_method, "lz4", "Compression method for Parquet output format. Supported codecs: snappy, lz4, brotli, zstd, gzip, none (uncompressed)", 0) \
|
||||
M(Bool, output_format_parquet_compliant_nested_types, true, "In parquet file schema, use name 'element' instead of 'item' for list elements. This is a historical artifact of Arrow library implementation. Generally increases compatibility, except perhaps with some old versions of Arrow.", 0) \
|
||||
M(Bool, output_format_parquet_use_custom_encoder, true, "Use experimental faster Parquet encoder implementation.", 0) \
|
||||
M(Bool, output_format_parquet_parallel_encoding, true, "Do Parquet encoding in multiple threads. Requires output_format_parquet_use_custom_encoder.", 0) \
|
||||
M(UInt64, output_format_parquet_data_page_size, 1024 * 1024, "Target page size in bytes, before compression.", 0) \
|
||||
M(UInt64, output_format_parquet_batch_size, 1024, "Check page size every this many rows. Consider decreasing if you have columns with average values size above a few KBs.", 0) \
|
||||
M(String, output_format_avro_codec, "", "Compression codec used for output. Possible values: 'null', 'deflate', 'snappy'.", 0) \
|
||||
M(UInt64, output_format_avro_sync_interval, 16 * 1024, "Sync interval in bytes.", 0) \
|
||||
M(String, output_format_avro_string_column_pattern, "", "For Avro format: regexp of String columns to select as AVRO string.", 0) \
|
||||
|
@ -34,7 +34,9 @@ enum class AttributeUnderlyingType : TypeIndexUnderlying
|
||||
map_item(Decimal32), map_item(Decimal64), map_item(Decimal128), map_item(Decimal256),
|
||||
map_item(DateTime64),
|
||||
|
||||
map_item(UUID), map_item(String), map_item(Array)
|
||||
map_item(UUID), map_item(String), map_item(Array),
|
||||
|
||||
map_item(IPv4), map_item(IPv6)
|
||||
};
|
||||
|
||||
#undef map_item
|
||||
|
@ -130,6 +130,10 @@ FormatSettings getFormatSettings(ContextPtr context, const Settings & settings)
|
||||
format_settings.parquet.max_block_size = settings.input_format_parquet_max_block_size;
|
||||
format_settings.parquet.output_compression_method = settings.output_format_parquet_compression_method;
|
||||
format_settings.parquet.output_compliant_nested_types = settings.output_format_parquet_compliant_nested_types;
|
||||
format_settings.parquet.use_custom_encoder = settings.output_format_parquet_use_custom_encoder;
|
||||
format_settings.parquet.parallel_encoding = settings.output_format_parquet_parallel_encoding;
|
||||
format_settings.parquet.data_page_size = settings.output_format_parquet_data_page_size;
|
||||
format_settings.parquet.write_batch_size = settings.output_format_parquet_batch_size;
|
||||
format_settings.pretty.charset = settings.output_format_pretty_grid_charset.toString() == "ASCII" ? FormatSettings::Pretty::Charset::ASCII : FormatSettings::Pretty::Charset::UTF8;
|
||||
format_settings.pretty.color = settings.output_format_pretty_color;
|
||||
format_settings.pretty.max_column_pad_width = settings.output_format_pretty_max_column_pad_width;
|
||||
@ -434,7 +438,7 @@ OutputFormatPtr FormatFactory::getOutputFormatParallelIfPossible(
|
||||
return format;
|
||||
}
|
||||
|
||||
return getOutputFormat(name, buf, sample, context, _format_settings);
|
||||
return getOutputFormat(name, buf, sample, context, format_settings);
|
||||
}
|
||||
|
||||
|
||||
@ -453,6 +457,7 @@ OutputFormatPtr FormatFactory::getOutputFormat(
|
||||
context->getQueryContext()->addQueryFactoriesInfo(Context::QueryLogFactories::Format, name);
|
||||
|
||||
auto format_settings = _format_settings ? *_format_settings : getFormatSettings(context);
|
||||
format_settings.max_threads = context->getSettingsRef().max_threads;
|
||||
|
||||
/** TODO: Materialization is needed, because formats can use the functions `IDataType`,
|
||||
* which only work with full columns.
|
||||
|
@ -100,6 +100,8 @@ struct FormatSettings
|
||||
|
||||
UInt64 max_parser_depth = DBMS_DEFAULT_MAX_PARSER_DEPTH;
|
||||
|
||||
size_t max_threads = 1;
|
||||
|
||||
enum class ArrowCompression
|
||||
{
|
||||
NONE,
|
||||
@ -233,10 +235,14 @@ struct FormatSettings
|
||||
bool output_string_as_string = false;
|
||||
bool output_fixed_string_as_fixed_byte_array = true;
|
||||
bool preserve_order = false;
|
||||
bool use_custom_encoder = true;
|
||||
bool parallel_encoding = true;
|
||||
UInt64 max_block_size = 8192;
|
||||
ParquetVersion output_version;
|
||||
ParquetCompression output_compression_method = ParquetCompression::SNAPPY;
|
||||
bool output_compliant_nested_types = true;
|
||||
size_t data_page_size = 1024 * 1024;
|
||||
size_t write_batch_size = 1024;
|
||||
} parquet;
|
||||
|
||||
struct Pretty
|
||||
|
22
src/Functions/FunctionToDecimalString.cpp
Normal file
22
src/Functions/FunctionToDecimalString.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionToDecimalString.h>
|
||||
#include <Functions/IFunction.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
REGISTER_FUNCTION(ToDecimalString)
|
||||
{
|
||||
factory.registerFunction<FunctionToDecimalString>(
|
||||
FunctionDocumentation{
|
||||
.description=R"(
|
||||
Returns string representation of a number. First argument is the number of any numeric type,
|
||||
second argument is the desired number of digits in fractional part. Returns String.
|
||||
|
||||
)",
|
||||
.examples{{"toDecimalString", "SELECT toDecimalString(2.1456,2)", ""}},
|
||||
.categories{"String"}
|
||||
}, FunctionFactory::CaseInsensitive);
|
||||
}
|
||||
|
||||
}
|
262
src/Functions/FunctionToDecimalString.h
Normal file
262
src/Functions/FunctionToDecimalString.h
Normal file
@ -0,0 +1,262 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Types.h>
|
||||
#include <Core/DecimalFunctions.h>
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnVector.h>
|
||||
#include <Columns/ColumnDecimal.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <IO/WriteBufferFromVector.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Interpreters/Context_fwd.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER;
|
||||
}
|
||||
|
||||
class FunctionToDecimalString : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = "toDecimalString";
|
||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionToDecimalString>(); }
|
||||
|
||||
String getName() const override { return name; }
|
||||
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
||||
|
||||
size_t getNumberOfArguments() const override { return 2; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
FunctionArgumentDescriptors mandatory_args = {
|
||||
{"Value", &isNumber<IDataType>, nullptr, "Number"},
|
||||
{"precision", &isNativeInteger<IDataType>, &isColumnConst, "const Integer"}
|
||||
};
|
||||
|
||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, {});
|
||||
|
||||
return std::make_shared<DataTypeString>();
|
||||
}
|
||||
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
|
||||
private:
|
||||
/// For operations with Integer/Float
|
||||
template <typename FromVectorType>
|
||||
void vectorConstant(const FromVectorType & vec_from, UInt8 precision,
|
||||
ColumnString::Chars & vec_to, ColumnString::Offsets & result_offsets) const
|
||||
{
|
||||
size_t input_rows_count = vec_from.size();
|
||||
result_offsets.resize(input_rows_count);
|
||||
|
||||
/// Buffer is used here and in functions below because resulting size cannot be precisely anticipated,
|
||||
/// and buffer resizes on-the-go. Also, .count() provided by buffer is convenient in this case.
|
||||
WriteBufferFromVector<ColumnString::Chars> buf_to(vec_to);
|
||||
|
||||
for (size_t i = 0; i < input_rows_count; ++i)
|
||||
{
|
||||
format(vec_from[i], buf_to, precision);
|
||||
result_offsets[i] = buf_to.count();
|
||||
}
|
||||
|
||||
buf_to.finalize();
|
||||
}
|
||||
|
||||
template <typename FirstArgVectorType>
|
||||
void vectorVector(const FirstArgVectorType & vec_from, const ColumnVector<UInt8>::Container & vec_precision,
|
||||
ColumnString::Chars & vec_to, ColumnString::Offsets & result_offsets) const
|
||||
{
|
||||
size_t input_rows_count = vec_from.size();
|
||||
result_offsets.resize(input_rows_count);
|
||||
|
||||
WriteBufferFromVector<ColumnString::Chars> buf_to(vec_to);
|
||||
|
||||
constexpr size_t max_digits = std::numeric_limits<UInt256>::digits10;
|
||||
|
||||
for (size_t i = 0; i < input_rows_count; ++i)
|
||||
{
|
||||
if (vec_precision[i] > max_digits)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER,
|
||||
"Too many fractional digits requested, shall not be more than {}", max_digits);
|
||||
format(vec_from[i], buf_to, vec_precision[i]);
|
||||
result_offsets[i] = buf_to.count();
|
||||
}
|
||||
|
||||
buf_to.finalize();
|
||||
}
|
||||
|
||||
/// For operations with Decimal
|
||||
template <typename FirstArgVectorType>
|
||||
void vectorConstant(const FirstArgVectorType & vec_from, UInt8 precision,
|
||||
ColumnString::Chars & vec_to, ColumnString::Offsets & result_offsets, UInt8 from_scale) const
|
||||
{
|
||||
/// There are no more than 77 meaning digits (as it is the max length of UInt256). So we can limit it with 77.
|
||||
constexpr size_t max_digits = std::numeric_limits<UInt256>::digits10;
|
||||
if (precision > max_digits)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER,
|
||||
"Too many fractional digits requested for Decimal, must not be more than {}", max_digits);
|
||||
|
||||
WriteBufferFromVector<ColumnString::Chars> buf_to(vec_to);
|
||||
size_t input_rows_count = vec_from.size();
|
||||
result_offsets.resize(input_rows_count);
|
||||
|
||||
for (size_t i = 0; i < input_rows_count; ++i)
|
||||
{
|
||||
writeText(vec_from[i], from_scale, buf_to, true, true, precision);
|
||||
writeChar(0, buf_to);
|
||||
result_offsets[i] = buf_to.count();
|
||||
}
|
||||
buf_to.finalize();
|
||||
}
|
||||
|
||||
template <typename FirstArgVectorType>
|
||||
void vectorVector(const FirstArgVectorType & vec_from, const ColumnVector<UInt8>::Container & vec_precision,
|
||||
ColumnString::Chars & vec_to, ColumnString::Offsets & result_offsets, UInt8 from_scale) const
|
||||
{
|
||||
size_t input_rows_count = vec_from.size();
|
||||
result_offsets.resize(input_rows_count);
|
||||
|
||||
WriteBufferFromVector<ColumnString::Chars> buf_to(vec_to);
|
||||
|
||||
constexpr size_t max_digits = std::numeric_limits<UInt256>::digits10;
|
||||
|
||||
for (size_t i = 0; i < input_rows_count; ++i)
|
||||
{
|
||||
if (vec_precision[i] > max_digits)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER,
|
||||
"Too many fractional digits requested for Decimal, must not be more than {}", max_digits);
|
||||
writeText(vec_from[i], from_scale, buf_to, true, true, vec_precision[i]);
|
||||
writeChar(0, buf_to);
|
||||
result_offsets[i] = buf_to.count();
|
||||
}
|
||||
buf_to.finalize();
|
||||
}
|
||||
|
||||
template <is_floating_point T>
|
||||
static void format(T value, DB::WriteBuffer & out, UInt8 precision)
|
||||
{
|
||||
/// Maximum of 60 is hard-coded in 'double-conversion/double-conversion.h' for floating point values,
|
||||
/// Catch this here to give user a more reasonable error.
|
||||
if (precision > 60)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER,
|
||||
"Too high precision requested for Float, must not be more than 60, got {}", Int8(precision));
|
||||
|
||||
DB::DoubleConverter<false>::BufferType buffer;
|
||||
double_conversion::StringBuilder builder{buffer, sizeof(buffer)};
|
||||
|
||||
const auto result = DB::DoubleConverter<false>::instance().ToFixed(value, precision, &builder);
|
||||
|
||||
if (!result)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER, "Error processing number: {}", value);
|
||||
|
||||
out.write(buffer, builder.position());
|
||||
writeChar(0, out);
|
||||
}
|
||||
|
||||
template <is_integer T>
|
||||
static void format(T value, DB::WriteBuffer & out, UInt8 precision)
|
||||
{
|
||||
/// Fractional part for Integer is just trailing zeros. Let's limit it with 77 (like with Decimals).
|
||||
constexpr size_t max_digits = std::numeric_limits<UInt256>::digits10;
|
||||
if (precision > max_digits)
|
||||
throw DB::Exception(DB::ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER,
|
||||
"Too many fractional digits requested, shall not be more than {}", max_digits);
|
||||
writeText(value, out);
|
||||
if (precision > 0) [[likely]]
|
||||
{
|
||||
writeChar('.', out);
|
||||
for (int i = 0; i < precision; ++i)
|
||||
writeChar('0', out);
|
||||
writeChar(0, out);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
|
||||
{
|
||||
switch (arguments[0].type->getTypeId())
|
||||
{
|
||||
case TypeIndex::UInt8: return executeType<UInt8>(arguments);
|
||||
case TypeIndex::UInt16: return executeType<UInt16>(arguments);
|
||||
case TypeIndex::UInt32: return executeType<UInt32>(arguments);
|
||||
case TypeIndex::UInt64: return executeType<UInt64>(arguments);
|
||||
case TypeIndex::UInt128: return executeType<UInt128>(arguments);
|
||||
case TypeIndex::UInt256: return executeType<UInt256>(arguments);
|
||||
case TypeIndex::Int8: return executeType<Int8>(arguments);
|
||||
case TypeIndex::Int16: return executeType<Int16>(arguments);
|
||||
case TypeIndex::Int32: return executeType<Int32>(arguments);
|
||||
case TypeIndex::Int64: return executeType<Int64>(arguments);
|
||||
case TypeIndex::Int128: return executeType<Int128>(arguments);
|
||||
case TypeIndex::Int256: return executeType<Int256>(arguments);
|
||||
case TypeIndex::Float32: return executeType<Float32>(arguments);
|
||||
case TypeIndex::Float64: return executeType<Float64>(arguments);
|
||||
case TypeIndex::Decimal32: return executeType<Decimal32>(arguments);
|
||||
case TypeIndex::Decimal64: return executeType<Decimal64>(arguments);
|
||||
case TypeIndex::Decimal128: return executeType<Decimal128>(arguments);
|
||||
case TypeIndex::Decimal256: return executeType<Decimal256>(arguments);
|
||||
default:
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}",
|
||||
arguments[0].column->getName(), getName());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
ColumnPtr executeType(const ColumnsWithTypeAndName & arguments) const
|
||||
{
|
||||
const auto * precision_col = checkAndGetColumn<ColumnVector<UInt8>>(arguments[1].column.get());
|
||||
const auto * precision_col_const = checkAndGetColumnConst<ColumnVector<UInt8>>(arguments[1].column.get());
|
||||
|
||||
auto result_col = ColumnString::create();
|
||||
auto * result_col_string = assert_cast<ColumnString *>(result_col.get());
|
||||
ColumnString::Chars & result_chars = result_col_string->getChars();
|
||||
ColumnString::Offsets & result_offsets = result_col_string->getOffsets();
|
||||
|
||||
if constexpr (is_decimal<T>)
|
||||
{
|
||||
const auto * from_col = checkAndGetColumn<ColumnDecimal<T>>(arguments[0].column.get());
|
||||
UInt8 from_scale = from_col->getScale();
|
||||
|
||||
if (from_col)
|
||||
{
|
||||
if (precision_col_const)
|
||||
vectorConstant(from_col->getData(), precision_col_const->template getValue<UInt8>(), result_chars, result_offsets, from_scale);
|
||||
else if (precision_col)
|
||||
vectorVector(from_col->getData(), precision_col->getData(), result_chars, result_offsets, from_scale);
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of second argument of function formatDecimal", arguments[1].column->getName());
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first argument of function formatDecimal", arguments[0].column->getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto * from_col = checkAndGetColumn<ColumnVector<T>>(arguments[0].column.get());
|
||||
if (from_col)
|
||||
{
|
||||
if (precision_col_const)
|
||||
vectorConstant(from_col->getData(), precision_col_const->template getValue<UInt8>(), result_chars, result_offsets);
|
||||
else if (precision_col)
|
||||
vectorVector(from_col->getData(), precision_col->getData(), result_chars, result_offsets);
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of second argument of function formatDecimal", arguments[1].column->getName());
|
||||
|
||||
}
|
||||
else
|
||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first argument of function formatDecimal", arguments[0].column->getName());
|
||||
}
|
||||
|
||||
return result_col;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -905,26 +905,26 @@ inline void writeText(const IPv4 & x, WriteBuffer & buf) { writeIPv4Text(x, buf)
|
||||
inline void writeText(const IPv6 & x, WriteBuffer & buf) { writeIPv6Text(x, buf); }
|
||||
|
||||
template <typename T>
|
||||
void writeDecimalFractional(const T & x, UInt32 scale, WriteBuffer & ostr, bool trailing_zeros)
|
||||
void writeDecimalFractional(const T & x, UInt32 scale, WriteBuffer & ostr, bool trailing_zeros,
|
||||
bool fixed_fractional_length, UInt32 fractional_length)
|
||||
{
|
||||
/// If it's big integer, but the number of digits is small,
|
||||
/// use the implementation for smaller integers for more efficient arithmetic.
|
||||
|
||||
if constexpr (std::is_same_v<T, Int256>)
|
||||
{
|
||||
if (x <= std::numeric_limits<UInt32>::max())
|
||||
{
|
||||
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
return;
|
||||
}
|
||||
else if (x <= std::numeric_limits<UInt64>::max())
|
||||
{
|
||||
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
return;
|
||||
}
|
||||
else if (x <= std::numeric_limits<UInt128>::max())
|
||||
{
|
||||
writeDecimalFractional(static_cast<UInt128>(x), scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(static_cast<UInt128>(x), scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -932,24 +932,36 @@ void writeDecimalFractional(const T & x, UInt32 scale, WriteBuffer & ostr, bool
|
||||
{
|
||||
if (x <= std::numeric_limits<UInt32>::max())
|
||||
{
|
||||
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(static_cast<UInt32>(x), scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
return;
|
||||
}
|
||||
else if (x <= std::numeric_limits<UInt64>::max())
|
||||
{
|
||||
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(static_cast<UInt64>(x), scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t max_digits = std::numeric_limits<UInt256>::digits10;
|
||||
assert(scale <= max_digits);
|
||||
assert(fractional_length <= max_digits);
|
||||
|
||||
char buf[max_digits];
|
||||
memset(buf, '0', scale);
|
||||
memset(buf, '0', std::max(scale, fractional_length));
|
||||
|
||||
T value = x;
|
||||
Int32 last_nonzero_pos = 0;
|
||||
for (Int32 pos = scale - 1; pos >= 0; --pos)
|
||||
|
||||
if (fixed_fractional_length && fractional_length < scale)
|
||||
{
|
||||
T new_value = value / DecimalUtils::scaleMultiplier<Int256>(scale - fractional_length - 1);
|
||||
auto round_carry = new_value % 10;
|
||||
value = new_value / 10;
|
||||
if (round_carry >= 5)
|
||||
value += 1;
|
||||
}
|
||||
|
||||
for (Int32 pos = fixed_fractional_length ? std::min(scale - 1, fractional_length - 1) : scale - 1; pos >= 0; --pos)
|
||||
{
|
||||
auto remainder = value % 10;
|
||||
value /= 10;
|
||||
@ -961,11 +973,12 @@ void writeDecimalFractional(const T & x, UInt32 scale, WriteBuffer & ostr, bool
|
||||
}
|
||||
|
||||
writeChar('.', ostr);
|
||||
ostr.write(buf, trailing_zeros ? scale : last_nonzero_pos + 1);
|
||||
ostr.write(buf, fixed_fractional_length ? fractional_length : (trailing_zeros ? scale : last_nonzero_pos + 1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr, bool trailing_zeros)
|
||||
void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr, bool trailing_zeros,
|
||||
bool fixed_fractional_length = false, UInt32 fractional_length = 0)
|
||||
{
|
||||
T part = DecimalUtils::getWholePart(x, scale);
|
||||
|
||||
@ -976,7 +989,7 @@ void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr, bool trailing_zer
|
||||
|
||||
writeIntText(part, ostr);
|
||||
|
||||
if (scale)
|
||||
if (scale || (fixed_fractional_length && fractional_length > 0))
|
||||
{
|
||||
part = DecimalUtils::getFractionalPart(x, scale);
|
||||
if (part || trailing_zeros)
|
||||
@ -984,7 +997,7 @@ void writeText(Decimal<T> x, UInt32 scale, WriteBuffer & ostr, bool trailing_zer
|
||||
if (part < 0)
|
||||
part *= T(-1);
|
||||
|
||||
writeDecimalFractional(part, scale, ostr, trailing_zeros);
|
||||
writeDecimalFractional(part, scale, ostr, trailing_zeros, fixed_fractional_length, fractional_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1210,22 +1210,16 @@ void ActionsMatcher::visit(const ASTFunction & node, const ASTPtr & ast, Data &
|
||||
else if (data.is_create_parameterized_view && query_parameter)
|
||||
{
|
||||
const auto data_type = DataTypeFactory::instance().get(query_parameter->type);
|
||||
/// Use getUniqueName() to allow multiple use of query parameter in the query:
|
||||
///
|
||||
/// CREATE VIEW view AS
|
||||
/// SELECT *
|
||||
/// FROM system.one
|
||||
/// WHERE dummy = {k1:Int}+1 OR dummy = {k1:Int}+2
|
||||
/// ^^ ^^
|
||||
///
|
||||
/// NOTE: query in the VIEW will not be modified this is needed
|
||||
/// only during analysis for CREATE VIEW to avoid duplicated
|
||||
/// column names.
|
||||
ColumnWithTypeAndName column(data_type, data.getUniqueName("__" + query_parameter->getColumnName()));
|
||||
data.addColumn(column);
|
||||
/// During analysis for CREATE VIEW of a parameterized view, if parameter is
|
||||
/// used multiple times, column is only added once
|
||||
if (!data.hasColumn(query_parameter->name))
|
||||
{
|
||||
ColumnWithTypeAndName column(data_type, query_parameter->name);
|
||||
data.addColumn(column);
|
||||
}
|
||||
|
||||
argument_types.push_back(data_type);
|
||||
argument_names.push_back(column.name);
|
||||
argument_names.push_back(query_parameter->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2603,6 +2603,20 @@ void NO_INLINE Aggregator::mergeWithoutKeyDataImpl(
|
||||
|
||||
AggregatedDataVariantsPtr & res = non_empty_data[0];
|
||||
|
||||
for (size_t i = 0; i < params.aggregates_size; ++i)
|
||||
{
|
||||
if (aggregate_functions[i]->isParallelizeMergePrepareNeeded())
|
||||
{
|
||||
size_t size = non_empty_data.size();
|
||||
std::vector<AggregateDataPtr> data_vec;
|
||||
|
||||
for (size_t result_num = 0; result_num < size; ++result_num)
|
||||
data_vec.emplace_back(non_empty_data[result_num]->without_key + offsets_of_aggregate_states[i]);
|
||||
|
||||
aggregate_functions[i]->parallelizeMergePrepare(data_vec, thread_pool);
|
||||
}
|
||||
}
|
||||
|
||||
/// We merge all aggregation results to the first.
|
||||
for (size_t result_num = 1, size = non_empty_data.size(); result_num < size; ++result_num)
|
||||
{
|
||||
|
@ -657,7 +657,7 @@ try
|
||||
total_rows, total_bytes, key.query_str);
|
||||
|
||||
bool pulling_pipeline = false;
|
||||
logQueryFinish(query_log_elem, insert_context, key.query, pipeline, pulling_pipeline, query_span, internal);
|
||||
logQueryFinish(query_log_elem, insert_context, key.query, pipeline, pulling_pipeline, query_span, QueryCache::Usage::None, internal);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -360,6 +360,9 @@ private:
|
||||
|
||||
struct DownloadInfo
|
||||
{
|
||||
DownloadInfo(const CacheMetadata::Key & key_, const size_t & offset_, const std::weak_ptr<FileSegment> & file_segment_)
|
||||
: key(key_), offset(offset_), file_segment(file_segment_) {}
|
||||
|
||||
CacheMetadata::Key key;
|
||||
size_t offset;
|
||||
/// We keep weak pointer to file segment
|
||||
|
@ -24,6 +24,14 @@ bool astContainsNonDeterministicFunctions(ASTPtr ast, ContextPtr context);
|
||||
class QueryCache
|
||||
{
|
||||
public:
|
||||
enum class Usage
|
||||
{
|
||||
Unknown, /// we don't know what what happened
|
||||
None, /// query result neither written nor read into/from query cache
|
||||
Write, /// query result written into query cache
|
||||
Read, /// query result read from query cache
|
||||
};
|
||||
|
||||
/// Represents a query result in the cache.
|
||||
struct Key
|
||||
{
|
||||
|
@ -41,6 +41,15 @@ NamesAndTypesList QueryLogElement::getNamesAndTypes()
|
||||
{"ExceptionWhileProcessing", static_cast<Int8>(EXCEPTION_WHILE_PROCESSING)}
|
||||
});
|
||||
|
||||
auto query_cache_usage_datatype = std::make_shared<DataTypeEnum8>(
|
||||
DataTypeEnum8::Values
|
||||
{
|
||||
{"Unknown", static_cast<Int8>(QueryCache::Usage::Unknown)},
|
||||
{"None", static_cast<Int8>(QueryCache::Usage::None)},
|
||||
{"Write", static_cast<Int8>(QueryCache::Usage::Write)},
|
||||
{"Read", static_cast<Int8>(QueryCache::Usage::Read)}
|
||||
});
|
||||
|
||||
auto low_cardinality_string = std::make_shared<DataTypeLowCardinality>(std::make_shared<DataTypeString>());
|
||||
auto array_low_cardinality_string = std::make_shared<DataTypeArray>(low_cardinality_string);
|
||||
|
||||
@ -126,6 +135,8 @@ NamesAndTypesList QueryLogElement::getNamesAndTypes()
|
||||
|
||||
{"transaction_id", getTransactionIDDataType()},
|
||||
|
||||
{"query_cache_usage", std::move(query_cache_usage_datatype)},
|
||||
|
||||
{"asynchronous_read_counters", std::make_shared<DataTypeMap>(low_cardinality_string, std::make_shared<DataTypeUInt64>())},
|
||||
};
|
||||
}
|
||||
@ -277,6 +288,8 @@ void QueryLogElement::appendToBlock(MutableColumns & columns) const
|
||||
|
||||
columns[i++]->insert(Tuple{tid.start_csn, tid.local_tid, tid.host_id});
|
||||
|
||||
columns[i++]->insert(query_cache_usage);
|
||||
|
||||
if (async_read_counters)
|
||||
async_read_counters->dumpToMapColumn(columns[i++].get());
|
||||
else
|
||||
|
@ -4,8 +4,9 @@
|
||||
#include <Core/NamesAndTypes.h>
|
||||
#include <Core/NamesAndAliases.h>
|
||||
#include <Core/Settings.h>
|
||||
#include <Interpreters/SystemLog.h>
|
||||
#include <Interpreters/Cache/QueryCache.h>
|
||||
#include <Interpreters/ClientInfo.h>
|
||||
#include <Interpreters/SystemLog.h>
|
||||
#include <Interpreters/TransactionVersionMetadata.h>
|
||||
#include <IO/AsyncReadCounters.h>
|
||||
#include <Parsers/IAST.h>
|
||||
@ -96,6 +97,8 @@ struct QueryLogElement
|
||||
|
||||
TransactionID tid;
|
||||
|
||||
QueryCache::Usage query_cache_usage = QueryCache::Usage::Unknown;
|
||||
|
||||
static std::string name() { return "QueryLog"; }
|
||||
|
||||
static NamesAndTypesList getNamesAndTypes();
|
||||
|
@ -209,7 +209,7 @@ static void logException(ContextPtr context, QueryLogElement & elem, bool log_er
|
||||
}
|
||||
|
||||
static void
|
||||
addStatusInfoToQueryElement(QueryLogElement & element, const QueryStatusInfo & info, const ASTPtr query_ast, const ContextPtr context_ptr)
|
||||
addStatusInfoToQueryLogElement(QueryLogElement & element, const QueryStatusInfo & info, const ASTPtr query_ast, const ContextPtr context_ptr)
|
||||
{
|
||||
const auto time_now = std::chrono::system_clock::now();
|
||||
UInt64 elapsed_microseconds = info.elapsed_microseconds;
|
||||
@ -347,6 +347,7 @@ void logQueryFinish(
|
||||
const QueryPipeline & query_pipeline,
|
||||
bool pulling_pipeline,
|
||||
std::shared_ptr<OpenTelemetry::SpanHolder> query_span,
|
||||
QueryCache::Usage query_cache_usage,
|
||||
bool internal)
|
||||
{
|
||||
const Settings & settings = context->getSettingsRef();
|
||||
@ -364,7 +365,7 @@ void logQueryFinish(
|
||||
QueryStatusInfo info = process_list_elem->getInfo(true, context->getSettingsRef().log_profile_events);
|
||||
elem.type = QueryLogElementType::QUERY_FINISH;
|
||||
|
||||
addStatusInfoToQueryElement(elem, info, query_ast, context);
|
||||
addStatusInfoToQueryLogElement(elem, info, query_ast, context);
|
||||
|
||||
if (pulling_pipeline)
|
||||
{
|
||||
@ -399,6 +400,8 @@ void logQueryFinish(
|
||||
ReadableSize(elem.read_bytes / elapsed_seconds));
|
||||
}
|
||||
|
||||
elem.query_cache_usage = query_cache_usage;
|
||||
|
||||
if (log_queries && elem.type >= log_queries_min_type
|
||||
&& static_cast<Int64>(elem.query_duration_ms) >= log_queries_min_query_duration_ms)
|
||||
{
|
||||
@ -499,13 +502,15 @@ void logQueryException(
|
||||
if (process_list_elem)
|
||||
{
|
||||
QueryStatusInfo info = process_list_elem->getInfo(true, settings.log_profile_events, false);
|
||||
addStatusInfoToQueryElement(elem, info, query_ast, context);
|
||||
addStatusInfoToQueryLogElement(elem, info, query_ast, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.query_duration_ms = start_watch.elapsedMilliseconds();
|
||||
}
|
||||
|
||||
elem.query_cache_usage = QueryCache::Usage::None;
|
||||
|
||||
if (settings.calculate_text_stack_trace && log_error)
|
||||
setExceptionStackTrace(elem);
|
||||
logException(context, elem, log_error);
|
||||
@ -975,7 +980,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
|
||||
QueryCachePtr query_cache = context->getQueryCache();
|
||||
const bool can_use_query_cache = query_cache != nullptr && settings.use_query_cache && !internal && (ast->as<ASTSelectQuery>() || ast->as<ASTSelectWithUnionQuery>());
|
||||
bool write_into_query_cache = false;
|
||||
QueryCache::Usage query_cache_usage = QueryCache::Usage::None;
|
||||
|
||||
if (!async_insert)
|
||||
{
|
||||
@ -992,6 +997,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
QueryPipeline pipeline;
|
||||
pipeline.readFromQueryCache(reader.getSource(), reader.getSourceTotals(), reader.getSourceExtremes());
|
||||
res.pipeline = std::move(pipeline);
|
||||
query_cache_usage = QueryCache::Usage::Read;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1095,7 +1101,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
settings.query_cache_max_size_in_bytes,
|
||||
settings.query_cache_max_entries));
|
||||
res.pipeline.writeResultIntoQueryCache(query_cache_writer);
|
||||
write_into_query_cache = true;
|
||||
query_cache_usage = QueryCache::Usage::Write;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1147,19 +1153,19 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
auto finish_callback = [elem,
|
||||
context,
|
||||
ast,
|
||||
write_into_query_cache,
|
||||
query_cache_usage,
|
||||
internal,
|
||||
implicit_txn_control,
|
||||
execute_implicit_tcl_query,
|
||||
pulling_pipeline = pipeline.pulling(),
|
||||
query_span](QueryPipeline & query_pipeline) mutable
|
||||
{
|
||||
if (write_into_query_cache)
|
||||
if (query_cache_usage == QueryCache::Usage::Write)
|
||||
/// Trigger the actual write of the buffered query result into the query cache. This is done explicitly to prevent
|
||||
/// partial/garbage results in case of exceptions during query execution.
|
||||
query_pipeline.finalizeWriteInQueryCache();
|
||||
|
||||
logQueryFinish(elem, context, ast, query_pipeline, pulling_pipeline, query_span, internal);
|
||||
logQueryFinish(elem, context, ast, query_pipeline, pulling_pipeline, query_span, query_cache_usage, internal);
|
||||
|
||||
if (*implicit_txn_control)
|
||||
execute_implicit_tcl_query(context, ASTTransactionControl::COMMIT);
|
||||
|
@ -92,6 +92,7 @@ void logQueryFinish(
|
||||
const QueryPipeline & query_pipeline,
|
||||
bool pulling_pipeline,
|
||||
std::shared_ptr<OpenTelemetry::SpanHolder> query_span,
|
||||
QueryCache::Usage query_cache_usage,
|
||||
bool internal);
|
||||
|
||||
void logQueryException(
|
||||
|
@ -1011,7 +1011,7 @@ private:
|
||||
using ConfluentSchemaRegistry = AvroConfluentRowInputFormat::SchemaRegistry;
|
||||
#define SCHEMA_REGISTRY_CACHE_MAX_SIZE 1000
|
||||
/// Cache of Schema Registry URL -> SchemaRegistry
|
||||
static CacheBase<std::string, ConfluentSchemaRegistry> schema_registry_cache(SCHEMA_REGISTRY_CACHE_MAX_SIZE);
|
||||
static CacheBase<std::string, ConfluentSchemaRegistry> schema_registry_cache(SCHEMA_REGISTRY_CACHE_MAX_SIZE);
|
||||
|
||||
static std::shared_ptr<ConfluentSchemaRegistry> getConfluentSchemaRegistry(const FormatSettings & format_settings)
|
||||
{
|
||||
|
@ -684,9 +684,6 @@ namespace DB
|
||||
bool output_fixed_string_as_fixed_byte_array,
|
||||
std::unordered_map<String, MutableColumnPtr> & dictionary_values)
|
||||
{
|
||||
const String column_type_name = column_type->getFamilyName();
|
||||
WhichDataType which(column_type);
|
||||
|
||||
switch (column_type->getTypeId())
|
||||
{
|
||||
case TypeIndex::Nullable:
|
||||
@ -796,7 +793,7 @@ namespace DB
|
||||
FOR_INTERNAL_NUMERIC_TYPES(DISPATCH)
|
||||
#undef DISPATCH
|
||||
default:
|
||||
throw Exception(ErrorCodes::UNKNOWN_TYPE, "Internal type '{}' of a column '{}' is not supported for conversion into {} data format.", column_type_name, column_name, format_name);
|
||||
throw Exception(ErrorCodes::UNKNOWN_TYPE, "Internal type '{}' of a column '{}' is not supported for conversion into {} data format.", column_type->getFamilyName(), column_name, format_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
628
src/Processors/Formats/Impl/Parquet/PrepareForWrite.cpp
Normal file
628
src/Processors/Formats/Impl/Parquet/PrepareForWrite.cpp
Normal file
@ -0,0 +1,628 @@
|
||||
#include "Processors/Formats/Impl/Parquet/Write.h"
|
||||
|
||||
#include <Columns/MaskOperations.h>
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnArray.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <Columns/ColumnMap.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/DataTypesDecimal.h>
|
||||
#include <DataTypes/DataTypeArray.h>
|
||||
#include <DataTypes/DataTypeTuple.h>
|
||||
#include <DataTypes/DataTypeLowCardinality.h>
|
||||
#include <DataTypes/DataTypeMap.h>
|
||||
#include <DataTypes/DataTypeDateTime64.h>
|
||||
#include <DataTypes/DataTypeFixedString.h>
|
||||
|
||||
|
||||
/// This file deals with schema conversion and with repetition and definition levels.
|
||||
|
||||
/// Schema conversion is pretty straightforward.
|
||||
|
||||
/// "Repetition and definition levels" are a somewhat tricky way of encoding information about
|
||||
/// optional fields and lists.
|
||||
///
|
||||
/// If you don't want to learn how these work, feel free to skip the updateRepDefLevels* functions.
|
||||
/// All you need to know is:
|
||||
/// * values for nulls are not encoded, so we have to filter nullable columns,
|
||||
/// * information about all array lengths and nulls is encoded in the arrays `def` and `rep`,
|
||||
/// which need to be encoded next to the data,
|
||||
/// * `def` and `rep` arrays can be longer than `primitive_column`, because they include nulls and
|
||||
/// empty arrays; the values in primitive_column correspond to positions where def[i] == max_def.
|
||||
///
|
||||
/// If you do want to learn it, dremel paper: https://research.google/pubs/pub36632/
|
||||
/// Instead of reading the whole paper, try staring at figures 2-3 for a while - it might be enough.
|
||||
/// (Why does Parquet do all this instead of just storing array lengths and null masks? I'm not
|
||||
/// really sure.)
|
||||
///
|
||||
/// We calculate the levels recursively, from inner to outer columns.
|
||||
/// This means scanning the whole array for each Array/Nullable nesting level, which is probably not
|
||||
/// the most efficient way to do it. But there's usually at most one nesting level, so it's fine.
|
||||
///
|
||||
/// Most of this is moot because ClickHouse doesn't support nullable arrays or tuples right now, so
|
||||
/// almost none of the tricky cases can happen. We implement it in full generality anyway (mostly
|
||||
/// because I only learned the previous sentence after writing most of the code).
|
||||
|
||||
|
||||
namespace DB::ErrorCodes
|
||||
{
|
||||
extern const int UNKNOWN_TYPE;
|
||||
extern const int TOO_DEEP_RECURSION; // I'm 14 and this is deep
|
||||
extern const int UNKNOWN_COMPRESSION_METHOD;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
namespace DB::Parquet
|
||||
{
|
||||
|
||||
/// Thrift structs that Parquet uses for various metadata inside the parquet file.
|
||||
namespace parq = parquet::format;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void assertNoDefOverflow(ColumnChunkWriteState & s)
|
||||
{
|
||||
if (s.max_def == UINT8_MAX)
|
||||
throw Exception(ErrorCodes::TOO_DEEP_RECURSION,
|
||||
"Column has more than 255 levels of nested Array/Nullable. Impressive! Unfortunately, "
|
||||
"this is not supported by this Parquet encoder (but is supported by Parquet, if you "
|
||||
"really need this for some reason).");
|
||||
}
|
||||
|
||||
void updateRepDefLevelsAndFilterColumnForNullable(ColumnChunkWriteState & s, const NullMap & null_map)
|
||||
{
|
||||
/// Increment definition levels for non-nulls.
|
||||
/// Filter the column to contain only non-null values.
|
||||
|
||||
assertNoDefOverflow(s);
|
||||
++s.max_def;
|
||||
|
||||
/// Normal case: no arrays or nullables inside this nullable.
|
||||
if (s.max_def == 1)
|
||||
{
|
||||
chassert(s.def.empty());
|
||||
s.def.resize(null_map.size());
|
||||
for (size_t i = 0; i < s.def.size(); ++i)
|
||||
s.def[i] = !null_map[i];
|
||||
|
||||
/// We could be more efficient with this:
|
||||
/// * Instead of doing the filter() here, we could defer it to writeColumnChunkBody(), at
|
||||
/// least in the simple case of Nullable(Primitive). Then it'll parallelize if the table
|
||||
/// consists of one big tuple.
|
||||
/// * Instead of filtering explicitly, we could build filtering into the data encoder.
|
||||
/// * Instead of filling out the `def` values above, we could point to null_map and build
|
||||
/// the '!' into the encoder.
|
||||
/// None of these seem worth the complexity right now.
|
||||
s.primitive_column = s.primitive_column->filter(s.def, /*result_size_hint*/ -1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// Weird general case: Nullable(Array), Nullable(Nullable), or any arbitrary nesting like that.
|
||||
/// This is currently not allowed in ClickHouse, but let's support it anyway just in case.
|
||||
|
||||
IColumn::Filter filter;
|
||||
size_t row_idx = static_cast<size_t>(-1);
|
||||
for (size_t i = 0; i < s.def.size(); ++i)
|
||||
{
|
||||
row_idx += s.max_rep == 0 || s.rep[i] == 0;
|
||||
if (s.def[i] == s.max_def - 1)
|
||||
filter.push_back(!null_map[row_idx]);
|
||||
s.def[i] += !null_map[row_idx];
|
||||
}
|
||||
s.primitive_column = s.primitive_column->filter(filter, /*result_size_hint*/ -1);
|
||||
}
|
||||
|
||||
void updateRepDefLevelsForArray(ColumnChunkWriteState & s, const IColumn::Offsets & offsets)
|
||||
{
|
||||
/// Increment all definition levels.
|
||||
/// For non-first elements of arrays, increment repetition levels.
|
||||
/// For empty arrays, insert a zero into repetition and definition levels arrays.
|
||||
|
||||
assertNoDefOverflow(s);
|
||||
++s.max_def;
|
||||
++s.max_rep;
|
||||
|
||||
/// Common case: no arrays or nullables inside this array.
|
||||
if (s.max_rep == 1 && s.max_def == 1)
|
||||
{
|
||||
s.def.resize_fill(s.primitive_column->size(), 1);
|
||||
s.rep.resize_fill(s.primitive_column->size(), 1);
|
||||
size_t i = 0;
|
||||
for (ssize_t row = 0; row < static_cast<ssize_t>(offsets.size()); ++row)
|
||||
{
|
||||
size_t n = offsets[row] - offsets[row - 1];
|
||||
if (n)
|
||||
{
|
||||
s.rep[i] = 0;
|
||||
i += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.def.push_back(1);
|
||||
s.rep.push_back(1);
|
||||
s.def[i] = 0;
|
||||
s.rep[i] = 0;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/// General case: Array(Array), Array(Nullable), or any arbitrary nesting like that.
|
||||
|
||||
for (auto & x : s.def)
|
||||
++x;
|
||||
|
||||
if (s.max_rep == 1)
|
||||
s.rep.resize_fill(s.def.size(), 1);
|
||||
else
|
||||
for (auto & x : s.rep)
|
||||
++x;
|
||||
|
||||
PaddedPODArray<UInt8> mask(s.def.size(), 1); // for inserting zeroes to rep and def
|
||||
size_t i = 0; // in the input (s.def/s.rep)
|
||||
size_t empty_arrays = 0;
|
||||
for (ssize_t row = 0; row < static_cast<ssize_t>(offsets.size()); ++row)
|
||||
{
|
||||
size_t n = offsets[row] - offsets[row - 1];
|
||||
if (n)
|
||||
{
|
||||
/// Un-increment the first rep of the array.
|
||||
/// Skip n "items" in the nested column; first element of each item has rep = 1
|
||||
/// (we incremented it above).
|
||||
chassert(s.rep[i] == 1);
|
||||
--s.rep[i];
|
||||
do
|
||||
{
|
||||
++i;
|
||||
if (i == s.rep.size())
|
||||
{
|
||||
--n;
|
||||
chassert(n == 0);
|
||||
break;
|
||||
}
|
||||
n -= s.rep[i] == 1;
|
||||
} while (n);
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.push_back(1);
|
||||
mask[i + empty_arrays] = 0;
|
||||
++empty_arrays;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty_arrays != 0)
|
||||
{
|
||||
expandDataByMask(s.def, mask, false);
|
||||
expandDataByMask(s.rep, mask, false);
|
||||
}
|
||||
}
|
||||
|
||||
parq::CompressionCodec::type compressionMethodToParquet(CompressionMethod c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case CompressionMethod::None: return parq::CompressionCodec::UNCOMPRESSED;
|
||||
case CompressionMethod::Snappy: return parq::CompressionCodec::SNAPPY;
|
||||
case CompressionMethod::Gzip: return parq::CompressionCodec::GZIP;
|
||||
case CompressionMethod::Brotli: return parq::CompressionCodec::BROTLI;
|
||||
case CompressionMethod::Lz4: return parq::CompressionCodec::LZ4_RAW;
|
||||
case CompressionMethod::Zstd: return parq::CompressionCodec::ZSTD;
|
||||
|
||||
default:
|
||||
throw Exception(ErrorCodes::UNKNOWN_COMPRESSION_METHOD, "Compression method {} is not supported by Parquet", toContentEncodingName(c));
|
||||
}
|
||||
}
|
||||
|
||||
/// Depth-first traversal of the schema tree for this column.
|
||||
void prepareColumnRecursive(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas);
|
||||
|
||||
void preparePrimitiveColumn(ColumnPtr column, DataTypePtr type, const std::string & name,
|
||||
const WriteOptions & options, ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
/// Add physical column info.
|
||||
auto & state = states.emplace_back();
|
||||
state.primitive_column = column;
|
||||
state.compression = options.compression;
|
||||
|
||||
state.column_chunk.__isset.meta_data = true;
|
||||
state.column_chunk.meta_data.__set_path_in_schema({name});
|
||||
state.column_chunk.meta_data.__set_codec(compressionMethodToParquet(state.compression));
|
||||
|
||||
/// Add logical schema leaf.
|
||||
auto & schema = schemas.emplace_back();
|
||||
schema.__set_repetition_type(parq::FieldRepetitionType::REQUIRED);
|
||||
schema.__set_name(name);
|
||||
|
||||
/// Convert the type enums.
|
||||
|
||||
using T = parq::Type;
|
||||
using C = parq::ConvertedType;
|
||||
|
||||
auto types = [&](T::type type_, std::optional<C::type> converted = std::nullopt, std::optional<parq::LogicalType> logical = std::nullopt)
|
||||
{
|
||||
state.column_chunk.meta_data.__set_type(type_);
|
||||
schema.__set_type(type_);
|
||||
if (converted)
|
||||
schema.__set_converted_type(*converted);
|
||||
if (logical)
|
||||
schema.__set_logicalType(*logical);
|
||||
};
|
||||
|
||||
auto int_type = [](Int8 bits, bool signed_)
|
||||
{
|
||||
parq::LogicalType t;
|
||||
t.__isset.INTEGER = true;
|
||||
t.INTEGER.__set_bitWidth(bits);
|
||||
t.INTEGER.__set_isSigned(signed_);
|
||||
return t;
|
||||
};
|
||||
|
||||
auto fixed_string = [&](size_t size, std::optional<C::type> converted = std::nullopt, std::optional<parq::LogicalType> logical = std::nullopt)
|
||||
{
|
||||
state.column_chunk.meta_data.__set_type(parq::Type::FIXED_LEN_BYTE_ARRAY);
|
||||
schema.__set_type(parq::Type::FIXED_LEN_BYTE_ARRAY);
|
||||
schema.__set_type_length(static_cast<Int32>(size));
|
||||
if (converted)
|
||||
schema.__set_converted_type(*converted);
|
||||
if (logical)
|
||||
schema.__set_logicalType(*logical);
|
||||
};
|
||||
|
||||
auto decimal = [&](Int32 bytes, UInt32 precision, UInt32 scale)
|
||||
{
|
||||
state.column_chunk.meta_data.__set_type(parq::Type::FIXED_LEN_BYTE_ARRAY);
|
||||
schema.__set_type(parq::Type::FIXED_LEN_BYTE_ARRAY);
|
||||
schema.__set_type_length(bytes);
|
||||
schema.__set_scale(static_cast<Int32>(scale));
|
||||
schema.__set_precision(static_cast<Int32>(precision));
|
||||
schema.__set_converted_type(parq::ConvertedType::DECIMAL);
|
||||
parq::DecimalType d;
|
||||
d.__set_scale(static_cast<Int32>(scale));
|
||||
d.__set_precision(static_cast<Int32>(precision));
|
||||
parq::LogicalType t;
|
||||
t.__set_DECIMAL(d);
|
||||
schema.__set_logicalType(t);
|
||||
};
|
||||
|
||||
switch (type->getTypeId())
|
||||
{
|
||||
case TypeIndex::UInt8:
|
||||
if (isBool(type))
|
||||
{
|
||||
types(T::BOOLEAN);
|
||||
state.is_bool = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
types(T::INT32, C::UINT_8, int_type(8, false));
|
||||
}
|
||||
break;
|
||||
case TypeIndex::UInt16: types(T::INT32, C::UINT_16, int_type(16, false)); break;
|
||||
case TypeIndex::UInt32: types(T::INT32, C::UINT_32, int_type(32, false)); break;
|
||||
case TypeIndex::UInt64: types(T::INT64, C::UINT_64, int_type(64, false)); break;
|
||||
case TypeIndex::Int8: types(T::INT32, C::INT_8, int_type(8, true)); break;
|
||||
case TypeIndex::Int16: types(T::INT32, C::INT_16, int_type(16, true)); break;
|
||||
case TypeIndex::Int32: types(T::INT32); break;
|
||||
case TypeIndex::Int64: types(T::INT64); break;
|
||||
case TypeIndex::Float32: types(T::FLOAT); break;
|
||||
case TypeIndex::Float64: types(T::DOUBLE); break;
|
||||
|
||||
/// These don't have suitable parquet logical types, so we write them as plain numbers.
|
||||
/// (Parquet has "enums" but they're just strings, with nowhere to declare all possible enum
|
||||
/// values in advance as part of the data type.)
|
||||
case TypeIndex::Enum8: types(T::INT32, C::INT_8, int_type(8, true)); break; // Int8
|
||||
case TypeIndex::Enum16: types(T::INT32, C::INT_16, int_type(16, true)); break; // Int16
|
||||
case TypeIndex::IPv4: types(T::INT32, C::UINT_32, int_type(32, false)); break; // UInt32
|
||||
case TypeIndex::Date: types(T::INT32, C::UINT_16, int_type(16, false)); break; // UInt16
|
||||
case TypeIndex::DateTime: types(T::INT32, C::UINT_32, int_type(32, false)); break; // UInt32
|
||||
|
||||
case TypeIndex::Date32:
|
||||
{
|
||||
parq::LogicalType t;
|
||||
t.__set_DATE({});
|
||||
types(T::INT32, C::DATE, t);
|
||||
break;
|
||||
}
|
||||
|
||||
case TypeIndex::DateTime64:
|
||||
{
|
||||
std::optional<parq::ConvertedType::type> converted;
|
||||
std::optional<parq::TimeUnit> unit;
|
||||
switch (assert_cast<const DataTypeDateTime64 &>(*type).getScale())
|
||||
{
|
||||
case 3:
|
||||
converted = parq::ConvertedType::TIMESTAMP_MILLIS;
|
||||
unit.emplace().__set_MILLIS({});
|
||||
break;
|
||||
case 6:
|
||||
converted = parq::ConvertedType::TIMESTAMP_MICROS;
|
||||
unit.emplace().__set_MICROS({});
|
||||
break;
|
||||
case 9:
|
||||
unit.emplace().__set_NANOS({});
|
||||
break;
|
||||
}
|
||||
|
||||
std::optional<parq::LogicalType> t;
|
||||
if (unit)
|
||||
{
|
||||
parq::TimestampType tt;
|
||||
tt.__set_isAdjustedToUTC(true);
|
||||
tt.__set_unit(*unit);
|
||||
t.emplace().__set_TIMESTAMP(tt);
|
||||
}
|
||||
types(T::INT64, converted, t);
|
||||
break;
|
||||
}
|
||||
|
||||
case TypeIndex::String:
|
||||
case TypeIndex::FixedString:
|
||||
{
|
||||
if (options.output_fixed_string_as_fixed_byte_array &&
|
||||
type->getTypeId() == TypeIndex::FixedString)
|
||||
{
|
||||
fixed_string(assert_cast<const DataTypeFixedString &>(*type).getN());
|
||||
}
|
||||
else if (options.output_string_as_string)
|
||||
{
|
||||
parq::LogicalType t;
|
||||
t.__set_STRING({});
|
||||
types(T::BYTE_ARRAY, C::UTF8, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
types(T::BYTE_ARRAY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/// Parquet doesn't have logical types for these.
|
||||
case TypeIndex::UInt128: fixed_string(16); break;
|
||||
case TypeIndex::UInt256: fixed_string(32); break;
|
||||
case TypeIndex::Int128: fixed_string(16); break;
|
||||
case TypeIndex::Int256: fixed_string(32); break;
|
||||
case TypeIndex::IPv6: fixed_string(16); break;
|
||||
|
||||
case TypeIndex::Decimal32: decimal(4, getDecimalPrecision(*type), getDecimalScale(*type)); break;
|
||||
case TypeIndex::Decimal64: decimal(8, getDecimalPrecision(*type), getDecimalScale(*type)); break;
|
||||
case TypeIndex::Decimal128: decimal(16, getDecimalPrecision(*type), getDecimalScale(*type)); break;
|
||||
case TypeIndex::Decimal256: decimal(32, getDecimalPrecision(*type), getDecimalScale(*type)); break;
|
||||
|
||||
default:
|
||||
throw Exception(ErrorCodes::UNKNOWN_TYPE, "Internal type '{}' of column '{}' is not supported for conversion into Parquet data format.", type->getFamilyName(), name);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareColumnNullable(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
const ColumnNullable * column_nullable = assert_cast<const ColumnNullable *>(column.get());
|
||||
ColumnPtr nested_column = column_nullable->getNestedColumnPtr();
|
||||
DataTypePtr nested_type = assert_cast<const DataTypeNullable *>(type.get())->getNestedType();
|
||||
const NullMap & null_map = column_nullable->getNullMapData();
|
||||
|
||||
size_t child_states_begin = states.size();
|
||||
size_t child_schema_idx = schemas.size();
|
||||
|
||||
prepareColumnRecursive(nested_column, nested_type, name, options, states, schemas);
|
||||
|
||||
if (schemas[child_schema_idx].repetition_type == parq::FieldRepetitionType::REQUIRED)
|
||||
{
|
||||
/// Normal case: we just slap a FieldRepetitionType::OPTIONAL onto the nested column.
|
||||
schemas[child_schema_idx].repetition_type = parq::FieldRepetitionType::OPTIONAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Weird case: Nullable(Nullable(...)). Or Nullable(Tuple(Nullable(...))), etc.
|
||||
/// This is probably not allowed in ClickHouse, but let's support it just in case.
|
||||
auto & schema = *schemas.insert(schemas.begin() + child_schema_idx, {});
|
||||
schema.__set_repetition_type(parq::FieldRepetitionType::OPTIONAL);
|
||||
schema.__set_name("nullable");
|
||||
schema.__set_num_children(1);
|
||||
for (size_t i = child_states_begin; i < states.size(); ++i)
|
||||
{
|
||||
Strings & path = states[i].column_chunk.meta_data.path_in_schema;
|
||||
path.insert(path.begin(), schema.name + ".");
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = child_states_begin; i < states.size(); ++i)
|
||||
{
|
||||
auto & s = states[i];
|
||||
updateRepDefLevelsAndFilterColumnForNullable(s, null_map);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareColumnTuple(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
const auto * column_tuple = assert_cast<const ColumnTuple *>(column.get());
|
||||
const auto * type_tuple = assert_cast<const DataTypeTuple *>(type.get());
|
||||
|
||||
auto & tuple_schema = schemas.emplace_back();
|
||||
tuple_schema.__set_repetition_type(parq::FieldRepetitionType::REQUIRED);
|
||||
tuple_schema.__set_name(name);
|
||||
tuple_schema.__set_num_children(static_cast<Int32>(type_tuple->getElements().size()));
|
||||
|
||||
size_t child_states_begin = states.size();
|
||||
|
||||
for (size_t i = 0; i < type_tuple->getElements().size(); ++i)
|
||||
prepareColumnRecursive(column_tuple->getColumnPtr(i), type_tuple->getElement(i), type_tuple->getNameByPosition(i + 1), options, states, schemas);
|
||||
|
||||
for (size_t i = child_states_begin; i < states.size(); ++i)
|
||||
{
|
||||
Strings & path = states[i].column_chunk.meta_data.path_in_schema;
|
||||
/// O(nesting_depth^2), but who cares.
|
||||
path.insert(path.begin(), name);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareColumnArray(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
const auto * column_array = assert_cast<const ColumnArray *>(column.get());
|
||||
ColumnPtr nested_column = column_array->getDataPtr();
|
||||
DataTypePtr nested_type = assert_cast<const DataTypeArray *>(type.get())->getNestedType();
|
||||
const auto & offsets = column_array->getOffsets();
|
||||
|
||||
/// Schema for lists https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#lists
|
||||
///
|
||||
/// required group `name` (List):
|
||||
/// repeated group "list":
|
||||
/// <recurse into nested type> "element"
|
||||
|
||||
/// Add the groups schema.
|
||||
|
||||
schemas.emplace_back();
|
||||
schemas.emplace_back();
|
||||
auto & list_schema = schemas[schemas.size() - 2];
|
||||
auto & item_schema = schemas[schemas.size() - 1];
|
||||
|
||||
list_schema.__set_repetition_type(parq::FieldRepetitionType::REQUIRED);
|
||||
list_schema.__set_name(name);
|
||||
list_schema.__set_num_children(1);
|
||||
list_schema.__set_converted_type(parq::ConvertedType::LIST);
|
||||
list_schema.__isset.logicalType = true;
|
||||
list_schema.logicalType.__set_LIST({});
|
||||
|
||||
item_schema.__set_repetition_type(parq::FieldRepetitionType::REPEATED);
|
||||
item_schema.__set_name("list");
|
||||
item_schema.__set_num_children(1);
|
||||
|
||||
std::array<std::string, 2> path_prefix = {list_schema.name, item_schema.name};
|
||||
size_t child_states_begin = states.size();
|
||||
|
||||
/// Recurse.
|
||||
prepareColumnRecursive(nested_column, nested_type, "element", options, states, schemas);
|
||||
|
||||
/// Update repetition+definition levels and fully-qualified column names (x -> myarray.list.x).
|
||||
for (size_t i = child_states_begin; i < states.size(); ++i)
|
||||
{
|
||||
Strings & path = states[i].column_chunk.meta_data.path_in_schema;
|
||||
path.insert(path.begin(), path_prefix.begin(), path_prefix.end());
|
||||
|
||||
updateRepDefLevelsForArray(states[i], offsets);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareColumnMap(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
const auto * column_map = assert_cast<const ColumnMap *>(column.get());
|
||||
const auto * column_array = &column_map->getNestedColumn();
|
||||
const auto & offsets = column_array->getOffsets();
|
||||
ColumnPtr column_tuple = column_array->getDataPtr();
|
||||
|
||||
const auto * map_type = assert_cast<const DataTypeMap *>(type.get());
|
||||
DataTypePtr tuple_type = std::make_shared<DataTypeTuple>(map_type->getKeyValueTypes(), Strings{"key", "value"});
|
||||
|
||||
/// Map is an array of tuples
|
||||
/// https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#maps
|
||||
///
|
||||
/// required group `name` (Map):
|
||||
/// repeated group "key_value":
|
||||
/// reqiured <...> "key"
|
||||
/// <...> "value"
|
||||
|
||||
auto & map_schema = schemas.emplace_back();
|
||||
map_schema.__set_repetition_type(parq::FieldRepetitionType::REQUIRED);
|
||||
map_schema.__set_name(name);
|
||||
map_schema.__set_num_children(1);
|
||||
map_schema.__set_converted_type(parq::ConvertedType::MAP);
|
||||
map_schema.__set_logicalType({});
|
||||
map_schema.logicalType.__set_MAP({});
|
||||
|
||||
size_t tuple_schema_idx = schemas.size();
|
||||
size_t child_states_begin = states.size();
|
||||
|
||||
prepareColumnTuple(column_tuple, tuple_type, "key_value", options, states, schemas);
|
||||
|
||||
schemas[tuple_schema_idx].__set_repetition_type(parq::FieldRepetitionType::REPEATED);
|
||||
schemas[tuple_schema_idx].__set_converted_type(parq::ConvertedType::MAP_KEY_VALUE);
|
||||
|
||||
for (size_t i = child_states_begin; i < states.size(); ++i)
|
||||
{
|
||||
Strings & path = states[i].column_chunk.meta_data.path_in_schema;
|
||||
path.insert(path.begin(), name);
|
||||
|
||||
updateRepDefLevelsForArray(states[i], offsets);
|
||||
}
|
||||
}
|
||||
|
||||
void prepareColumnRecursive(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates & states, SchemaElements & schemas)
|
||||
{
|
||||
switch (type->getTypeId())
|
||||
{
|
||||
case TypeIndex::Nullable: prepareColumnNullable(column, type, name, options, states, schemas); break;
|
||||
case TypeIndex::Array: prepareColumnArray(column, type, name, options, states, schemas); break;
|
||||
case TypeIndex::Tuple: prepareColumnTuple(column, type, name, options, states, schemas); break;
|
||||
case TypeIndex::Map: prepareColumnMap(column, type, name, options, states, schemas); break;
|
||||
case TypeIndex::LowCardinality:
|
||||
{
|
||||
auto nested_type = assert_cast<const DataTypeLowCardinality &>(*type).getDictionaryType();
|
||||
if (nested_type->isNullable())
|
||||
prepareColumnNullable(
|
||||
column->convertToFullColumnIfLowCardinality(), nested_type, name, options, states, schemas);
|
||||
else
|
||||
/// Use nested data type, but keep ColumnLowCardinality. The encoder can deal with it.
|
||||
preparePrimitiveColumn(column, nested_type, name, options, states, schemas);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
preparePrimitiveColumn(column, type, name, options, states, schemas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SchemaElements convertSchema(const Block & sample, const WriteOptions & options)
|
||||
{
|
||||
SchemaElements schema;
|
||||
auto & root = schema.emplace_back();
|
||||
root.__set_name("schema");
|
||||
root.__set_num_children(static_cast<Int32>(sample.columns()));
|
||||
|
||||
for (const auto & c : sample)
|
||||
prepareColumnForWrite(c.column, c.type, c.name, options, nullptr, &schema);
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
void prepareColumnForWrite(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates * out_columns_to_write, SchemaElements * out_schema)
|
||||
{
|
||||
if (column->empty() && out_columns_to_write != nullptr)
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Empty column passed to Parquet encoder");
|
||||
|
||||
ColumnChunkWriteStates states;
|
||||
SchemaElements schemas;
|
||||
prepareColumnRecursive(column, type, name, options, states, schemas);
|
||||
|
||||
if (out_columns_to_write)
|
||||
for (auto & s : states)
|
||||
out_columns_to_write->push_back(std::move(s));
|
||||
if (out_schema)
|
||||
out_schema->insert(out_schema->end(), schemas.begin(), schemas.end());
|
||||
|
||||
if (column->empty())
|
||||
states.clear();
|
||||
}
|
||||
|
||||
}
|
35
src/Processors/Formats/Impl/Parquet/ThriftUtil.cpp
Normal file
35
src/Processors/Formats/Impl/Parquet/ThriftUtil.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <Processors/Formats/Impl/Parquet/ThriftUtil.h>
|
||||
#include <thrift/protocol/TCompactProtocol.h>
|
||||
|
||||
namespace DB::Parquet
|
||||
{
|
||||
|
||||
class WriteBufferTransport : public apache::thrift::transport::TTransport
|
||||
{
|
||||
public:
|
||||
WriteBuffer & out;
|
||||
size_t bytes = 0;
|
||||
|
||||
explicit WriteBufferTransport(WriteBuffer & out_) : out(out_) {}
|
||||
|
||||
void write(const uint8_t* buf, uint32_t len)
|
||||
{
|
||||
out.write(reinterpret_cast<const char *>(buf), len);
|
||||
bytes += len;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
size_t serializeThriftStruct(const T & obj, WriteBuffer & out)
|
||||
{
|
||||
auto trans = std::make_shared<WriteBufferTransport>(out);
|
||||
auto proto = apache::thrift::protocol::TCompactProtocolFactoryT<WriteBufferTransport>().getProtocol(trans);
|
||||
obj.write(proto.get());
|
||||
return trans->bytes;
|
||||
}
|
||||
|
||||
template size_t serializeThriftStruct<parquet::format::PageHeader>(const parquet::format::PageHeader &, WriteBuffer & out);
|
||||
template size_t serializeThriftStruct<parquet::format::ColumnChunk>(const parquet::format::ColumnChunk &, WriteBuffer & out);
|
||||
template size_t serializeThriftStruct<parquet::format::FileMetaData>(const parquet::format::FileMetaData &, WriteBuffer & out);
|
||||
|
||||
}
|
17
src/Processors/Formats/Impl/Parquet/ThriftUtil.h
Normal file
17
src/Processors/Formats/Impl/Parquet/ThriftUtil.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <generated/parquet_types.h> // in contrib/arrow/cpp/src/ , generated from parquet.thrift
|
||||
#include <IO/WriteBuffer.h>
|
||||
|
||||
namespace DB::Parquet
|
||||
{
|
||||
|
||||
/// Returns number of bytes written.
|
||||
template <typename T>
|
||||
size_t serializeThriftStruct(const T & obj, WriteBuffer & out);
|
||||
|
||||
extern template size_t serializeThriftStruct<parquet::format::PageHeader>(const parquet::format::PageHeader &, WriteBuffer & out);
|
||||
extern template size_t serializeThriftStruct<parquet::format::ColumnChunk>(const parquet::format::ColumnChunk &, WriteBuffer & out);
|
||||
extern template size_t serializeThriftStruct<parquet::format::FileMetaData>(const parquet::format::FileMetaData &, WriteBuffer & out);
|
||||
|
||||
}
|
911
src/Processors/Formats/Impl/Parquet/Write.cpp
Normal file
911
src/Processors/Formats/Impl/Parquet/Write.cpp
Normal file
@ -0,0 +1,911 @@
|
||||
#include "Processors/Formats/Impl/Parquet/Write.h"
|
||||
#include "Processors/Formats/Impl/Parquet/ThriftUtil.h"
|
||||
#include <parquet/encoding.h>
|
||||
#include <parquet/schema.h>
|
||||
#include <arrow/util/rle_encoding.h>
|
||||
#include <lz4.h>
|
||||
#include <Columns/MaskOperations.h>
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnArray.h>
|
||||
#include <Columns/ColumnDecimal.h>
|
||||
#include <Columns/ColumnTuple.h>
|
||||
#include <Columns/ColumnMap.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include "config_version.h"
|
||||
|
||||
#if USE_SNAPPY
|
||||
#include <snappy.h>
|
||||
#endif
|
||||
|
||||
namespace DB::ErrorCodes
|
||||
{
|
||||
extern const int CANNOT_COMPRESS;
|
||||
extern const int LIMIT_EXCEEDED;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
namespace DB::Parquet
|
||||
{
|
||||
|
||||
namespace parq = parquet::format;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T, typename SourceType>
|
||||
struct StatisticsNumeric
|
||||
{
|
||||
T min = std::numeric_limits<T>::max();
|
||||
T max = std::numeric_limits<T>::min();
|
||||
|
||||
void add(SourceType x)
|
||||
{
|
||||
min = std::min(min, static_cast<T>(x));
|
||||
max = std::max(max, static_cast<T>(x));
|
||||
}
|
||||
|
||||
void merge(const StatisticsNumeric & s)
|
||||
{
|
||||
min = std::min(min, s.min);
|
||||
max = std::max(max, s.max);
|
||||
}
|
||||
|
||||
void clear() { *this = {}; }
|
||||
|
||||
parq::Statistics get(const WriteOptions &)
|
||||
{
|
||||
parq::Statistics s;
|
||||
s.__isset.min_value = s.__isset.max_value = true;
|
||||
s.min_value.resize(sizeof(T));
|
||||
s.max_value.resize(sizeof(T));
|
||||
memcpy(s.min_value.data(), &min, sizeof(T));
|
||||
memcpy(s.max_value.data(), &max, sizeof(T));
|
||||
|
||||
if constexpr (std::is_signed<T>::value)
|
||||
{
|
||||
s.__set_min(s.min_value);
|
||||
s.__set_max(s.max_value);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
struct StatisticsFixedStringRef
|
||||
{
|
||||
size_t fixed_string_size = UINT64_MAX;
|
||||
const uint8_t * min = nullptr;
|
||||
const uint8_t * max = nullptr;
|
||||
|
||||
void add(parquet::FixedLenByteArray a)
|
||||
{
|
||||
chassert(fixed_string_size != UINT64_MAX);
|
||||
addMin(a.ptr);
|
||||
addMax(a.ptr);
|
||||
}
|
||||
|
||||
void merge(const StatisticsFixedStringRef & s)
|
||||
{
|
||||
chassert(fixed_string_size == UINT64_MAX || fixed_string_size == s.fixed_string_size);
|
||||
fixed_string_size = s.fixed_string_size;
|
||||
if (s.min == nullptr)
|
||||
return;
|
||||
addMin(s.min);
|
||||
addMax(s.max);
|
||||
}
|
||||
|
||||
void clear() { min = max = nullptr; }
|
||||
|
||||
parq::Statistics get(const WriteOptions & options) const
|
||||
{
|
||||
parq::Statistics s;
|
||||
if (min == nullptr || fixed_string_size > options.max_statistics_size)
|
||||
return s;
|
||||
s.__set_min_value(std::string(reinterpret_cast<const char *>(min), fixed_string_size));
|
||||
s.__set_max_value(std::string(reinterpret_cast<const char *>(max), fixed_string_size));
|
||||
return s;
|
||||
}
|
||||
|
||||
void addMin(const uint8_t * p)
|
||||
{
|
||||
if (min == nullptr || memcmp(p, min, fixed_string_size) < 0)
|
||||
min = p;
|
||||
}
|
||||
void addMax(const uint8_t * p)
|
||||
{
|
||||
if (max == nullptr || memcmp(p, max, fixed_string_size) > 0)
|
||||
max = p;
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t S>
|
||||
struct StatisticsFixedStringCopy
|
||||
{
|
||||
bool empty = true;
|
||||
std::array<uint8_t, S> min {};
|
||||
std::array<uint8_t, S> max {};
|
||||
|
||||
void add(parquet::FixedLenByteArray a)
|
||||
{
|
||||
addMin(a.ptr);
|
||||
addMax(a.ptr);
|
||||
empty = false;
|
||||
}
|
||||
|
||||
void merge(const StatisticsFixedStringCopy<S> & s)
|
||||
{
|
||||
if (s.empty)
|
||||
return;
|
||||
addMin(&s.min[0]);
|
||||
addMax(&s.max[0]);
|
||||
empty = false;
|
||||
}
|
||||
|
||||
void clear() { empty = true; }
|
||||
|
||||
parq::Statistics get(const WriteOptions &) const
|
||||
{
|
||||
parq::Statistics s;
|
||||
if (empty)
|
||||
return s;
|
||||
s.__set_min_value(std::string(reinterpret_cast<const char *>(min.data()), S));
|
||||
s.__set_max_value(std::string(reinterpret_cast<const char *>(max.data()), S));
|
||||
return s;
|
||||
}
|
||||
|
||||
void addMin(const uint8_t * p)
|
||||
{
|
||||
if (empty || memcmp(p, min.data(), S) < 0)
|
||||
memcpy(min.data(), p, S);
|
||||
}
|
||||
void addMax(const uint8_t * p)
|
||||
{
|
||||
if (empty || memcmp(p, max.data(), S) > 0)
|
||||
memcpy(max.data(), p, S);
|
||||
}
|
||||
};
|
||||
|
||||
struct StatisticsStringRef
|
||||
{
|
||||
parquet::ByteArray min;
|
||||
parquet::ByteArray max;
|
||||
|
||||
void add(parquet::ByteArray x)
|
||||
{
|
||||
addMin(x);
|
||||
addMax(x);
|
||||
}
|
||||
|
||||
void merge(const StatisticsStringRef & s)
|
||||
{
|
||||
if (s.min.ptr == nullptr)
|
||||
return;
|
||||
addMin(s.min);
|
||||
addMax(s.max);
|
||||
}
|
||||
|
||||
void clear() { *this = {}; }
|
||||
|
||||
parq::Statistics get(const WriteOptions & options) const
|
||||
{
|
||||
parq::Statistics s;
|
||||
if (min.ptr == nullptr)
|
||||
return s;
|
||||
if (static_cast<size_t>(min.len) <= options.max_statistics_size)
|
||||
s.__set_min_value(std::string(reinterpret_cast<const char *>(min.ptr), static_cast<size_t>(min.len)));
|
||||
if (static_cast<size_t>(max.len) <= options.max_statistics_size)
|
||||
s.__set_max_value(std::string(reinterpret_cast<const char *>(max.ptr), static_cast<size_t>(max.len)));
|
||||
return s;
|
||||
}
|
||||
|
||||
void addMin(parquet::ByteArray x)
|
||||
{
|
||||
if (min.ptr == nullptr || compare(x, min) < 0)
|
||||
min = x;
|
||||
}
|
||||
|
||||
void addMax(parquet::ByteArray x)
|
||||
{
|
||||
if (max.ptr == nullptr || compare(x, max) > 0)
|
||||
max = x;
|
||||
}
|
||||
|
||||
static int compare(parquet::ByteArray a, parquet::ByteArray b)
|
||||
{
|
||||
int t = memcmp(a.ptr, b.ptr, std::min(a.len, b.len));
|
||||
if (t != 0)
|
||||
return t;
|
||||
return a.len - b.len;
|
||||
}
|
||||
};
|
||||
|
||||
/// The column usually needs to be converted to one of Parquet physical types, e.g. UInt16 -> Int32
|
||||
/// or [element of ColumnString] -> std::string_view.
|
||||
/// We do this conversion in small batches rather than all at once, just before encoding the batch,
|
||||
/// in hopes of getting better performance through cache locality.
|
||||
/// The Coverter* structs below are responsible for that.
|
||||
/// When conversion is not needed, getBatch() will just return pointer into original data.
|
||||
|
||||
template <typename Col, typename To, typename MinMaxType = typename std::conditional<
|
||||
std::is_signed<typename Col::Container::value_type>::value,
|
||||
To,
|
||||
typename std::make_unsigned<To>::type>::type>
|
||||
struct ConverterNumeric
|
||||
{
|
||||
using Statistics = StatisticsNumeric<MinMaxType, To>;
|
||||
|
||||
const Col & column;
|
||||
PODArray<To> buf;
|
||||
|
||||
explicit ConverterNumeric(const ColumnPtr & c) : column(assert_cast<const Col &>(*c)) {}
|
||||
|
||||
const To * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
if constexpr (sizeof(*column.getData().data()) == sizeof(To))
|
||||
return reinterpret_cast<const To *>(column.getData().data() + offset);
|
||||
else
|
||||
{
|
||||
buf.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
buf[i] = static_cast<To>(column.getData()[offset + i]); // NOLINT
|
||||
return buf.data();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ConverterString
|
||||
{
|
||||
using Statistics = StatisticsStringRef;
|
||||
|
||||
const ColumnString & column;
|
||||
PODArray<parquet::ByteArray> buf;
|
||||
|
||||
explicit ConverterString(const ColumnPtr & c) : column(assert_cast<const ColumnString &>(*c)) {}
|
||||
|
||||
const parquet::ByteArray * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
buf.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
StringRef s = column.getDataAt(offset + i);
|
||||
buf[i] = parquet::ByteArray(static_cast<UInt32>(s.size), reinterpret_cast<const uint8_t *>(s.data));
|
||||
}
|
||||
return buf.data();
|
||||
}
|
||||
};
|
||||
|
||||
struct ConverterFixedString
|
||||
{
|
||||
using Statistics = StatisticsFixedStringRef;
|
||||
|
||||
const ColumnFixedString & column;
|
||||
PODArray<parquet::FixedLenByteArray> buf;
|
||||
|
||||
explicit ConverterFixedString(const ColumnPtr & c) : column(assert_cast<const ColumnFixedString &>(*c)) {}
|
||||
|
||||
const parquet::FixedLenByteArray * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
buf.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
buf[i].ptr = reinterpret_cast<const uint8_t *>(column.getChars().data() + (offset + i) * column.getN());
|
||||
return buf.data();
|
||||
}
|
||||
|
||||
size_t fixedStringSize() { return column.getN(); }
|
||||
};
|
||||
|
||||
struct ConverterFixedStringAsString
|
||||
{
|
||||
using Statistics = StatisticsStringRef;
|
||||
|
||||
const ColumnFixedString & column;
|
||||
PODArray<parquet::ByteArray> buf;
|
||||
|
||||
explicit ConverterFixedStringAsString(const ColumnPtr & c) : column(assert_cast<const ColumnFixedString &>(*c)) {}
|
||||
|
||||
const parquet::ByteArray * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
buf.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
buf[i] = parquet::ByteArray(static_cast<UInt32>(column.getN()), reinterpret_cast<const uint8_t *>(column.getChars().data() + (offset + i) * column.getN()));
|
||||
return buf.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ConverterNumberAsFixedString
|
||||
{
|
||||
/// Calculate min/max statistics for little-endian fixed strings, not numbers, because parquet
|
||||
/// doesn't know it's numbers.
|
||||
using Statistics = StatisticsFixedStringCopy<sizeof(T)>;
|
||||
|
||||
const ColumnVector<T> & column;
|
||||
PODArray<parquet::FixedLenByteArray> buf;
|
||||
|
||||
explicit ConverterNumberAsFixedString(const ColumnPtr & c) : column(assert_cast<const ColumnVector<T> &>(*c)) {}
|
||||
|
||||
const parquet::FixedLenByteArray * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
buf.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
buf[i].ptr = reinterpret_cast<const uint8_t *>(column.getData().data() + offset + i);
|
||||
return buf.data();
|
||||
}
|
||||
|
||||
size_t fixedStringSize() { return sizeof(T); }
|
||||
};
|
||||
|
||||
/// Like ConverterNumberAsFixedString, but converts to big-endian. Because that's the byte order
|
||||
/// Parquet uses for decimal types and literally nothing else, for some reason.
|
||||
template <typename T>
|
||||
struct ConverterDecimal
|
||||
{
|
||||
using Statistics = StatisticsFixedStringCopy<sizeof(T)>;
|
||||
|
||||
const ColumnDecimal<T> & column;
|
||||
PODArray<uint8_t> data_buf;
|
||||
PODArray<parquet::FixedLenByteArray> ptr_buf;
|
||||
|
||||
explicit ConverterDecimal(const ColumnPtr & c) : column(assert_cast<const ColumnDecimal<T> &>(*c)) {}
|
||||
|
||||
const parquet::FixedLenByteArray * getBatch(size_t offset, size_t count)
|
||||
{
|
||||
data_buf.resize(count * sizeof(T));
|
||||
ptr_buf.resize(count);
|
||||
memcpy(data_buf.data(), reinterpret_cast<const char *>(column.getData().data() + offset), count * sizeof(T));
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
std::reverse(data_buf.data() + i * sizeof(T), data_buf.data() + (i + 1) * sizeof(T));
|
||||
ptr_buf[i].ptr = data_buf.data() + i * sizeof(T);
|
||||
}
|
||||
return ptr_buf.data();
|
||||
}
|
||||
|
||||
size_t fixedStringSize() { return sizeof(T); }
|
||||
};
|
||||
|
||||
/// Returns either `source` or `scratch`.
|
||||
PODArray<char> & compress(PODArray<char> & source, PODArray<char> & scratch, CompressionMethod method)
|
||||
{
|
||||
/// We could use wrapWriteBufferWithCompressionMethod() for everything, but I worry about the
|
||||
/// overhead of creating a bunch of WriteBuffers on each page (thousands of values).
|
||||
switch (method)
|
||||
{
|
||||
case CompressionMethod::None:
|
||||
return source;
|
||||
|
||||
case CompressionMethod::Lz4:
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
|
||||
size_t max_dest_size = LZ4_COMPRESSBOUND(source.size());
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
if (max_dest_size > std::numeric_limits<int>::max())
|
||||
throw Exception(ErrorCodes::CANNOT_COMPRESS, "Cannot compress column of size {}", formatReadableSizeWithBinarySuffix(source.size()));
|
||||
|
||||
scratch.resize(max_dest_size);
|
||||
|
||||
int compressed_size = LZ4_compress_default(
|
||||
source.data(),
|
||||
scratch.data(),
|
||||
static_cast<int>(source.size()),
|
||||
static_cast<int>(max_dest_size));
|
||||
|
||||
scratch.resize(static_cast<size_t>(compressed_size));
|
||||
return scratch;
|
||||
}
|
||||
|
||||
#if USE_SNAPPY
|
||||
case CompressionMethod::Snappy:
|
||||
{
|
||||
size_t max_dest_size = snappy::MaxCompressedLength(source.size());
|
||||
|
||||
if (max_dest_size > std::numeric_limits<int>::max())
|
||||
throw Exception(ErrorCodes::CANNOT_COMPRESS, "Cannot compress column of size {}", formatReadableSizeWithBinarySuffix(source.size()));
|
||||
|
||||
scratch.resize(max_dest_size);
|
||||
|
||||
size_t compressed_size;
|
||||
snappy::RawCompress(source.data(), source.size(), scratch.data(), &compressed_size);
|
||||
|
||||
scratch.resize(static_cast<size_t>(compressed_size));
|
||||
return scratch;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
auto dest_buf = std::make_unique<WriteBufferFromVector<PODArray<char>>>(scratch);
|
||||
auto compressed_buf = wrapWriteBufferWithCompressionMethod(
|
||||
std::move(dest_buf),
|
||||
method,
|
||||
/*level*/ 3,
|
||||
source.size(),
|
||||
/*existing_memory*/ source.data());
|
||||
chassert(compressed_buf->position() == source.data());
|
||||
chassert(compressed_buf->available() == source.size());
|
||||
compressed_buf->position() += source.size();
|
||||
compressed_buf->finalize();
|
||||
return scratch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void encodeRepDefLevelsRLE(const UInt8 * data, size_t size, UInt8 max_level, PODArray<char> & out)
|
||||
{
|
||||
using arrow::util::RleEncoder;
|
||||
|
||||
chassert(max_level > 0);
|
||||
size_t offset = out.size();
|
||||
size_t prefix_size = sizeof(Int32);
|
||||
|
||||
int bit_width = bitScanReverse(max_level) + 1;
|
||||
int max_rle_size = RleEncoder::MaxBufferSize(bit_width, static_cast<int>(size)) +
|
||||
RleEncoder::MinBufferSize(bit_width);
|
||||
|
||||
out.resize(offset + prefix_size + max_rle_size);
|
||||
|
||||
RleEncoder encoder(reinterpret_cast<uint8_t *>(out.data() + offset + prefix_size), max_rle_size, bit_width);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
encoder.Put(data[i]);
|
||||
encoder.Flush();
|
||||
Int32 len = encoder.len();
|
||||
|
||||
memcpy(out.data() + offset, &len, prefix_size);
|
||||
out.resize(offset + prefix_size + len);
|
||||
}
|
||||
|
||||
void addToEncodingsUsed(ColumnChunkWriteState & s, parq::Encoding::type e)
|
||||
{
|
||||
if (!std::count(s.column_chunk.meta_data.encodings.begin(), s.column_chunk.meta_data.encodings.end(), e))
|
||||
s.column_chunk.meta_data.encodings.push_back(e);
|
||||
}
|
||||
|
||||
void writePage(const parq::PageHeader & header, const PODArray<char> & compressed, ColumnChunkWriteState & s, WriteBuffer & out)
|
||||
{
|
||||
size_t header_size = serializeThriftStruct(header, out);
|
||||
out.write(compressed.data(), compressed.size());
|
||||
|
||||
/// Remember first data page and first dictionary page.
|
||||
if (header.__isset.data_page_header && s.column_chunk.meta_data.data_page_offset == -1)
|
||||
s.column_chunk.meta_data.__set_data_page_offset(s.column_chunk.meta_data.total_compressed_size);
|
||||
if (header.__isset.dictionary_page_header && !s.column_chunk.meta_data.__isset.dictionary_page_offset)
|
||||
s.column_chunk.meta_data.__set_dictionary_page_offset(s.column_chunk.meta_data.total_compressed_size);
|
||||
|
||||
s.column_chunk.meta_data.total_uncompressed_size += header.uncompressed_page_size + header_size;
|
||||
s.column_chunk.meta_data.total_compressed_size += header.compressed_page_size + header_size;
|
||||
}
|
||||
|
||||
template <typename ParquetDType, typename Converter>
|
||||
void writeColumnImpl(
|
||||
ColumnChunkWriteState & s, const WriteOptions & options, WriteBuffer & out, Converter && converter)
|
||||
{
|
||||
size_t num_values = s.max_def > 0 ? s.def.size() : s.primitive_column->size();
|
||||
auto encoding = options.encoding;
|
||||
|
||||
typename Converter::Statistics page_statistics;
|
||||
typename Converter::Statistics total_statistics;
|
||||
|
||||
bool use_dictionary = options.use_dictionary_encoding && !s.is_bool;
|
||||
|
||||
std::optional<parquet::ColumnDescriptor> fixed_string_descr;
|
||||
if constexpr (std::is_same<ParquetDType, parquet::FLBAType>::value)
|
||||
{
|
||||
/// This just communicates one number to MakeTypedEncoder(): the fixed string length.
|
||||
fixed_string_descr.emplace(parquet::schema::PrimitiveNode::Make(
|
||||
"", parquet::Repetition::REQUIRED, parquet::Type::FIXED_LEN_BYTE_ARRAY,
|
||||
parquet::ConvertedType::NONE, static_cast<int>(converter.fixedStringSize())), 0, 0);
|
||||
|
||||
if constexpr (std::is_same<typename Converter::Statistics, StatisticsFixedStringRef>::value)
|
||||
page_statistics.fixed_string_size = converter.fixedStringSize();
|
||||
}
|
||||
|
||||
/// Could use an arena here (by passing a custom MemoryPool), to reuse memory across pages.
|
||||
/// Alternatively, we could avoid using arrow's dictionary encoding code and leverage
|
||||
/// ColumnLowCardinality instead. It would work basically the same way as what this function
|
||||
/// currently does: add values to the ColumnRowCardinality (instead of `encoder`) in batches,
|
||||
/// checking dictionary size after each batch. That might be faster.
|
||||
auto encoder = parquet::MakeTypedEncoder<ParquetDType>(
|
||||
// ignored if using dictionary
|
||||
static_cast<parquet::Encoding::type>(encoding),
|
||||
use_dictionary, fixed_string_descr ? &*fixed_string_descr : nullptr);
|
||||
|
||||
struct PageData
|
||||
{
|
||||
parq::PageHeader header;
|
||||
PODArray<char> data;
|
||||
};
|
||||
std::vector<PageData> dict_encoded_pages; // can't write them out until we have full dictionary
|
||||
|
||||
/// Reused across pages to reduce number of allocations and improve locality.
|
||||
PODArray<char> encoded;
|
||||
PODArray<char> compressed_maybe;
|
||||
|
||||
/// Start of current page.
|
||||
size_t def_offset = 0; // index in def and rep
|
||||
size_t data_offset = 0; // index in primitive_column
|
||||
|
||||
auto flush_page = [&](size_t def_count, size_t data_count)
|
||||
{
|
||||
encoded.clear();
|
||||
|
||||
/// Concatenate encoded rep, def, and data.
|
||||
|
||||
if (s.max_rep > 0)
|
||||
encodeRepDefLevelsRLE(s.rep.data() + def_offset, def_count, s.max_rep, encoded);
|
||||
if (s.max_def > 0)
|
||||
encodeRepDefLevelsRLE(s.def.data() + def_offset, def_count, s.max_def, encoded);
|
||||
|
||||
std::shared_ptr<parquet::Buffer> values = encoder->FlushValues(); // resets it for next page
|
||||
|
||||
encoded.resize(encoded.size() + values->size());
|
||||
memcpy(encoded.data() + encoded.size() - values->size(), values->data(), values->size());
|
||||
values.reset();
|
||||
|
||||
if (encoded.size() > INT32_MAX)
|
||||
throw Exception(ErrorCodes::CANNOT_COMPRESS, "Uncompressed page is too big: {}", encoded.size());
|
||||
|
||||
size_t uncompressed_size = encoded.size();
|
||||
auto & compressed = compress(encoded, compressed_maybe, s.compression);
|
||||
|
||||
if (compressed.size() > INT32_MAX)
|
||||
throw Exception(ErrorCodes::CANNOT_COMPRESS, "Compressed page is too big: {}", compressed.size());
|
||||
|
||||
parq::PageHeader header;
|
||||
header.__set_type(parq::PageType::DATA_PAGE);
|
||||
header.__set_uncompressed_page_size(static_cast<int>(uncompressed_size));
|
||||
header.__set_compressed_page_size(static_cast<int>(compressed.size()));
|
||||
header.__isset.data_page_header = true;
|
||||
auto & d = header.data_page_header;
|
||||
d.__set_num_values(static_cast<Int32>(def_count));
|
||||
d.__set_encoding(use_dictionary ? parq::Encoding::RLE_DICTIONARY : encoding);
|
||||
d.__set_definition_level_encoding(parq::Encoding::RLE);
|
||||
d.__set_repetition_level_encoding(parq::Encoding::RLE);
|
||||
/// We could also put checksum in `header.crc`, but apparently no one uses it:
|
||||
/// https://issues.apache.org/jira/browse/PARQUET-594
|
||||
|
||||
if (options.write_page_statistics)
|
||||
{
|
||||
d.__set_statistics(page_statistics.get(options));
|
||||
|
||||
if (s.max_def == 1 && s.max_rep == 0)
|
||||
d.statistics.__set_null_count(static_cast<Int64>(def_count - data_count));
|
||||
}
|
||||
|
||||
total_statistics.merge(page_statistics);
|
||||
page_statistics.clear();
|
||||
|
||||
if (use_dictionary)
|
||||
{
|
||||
dict_encoded_pages.push_back({.header = std::move(header)});
|
||||
std::swap(dict_encoded_pages.back().data, compressed);
|
||||
}
|
||||
else
|
||||
{
|
||||
writePage(header, compressed, s, out);
|
||||
}
|
||||
|
||||
def_offset += def_count;
|
||||
data_offset += data_count;
|
||||
};
|
||||
|
||||
auto flush_dict = [&] -> bool
|
||||
{
|
||||
auto * dict_encoder = dynamic_cast<parquet::DictEncoder<ParquetDType> *>(encoder.get());
|
||||
int dict_size = dict_encoder->dict_encoded_size();
|
||||
|
||||
encoded.resize(static_cast<size_t>(dict_size));
|
||||
dict_encoder->WriteDict(reinterpret_cast<uint8_t *>(encoded.data()));
|
||||
|
||||
auto & compressed = compress(encoded, compressed_maybe, s.compression);
|
||||
|
||||
if (compressed.size() > INT32_MAX)
|
||||
throw Exception(ErrorCodes::CANNOT_COMPRESS, "Compressed dictionary page is too big: {}", compressed.size());
|
||||
|
||||
parq::PageHeader header;
|
||||
header.__set_type(parq::PageType::DICTIONARY_PAGE);
|
||||
header.__set_uncompressed_page_size(dict_size);
|
||||
header.__set_compressed_page_size(static_cast<int>(compressed.size()));
|
||||
header.__isset.dictionary_page_header = true;
|
||||
header.dictionary_page_header.__set_num_values(dict_encoder->num_entries());
|
||||
header.dictionary_page_header.__set_encoding(parq::Encoding::PLAIN);
|
||||
|
||||
writePage(header, compressed, s, out);
|
||||
|
||||
for (auto & p : dict_encoded_pages)
|
||||
writePage(p.header, p.data, s, out);
|
||||
|
||||
dict_encoded_pages.clear();
|
||||
encoder.reset();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto is_dict_too_big = [&] {
|
||||
auto * dict_encoder = dynamic_cast<parquet::DictEncoder<ParquetDType> *>(encoder.get());
|
||||
int dict_size = dict_encoder->dict_encoded_size();
|
||||
return static_cast<size_t>(dict_size) >= options.dictionary_size_limit;
|
||||
};
|
||||
|
||||
while (def_offset < num_values)
|
||||
{
|
||||
/// Pick enough data for a page.
|
||||
size_t next_def_offset = def_offset;
|
||||
size_t next_data_offset = data_offset;
|
||||
while (true)
|
||||
{
|
||||
/// Bite off a batch of defs and corresponding data values.
|
||||
size_t def_count = std::min(options.write_batch_size, num_values - next_def_offset);
|
||||
size_t data_count = 0;
|
||||
if (s.max_def == 0)
|
||||
data_count = def_count;
|
||||
else
|
||||
for (size_t i = 0; i < def_count; ++i)
|
||||
data_count += s.def[next_def_offset + i] == s.max_def;
|
||||
|
||||
/// Encode the data (but not the levels yet), so that we can estimate its encoded size.
|
||||
const typename ParquetDType::c_type * converted = converter.getBatch(next_data_offset, data_count);
|
||||
|
||||
if (options.write_page_statistics || options.write_column_chunk_statistics)
|
||||
/// Workaround for clang bug: https://github.com/llvm/llvm-project/issues/63630
|
||||
#ifdef MEMORY_SANITIZER
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for (size_t i = 0; i < data_count; ++i)
|
||||
page_statistics.add(converted[i]);
|
||||
|
||||
encoder->Put(converted, static_cast<int>(data_count));
|
||||
|
||||
next_def_offset += def_count;
|
||||
next_data_offset += data_count;
|
||||
|
||||
if (use_dictionary && is_dict_too_big())
|
||||
{
|
||||
/// Fallback to non-dictionary encoding.
|
||||
///
|
||||
/// Discard encoded data and start over.
|
||||
/// This is different from what arrow does: arrow writes out the dictionary-encoded
|
||||
/// data, then uses non-dictionary encoding for later pages.
|
||||
/// Starting over seems better: it produces slightly smaller files (I saw 1-4%) in
|
||||
/// exchange for slight decrease in speed (I saw < 5%). This seems like a good
|
||||
/// trade because encoding speed is much less important than decoding (as evidenced
|
||||
/// by arrow not supporting parallel encoding, even though it's easy to support).
|
||||
|
||||
def_offset = 0;
|
||||
data_offset = 0;
|
||||
dict_encoded_pages.clear();
|
||||
use_dictionary = false;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Arrow's DictEncoderImpl destructor asserts that FlushValues() was called, so we
|
||||
/// call it even though we don't need its output.
|
||||
encoder->FlushValues();
|
||||
#endif
|
||||
|
||||
encoder = parquet::MakeTypedEncoder<ParquetDType>(
|
||||
static_cast<parquet::Encoding::type>(encoding), /* use_dictionary */ false,
|
||||
fixed_string_descr ? &*fixed_string_descr : nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (next_def_offset == num_values ||
|
||||
static_cast<size_t>(encoder->EstimatedDataEncodedSize()) >= options.data_page_size)
|
||||
{
|
||||
flush_page(next_def_offset - def_offset, next_data_offset - data_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_dictionary)
|
||||
flush_dict();
|
||||
|
||||
chassert(data_offset == s.primitive_column->size());
|
||||
|
||||
if (options.write_column_chunk_statistics)
|
||||
{
|
||||
s.column_chunk.meta_data.__set_statistics(total_statistics.get(options));
|
||||
|
||||
if (s.max_def == 1 && s.max_rep == 0)
|
||||
s.column_chunk.meta_data.statistics.__set_null_count(static_cast<Int64>(def_offset - data_offset));
|
||||
}
|
||||
|
||||
/// Report which encodings we've used.
|
||||
if (s.max_rep > 0 || s.max_def > 0)
|
||||
addToEncodingsUsed(s, parq::Encoding::RLE); // levels
|
||||
if (use_dictionary)
|
||||
{
|
||||
addToEncodingsUsed(s, parq::Encoding::PLAIN); // dictionary itself
|
||||
addToEncodingsUsed(s, parq::Encoding::RLE_DICTIONARY); // ids
|
||||
}
|
||||
else
|
||||
{
|
||||
addToEncodingsUsed(s, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void writeColumnChunkBody(ColumnChunkWriteState & s, const WriteOptions & options, WriteBuffer & out)
|
||||
{
|
||||
s.column_chunk.meta_data.__set_num_values(s.max_def > 0 ? s.def.size() : s.primitive_column->size());
|
||||
|
||||
/// We'll be updating these as we go.
|
||||
s.column_chunk.meta_data.__set_encodings({});
|
||||
s.column_chunk.meta_data.__set_total_compressed_size(0);
|
||||
s.column_chunk.meta_data.__set_total_uncompressed_size(0);
|
||||
s.column_chunk.meta_data.__set_data_page_offset(-1);
|
||||
|
||||
s.primitive_column = s.primitive_column->convertToFullColumnIfLowCardinality();
|
||||
|
||||
switch (s.primitive_column->getDataType())
|
||||
{
|
||||
/// Numeric conversion to Int32 or Int64.
|
||||
#define N(source_type, parquet_dtype) \
|
||||
writeColumnImpl<parquet::parquet_dtype>(s, options, out, \
|
||||
ConverterNumeric<ColumnVector<source_type>, parquet::parquet_dtype::c_type>( \
|
||||
s.primitive_column))
|
||||
|
||||
case TypeIndex::UInt8:
|
||||
if (s.is_bool)
|
||||
writeColumnImpl<parquet::BooleanType>(s, options, out,
|
||||
ConverterNumeric<ColumnVector<UInt8>, bool, bool>(s.primitive_column));
|
||||
else
|
||||
N(UInt8, Int32Type);
|
||||
break;
|
||||
case TypeIndex::UInt16 : N(UInt16, Int32Type); break;
|
||||
case TypeIndex::UInt32 : N(UInt32, Int32Type); break;
|
||||
case TypeIndex::UInt64 : N(UInt64, Int64Type); break;
|
||||
case TypeIndex::Int8 : N(Int8, Int32Type); break;
|
||||
case TypeIndex::Int16 : N(Int16, Int32Type); break;
|
||||
case TypeIndex::Int32 : N(Int32, Int32Type); break;
|
||||
case TypeIndex::Int64 : N(Int64, Int64Type); break;
|
||||
|
||||
case TypeIndex::Enum8: N(Int8, Int32Type); break;
|
||||
case TypeIndex::Enum16: N(Int16, Int32Type); break;
|
||||
case TypeIndex::Date: N(UInt16, Int32Type); break;
|
||||
case TypeIndex::Date32: N(Int32, Int32Type); break;
|
||||
case TypeIndex::DateTime: N(UInt32, Int32Type); break;
|
||||
|
||||
#undef N
|
||||
|
||||
case TypeIndex::Float32:
|
||||
writeColumnImpl<parquet::FloatType>(
|
||||
s, options, out, ConverterNumeric<ColumnVector<Float32>, Float32, Float32>(
|
||||
s.primitive_column));
|
||||
break;
|
||||
|
||||
case TypeIndex::Float64:
|
||||
writeColumnImpl<parquet::DoubleType>(
|
||||
s, options, out, ConverterNumeric<ColumnVector<Float64>, Float64, Float64>(
|
||||
s.primitive_column));
|
||||
break;
|
||||
|
||||
case TypeIndex::DateTime64:
|
||||
writeColumnImpl<parquet::Int64Type>(
|
||||
s, options, out, ConverterNumeric<ColumnDecimal<DateTime64>, Int64, Int64>(
|
||||
s.primitive_column));
|
||||
break;
|
||||
|
||||
case TypeIndex::IPv4:
|
||||
writeColumnImpl<parquet::Int32Type>(
|
||||
s, options, out, ConverterNumeric<ColumnVector<IPv4>, Int32, UInt32>(
|
||||
s.primitive_column));
|
||||
break;
|
||||
|
||||
case TypeIndex::String:
|
||||
writeColumnImpl<parquet::ByteArrayType>(
|
||||
s, options, out, ConverterString(s.primitive_column));
|
||||
break;
|
||||
|
||||
case TypeIndex::FixedString:
|
||||
if (options.output_fixed_string_as_fixed_byte_array)
|
||||
writeColumnImpl<parquet::FLBAType>(
|
||||
s, options, out, ConverterFixedString(s.primitive_column));
|
||||
else
|
||||
writeColumnImpl<parquet::ByteArrayType>(
|
||||
s, options, out, ConverterFixedStringAsString(s.primitive_column));
|
||||
break;
|
||||
|
||||
#define F(source_type) \
|
||||
writeColumnImpl<parquet::FLBAType>( \
|
||||
s, options, out, ConverterNumberAsFixedString<source_type>(s.primitive_column))
|
||||
case TypeIndex::UInt128: F(UInt128); break;
|
||||
case TypeIndex::UInt256: F(UInt256); break;
|
||||
case TypeIndex::Int128: F(Int128); break;
|
||||
case TypeIndex::Int256: F(Int256); break;
|
||||
case TypeIndex::IPv6: F(IPv6); break;
|
||||
#undef F
|
||||
|
||||
#define D(source_type) \
|
||||
writeColumnImpl<parquet::FLBAType>( \
|
||||
s, options, out, ConverterDecimal<source_type>(s.primitive_column))
|
||||
case TypeIndex::Decimal32: D(Decimal32); break;
|
||||
case TypeIndex::Decimal64: D(Decimal64); break;
|
||||
case TypeIndex::Decimal128: D(Decimal128); break;
|
||||
case TypeIndex::Decimal256: D(Decimal256); break;
|
||||
#undef D
|
||||
|
||||
default:
|
||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected column type: {}", s.primitive_column->getFamilyName());
|
||||
}
|
||||
|
||||
/// Free some memory.
|
||||
s.primitive_column = {};
|
||||
s.def = {};
|
||||
s.rep = {};
|
||||
}
|
||||
|
||||
void writeFileHeader(WriteBuffer & out)
|
||||
{
|
||||
/// Write the magic bytes. We're a wizard now.
|
||||
out.write("PAR1", 4);
|
||||
}
|
||||
|
||||
parq::ColumnChunk finalizeColumnChunkAndWriteFooter(
|
||||
size_t offset_in_file, ColumnChunkWriteState s, const WriteOptions &, WriteBuffer & out)
|
||||
{
|
||||
if (s.column_chunk.meta_data.data_page_offset != -1)
|
||||
s.column_chunk.meta_data.data_page_offset += offset_in_file;
|
||||
if (s.column_chunk.meta_data.__isset.dictionary_page_offset)
|
||||
s.column_chunk.meta_data.dictionary_page_offset += offset_in_file;
|
||||
s.column_chunk.file_offset = offset_in_file + s.column_chunk.meta_data.total_compressed_size;
|
||||
|
||||
serializeThriftStruct(s.column_chunk, out);
|
||||
|
||||
return s.column_chunk;
|
||||
}
|
||||
|
||||
parq::RowGroup makeRowGroup(std::vector<parq::ColumnChunk> column_chunks, size_t num_rows)
|
||||
{
|
||||
parq::RowGroup r;
|
||||
r.__set_num_rows(num_rows);
|
||||
r.__set_columns(column_chunks);
|
||||
r.__set_total_compressed_size(0);
|
||||
for (auto & c : r.columns)
|
||||
{
|
||||
r.total_byte_size += c.meta_data.total_uncompressed_size;
|
||||
r.total_compressed_size += c.meta_data.total_compressed_size;
|
||||
}
|
||||
if (!r.columns.empty())
|
||||
{
|
||||
auto & m = r.columns[0].meta_data;
|
||||
r.__set_file_offset(m.__isset.dictionary_page_offset ? m.dictionary_page_offset : m.data_page_offset);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void writeFileFooter(std::vector<parq::RowGroup> row_groups, SchemaElements schema, const WriteOptions & options, WriteBuffer & out)
|
||||
{
|
||||
parq::FileMetaData meta;
|
||||
meta.version = 2;
|
||||
meta.schema = std::move(schema);
|
||||
meta.row_groups = std::move(row_groups);
|
||||
for (auto & r : meta.row_groups)
|
||||
meta.num_rows += r.num_rows;
|
||||
meta.__set_created_by(VERSION_NAME " " VERSION_DESCRIBE);
|
||||
|
||||
if (options.write_page_statistics || options.write_column_chunk_statistics)
|
||||
{
|
||||
meta.__set_column_orders({});
|
||||
for (auto & s : meta.schema)
|
||||
if (!s.__isset.num_children)
|
||||
meta.column_orders.emplace_back();
|
||||
for (auto & c : meta.column_orders)
|
||||
c.__set_TYPE_ORDER({});
|
||||
}
|
||||
|
||||
size_t footer_size = serializeThriftStruct(meta, out);
|
||||
|
||||
if (footer_size > INT32_MAX)
|
||||
throw Exception(ErrorCodes::LIMIT_EXCEEDED, "Parquet file metadata too big: {}", footer_size);
|
||||
|
||||
writeIntBinary(static_cast<int>(footer_size), out);
|
||||
out.write("PAR1", 4);
|
||||
}
|
||||
|
||||
}
|
136
src/Processors/Formats/Impl/Parquet/Write.h
Normal file
136
src/Processors/Formats/Impl/Parquet/Write.h
Normal file
@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include <Processors/Formats/Impl/Parquet/ThriftUtil.h>
|
||||
#include <Columns/IColumn.h>
|
||||
#include <DataTypes/IDataType.h>
|
||||
#include <Common/PODArray.h>
|
||||
#include <IO/CompressionMethod.h>
|
||||
|
||||
namespace DB::Parquet
|
||||
{
|
||||
|
||||
/// A good resource for learning how Parquet format works is
|
||||
/// contrib/arrow/cpp/src/parquet/parquet.thrift
|
||||
|
||||
struct WriteOptions
|
||||
{
|
||||
bool output_string_as_string = false;
|
||||
bool output_fixed_string_as_fixed_byte_array = true;
|
||||
|
||||
CompressionMethod compression = CompressionMethod::Lz4;
|
||||
|
||||
size_t data_page_size = 1024 * 1024;
|
||||
size_t write_batch_size = 1024;
|
||||
|
||||
bool use_dictionary_encoding = true;
|
||||
size_t dictionary_size_limit = 1024 * 1024;
|
||||
/// If using dictionary, this encoding is used as a fallback when dictionary gets too big.
|
||||
/// Otherwise, this is used for everything.
|
||||
parquet::format::Encoding::type encoding = parquet::format::Encoding::PLAIN;
|
||||
|
||||
bool write_page_statistics = true;
|
||||
bool write_column_chunk_statistics = true;
|
||||
size_t max_statistics_size = 4096;
|
||||
};
|
||||
|
||||
/// Information about a primitive column (leaf of the schema tree) to write to Parquet file.
|
||||
struct ColumnChunkWriteState
|
||||
{
|
||||
/// After writeColumnChunkBody(), offsets in this struct are relative to the start of column chunk.
|
||||
/// Then finalizeColumnChunkAndWriteFooter() fixes them up before writing to file.
|
||||
parquet::format::ColumnChunk column_chunk;
|
||||
|
||||
ColumnPtr primitive_column;
|
||||
CompressionMethod compression; // must match what's inside column_chunk
|
||||
bool is_bool = false;
|
||||
|
||||
/// Repetition and definition levels. Produced by prepareColumnForWrite().
|
||||
/// def is empty iff max_def == 0, which means no arrays or nullables.
|
||||
/// rep is empty iff max_rep == 0, which means no arrays.
|
||||
PaddedPODArray<UInt8> def; // definition levels
|
||||
PaddedPODArray<UInt8> rep; // repetition levels
|
||||
/// Max possible levels, according to schema. Actual max in def/rep may be smaller.
|
||||
UInt8 max_def = 0;
|
||||
UInt8 max_rep = 0;
|
||||
|
||||
ColumnChunkWriteState() = default;
|
||||
/// Prevent accidental copying.
|
||||
ColumnChunkWriteState(ColumnChunkWriteState &&) = default;
|
||||
ColumnChunkWriteState & operator=(ColumnChunkWriteState &&) = default;
|
||||
|
||||
/// Estimated memory usage.
|
||||
size_t allocatedBytes() const
|
||||
{
|
||||
size_t r = def.allocated_bytes() + rep.allocated_bytes();
|
||||
if (primitive_column)
|
||||
r += primitive_column->allocatedBytes();
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
using SchemaElements = std::vector<parquet::format::SchemaElement>;
|
||||
using ColumnChunkWriteStates = std::vector<ColumnChunkWriteState>;
|
||||
|
||||
/// Parquet file consists of row groups, which consist of column chunks.
|
||||
///
|
||||
/// Column chunks can be encoded mostly independently of each other, in parallel.
|
||||
/// But there are two small complications:
|
||||
/// 1. One ClickHouse column can translate to multiple leaf columns in parquet.
|
||||
/// E.g. tuples and maps.
|
||||
/// If all primitive columns are in one big tuple, we'd like to encode them in parallel too,
|
||||
/// even though they're one top-level ClickHouse column.
|
||||
/// 2. At the end of each encoded column chunk there's a footer (struct ColumnMetaData) that
|
||||
/// contains some absolute offsets in the file. We can't encode it until we know the exact
|
||||
/// position in the file where the column chunk will go. So these footers have to be serialized
|
||||
/// sequentially, after we know sizes of all previous column chunks.
|
||||
///
|
||||
/// With that in mind, here's how to write a parquet file:
|
||||
///
|
||||
/// (1) writeFileHeader()
|
||||
/// (2) For each row group:
|
||||
/// | (3) For each ClickHouse column:
|
||||
/// | (4) Call prepareColumnForWrite().
|
||||
/// | It'll produce one or more ColumnChunkWriteStates, corresponding to primitive columns that
|
||||
/// | we need to write.
|
||||
/// | It'll also produce SchemaElements as a byproduct, describing the logical types and
|
||||
/// | groupings of the physical columns (e.g. tuples, arrays, maps).
|
||||
/// | (5) For each ColumnChunkWriteState:
|
||||
/// | (6) Call writeColumnChunkBody() to write the actual data to the given WriteBuffer.
|
||||
/// | (7) Call finalizeColumnChunkAndWriteFooter() to write the footer of the column chunk.
|
||||
/// | (8) Call makeRowGroup() using the ColumnChunk metadata structs from previous step.
|
||||
/// (9) Call writeFileFooter() using the row groups from previous step and SchemaElements from
|
||||
/// convertSchema().
|
||||
///
|
||||
/// Steps (4) and (6) can be parallelized, both within and across row groups.
|
||||
|
||||
/// Parquet schema is a tree of SchemaElements, flattened into a list in depth-first order.
|
||||
/// Leaf nodes correspond to physical columns of primitive types. Inner nodes describe logical
|
||||
/// groupings of those columns, e.g. tuples or structs.
|
||||
SchemaElements convertSchema(const Block & sample, const WriteOptions & options);
|
||||
|
||||
void prepareColumnForWrite(
|
||||
ColumnPtr column, DataTypePtr type, const std::string & name, const WriteOptions & options,
|
||||
ColumnChunkWriteStates * out_columns_to_write, SchemaElements * out_schema = nullptr);
|
||||
|
||||
void writeFileHeader(WriteBuffer & out);
|
||||
|
||||
/// Encodes a column chunk, without the footer.
|
||||
/// The ColumnChunkWriteState-s should then passed to finalizeColumnChunkAndWriteFooter().
|
||||
void writeColumnChunkBody(ColumnChunkWriteState & s, const WriteOptions & options, WriteBuffer & out);
|
||||
|
||||
/// Unlike most of the column chunk data, the footer (`ColumnMetaData`) needs to know its absolute
|
||||
/// offset in the file. So we encode it separately, after all previous row groups and column chunks
|
||||
/// have been encoded.
|
||||
/// (If you're wondering if the 8-byte offset values can be patched inside the encoded blob - no,
|
||||
/// they're varint-encoded and can't be padded to a fixed length.)
|
||||
/// `offset_in_file` is the absolute position in the file where the writeColumnChunkBody()'s output
|
||||
/// starts.
|
||||
/// Returns a ColumnChunk to add to the RowGroup.
|
||||
parquet::format::ColumnChunk finalizeColumnChunkAndWriteFooter(
|
||||
size_t offset_in_file, ColumnChunkWriteState s, const WriteOptions & options, WriteBuffer & out);
|
||||
|
||||
parquet::format::RowGroup makeRowGroup(std::vector<parquet::format::ColumnChunk> column_chunks, size_t num_rows);
|
||||
|
||||
void writeFileFooter(std::vector<parquet::format::RowGroup> row_groups, SchemaElements schema, const WriteOptions & options, WriteBuffer & out);
|
||||
|
||||
}
|
@ -59,7 +59,12 @@ ParquetBlockInputFormat::ParquetBlockInputFormat(
|
||||
pool = std::make_unique<ThreadPool>(CurrentMetrics::ParquetDecoderThreads, CurrentMetrics::ParquetDecoderThreadsActive, max_decoding_threads);
|
||||
}
|
||||
|
||||
ParquetBlockInputFormat::~ParquetBlockInputFormat() = default;
|
||||
ParquetBlockInputFormat::~ParquetBlockInputFormat()
|
||||
{
|
||||
is_stopped = true;
|
||||
if (pool)
|
||||
pool->wait();
|
||||
}
|
||||
|
||||
void ParquetBlockInputFormat::initializeIfNeeded()
|
||||
{
|
||||
|
@ -3,14 +3,23 @@
|
||||
#if USE_PARQUET
|
||||
|
||||
#include <Formats/FormatFactory.h>
|
||||
#include <IO/WriteBufferFromVector.h>
|
||||
#include <parquet/arrow/writer.h>
|
||||
#include "ArrowBufferedStreams.h"
|
||||
#include "CHColumnToArrowColumn.h"
|
||||
|
||||
|
||||
namespace CurrentMetrics
|
||||
{
|
||||
extern const Metric ParquetEncoderThreads;
|
||||
extern const Metric ParquetEncoderThreadsActive;
|
||||
}
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using namespace Parquet;
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int UNKNOWN_EXCEPTION;
|
||||
@ -59,19 +68,229 @@ namespace
|
||||
if (method == FormatSettings::ParquetCompression::GZIP)
|
||||
return parquet::Compression::type::GZIP;
|
||||
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Unsupported compression method");
|
||||
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Unsupported parquet compression method");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ParquetBlockOutputFormat::ParquetBlockOutputFormat(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings_)
|
||||
: IOutputFormat(header_, out_), format_settings{format_settings_}
|
||||
{
|
||||
if (format_settings.parquet.use_custom_encoder)
|
||||
{
|
||||
if (format_settings.parquet.parallel_encoding && format_settings.max_threads > 1)
|
||||
pool = std::make_unique<ThreadPool>(
|
||||
CurrentMetrics::ParquetEncoderThreads, CurrentMetrics::ParquetEncoderThreadsActive,
|
||||
format_settings.max_threads);
|
||||
|
||||
using C = FormatSettings::ParquetCompression;
|
||||
switch (format_settings.parquet.output_compression_method)
|
||||
{
|
||||
case C::NONE: options.compression = CompressionMethod::None; break;
|
||||
case C::SNAPPY: options.compression = CompressionMethod::Snappy; break;
|
||||
case C::ZSTD: options.compression = CompressionMethod::Zstd; break;
|
||||
case C::LZ4: options.compression = CompressionMethod::Lz4; break;
|
||||
case C::GZIP: options.compression = CompressionMethod::Gzip; break;
|
||||
case C::BROTLI: options.compression = CompressionMethod::Brotli; break;
|
||||
}
|
||||
options.output_string_as_string = format_settings.parquet.output_string_as_string;
|
||||
options.output_fixed_string_as_fixed_byte_array = format_settings.parquet.output_fixed_string_as_fixed_byte_array;
|
||||
options.data_page_size = format_settings.parquet.data_page_size;
|
||||
options.write_batch_size = format_settings.parquet.write_batch_size;
|
||||
|
||||
schema = convertSchema(header_, options);
|
||||
}
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::consumeStaged()
|
||||
ParquetBlockOutputFormat::~ParquetBlockOutputFormat()
|
||||
{
|
||||
const size_t columns_num = staging_chunks.at(0).getNumColumns();
|
||||
if (pool)
|
||||
{
|
||||
is_stopped = true;
|
||||
pool->wait();
|
||||
}
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::consume(Chunk chunk)
|
||||
{
|
||||
/// Poll background tasks.
|
||||
if (pool)
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
while (true)
|
||||
{
|
||||
/// If some row groups are ready to be written to the file, write them.
|
||||
reapCompletedRowGroups(lock);
|
||||
|
||||
if (background_exception)
|
||||
std::rethrow_exception(background_exception);
|
||||
|
||||
if (is_stopped)
|
||||
return;
|
||||
|
||||
/// If there's too much work in flight, wait for some of it to complete.
|
||||
if (row_groups.size() < 2)
|
||||
break;
|
||||
if (bytes_in_flight <= format_settings.parquet.row_group_bytes * 4 &&
|
||||
task_queue.size() <= format_settings.max_threads * 4)
|
||||
break;
|
||||
|
||||
condvar.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/// Do something like SquashingTransform to produce big enough row groups.
|
||||
/// Because the real SquashingTransform is only used for INSERT, not for SELECT ... INTO OUTFILE.
|
||||
/// The latter doesn't even have a pipeline where a transform could be inserted, so it's more
|
||||
/// convenient to do the squashing here. It's also parallelized here.
|
||||
|
||||
if (chunk.getNumRows() != 0)
|
||||
{
|
||||
staging_rows += chunk.getNumRows();
|
||||
staging_bytes += chunk.bytes();
|
||||
staging_chunks.push_back(std::move(chunk));
|
||||
}
|
||||
|
||||
const size_t target_rows = std::max(static_cast<UInt64>(1), format_settings.parquet.row_group_rows);
|
||||
|
||||
if (staging_rows < target_rows &&
|
||||
staging_bytes < format_settings.parquet.row_group_bytes)
|
||||
return;
|
||||
|
||||
/// In the rare case that more than `row_group_rows` rows arrived in one chunk, split the
|
||||
/// staging chunk into multiple row groups.
|
||||
if (staging_rows >= target_rows * 2)
|
||||
{
|
||||
/// Increase row group size slightly (by < 2x) to avoid a small row group at the end.
|
||||
size_t num_row_groups = std::max(static_cast<size_t>(1), staging_rows / target_rows);
|
||||
size_t row_group_size = (staging_rows - 1) / num_row_groups + 1; // round up
|
||||
|
||||
Chunk concatenated = std::move(staging_chunks[0]);
|
||||
for (size_t i = 1; i < staging_chunks.size(); ++i)
|
||||
concatenated.append(staging_chunks[i]);
|
||||
staging_chunks.clear();
|
||||
|
||||
for (size_t offset = 0; offset < staging_rows; offset += row_group_size)
|
||||
{
|
||||
size_t count = std::min(row_group_size, staging_rows - offset);
|
||||
MutableColumns columns = concatenated.cloneEmptyColumns();
|
||||
for (size_t i = 0; i < columns.size(); ++i)
|
||||
columns[i]->insertRangeFrom(*concatenated.getColumns()[i], offset, count);
|
||||
|
||||
Chunks piece;
|
||||
piece.emplace_back(std::move(columns), count, concatenated.getChunkInfo());
|
||||
writeRowGroup(std::move(piece));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeRowGroup(std::move(staging_chunks));
|
||||
}
|
||||
|
||||
staging_chunks.clear();
|
||||
staging_rows = 0;
|
||||
staging_bytes = 0;
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::finalizeImpl()
|
||||
{
|
||||
if (!staging_chunks.empty())
|
||||
writeRowGroup(std::move(staging_chunks));
|
||||
|
||||
if (format_settings.parquet.use_custom_encoder)
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
|
||||
/// Wait for background work to complete.
|
||||
while (true)
|
||||
{
|
||||
reapCompletedRowGroups(lock);
|
||||
|
||||
if (background_exception)
|
||||
std::rethrow_exception(background_exception);
|
||||
|
||||
if (is_stopped)
|
||||
return;
|
||||
|
||||
if (row_groups.empty())
|
||||
break;
|
||||
|
||||
condvar.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (row_groups_complete.empty())
|
||||
{
|
||||
base_offset = out.count();
|
||||
writeFileHeader(out);
|
||||
}
|
||||
writeFileFooter(std::move(row_groups_complete), schema, options, out);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!file_writer)
|
||||
{
|
||||
Block header = materializeBlock(getPort(PortKind::Main).getHeader());
|
||||
std::vector<Chunk> chunks;
|
||||
chunks.push_back(Chunk(header.getColumns(), 0));
|
||||
writeRowGroup(std::move(chunks));
|
||||
}
|
||||
|
||||
if (file_writer)
|
||||
{
|
||||
auto status = file_writer->Close();
|
||||
if (!status.ok())
|
||||
throw Exception(ErrorCodes::UNKNOWN_EXCEPTION, "Error while closing a table: {}", status.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::resetFormatterImpl()
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
is_stopped = true;
|
||||
pool->wait();
|
||||
is_stopped = false;
|
||||
}
|
||||
|
||||
background_exception = nullptr;
|
||||
threads_running = 0;
|
||||
task_queue.clear();
|
||||
row_groups.clear();
|
||||
file_writer.reset();
|
||||
row_groups_complete.clear();
|
||||
staging_chunks.clear();
|
||||
staging_rows = 0;
|
||||
staging_bytes = 0;
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::onCancel()
|
||||
{
|
||||
is_stopped = true;
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::writeRowGroup(std::vector<Chunk> chunks)
|
||||
{
|
||||
if (pool)
|
||||
writeRowGroupInParallel(std::move(chunks));
|
||||
else if (!format_settings.parquet.use_custom_encoder)
|
||||
writeUsingArrow(std::move(chunks));
|
||||
else
|
||||
{
|
||||
Chunk concatenated = std::move(chunks[0]);
|
||||
for (size_t i = 1; i < chunks.size(); ++i)
|
||||
concatenated.append(chunks[i]);
|
||||
chunks.clear();
|
||||
|
||||
writeRowGroupInOneThread(std::move(concatenated));
|
||||
}
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::writeUsingArrow(std::vector<Chunk> chunks)
|
||||
{
|
||||
const size_t columns_num = chunks.at(0).getNumColumns();
|
||||
std::shared_ptr<arrow::Table> arrow_table;
|
||||
|
||||
if (!ch_column_to_arrow_column)
|
||||
@ -85,7 +304,7 @@ void ParquetBlockOutputFormat::consumeStaged()
|
||||
format_settings.parquet.output_fixed_string_as_fixed_byte_array);
|
||||
}
|
||||
|
||||
ch_column_to_arrow_column->chChunkToArrowTable(arrow_table, staging_chunks, columns_num);
|
||||
ch_column_to_arrow_column->chChunkToArrowTable(arrow_table, chunks, columns_num);
|
||||
|
||||
if (!file_writer)
|
||||
{
|
||||
@ -112,64 +331,234 @@ void ParquetBlockOutputFormat::consumeStaged()
|
||||
file_writer = std::move(result.ValueOrDie());
|
||||
}
|
||||
|
||||
// TODO: calculate row_group_size depending on a number of rows and table size
|
||||
|
||||
// allow slightly bigger than row_group_size to avoid a very small tail row group
|
||||
auto status = file_writer->WriteTable(*arrow_table, std::max<size_t>(format_settings.parquet.row_group_rows, staging_rows));
|
||||
auto status = file_writer->WriteTable(*arrow_table, INT64_MAX);
|
||||
|
||||
if (!status.ok())
|
||||
throw Exception(ErrorCodes::UNKNOWN_EXCEPTION, "Error while writing a table: {}", status.ToString());
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::consume(Chunk chunk)
|
||||
void ParquetBlockOutputFormat::writeRowGroupInOneThread(Chunk chunk)
|
||||
{
|
||||
/// Do something like SquashingTransform to produce big enough row groups.
|
||||
/// Because the real SquashingTransform is only used for INSERT, not for SELECT ... INTO OUTFILE.
|
||||
/// The latter doesn't even have a pipeline where a transform could be inserted, so it's more
|
||||
/// convenient to do the squashing here.
|
||||
staging_rows += chunk.getNumRows();
|
||||
staging_bytes += chunk.bytes();
|
||||
staging_chunks.push_back(std::move(chunk));
|
||||
chassert(staging_chunks.back().getNumColumns() == staging_chunks.front().getNumColumns());
|
||||
if (staging_rows < format_settings.parquet.row_group_rows &&
|
||||
staging_bytes < format_settings.parquet.row_group_bytes)
|
||||
{
|
||||
if (chunk.getNumRows() == 0)
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
const Block & header = getPort(PortKind::Main).getHeader();
|
||||
Parquet::ColumnChunkWriteStates columns_to_write;
|
||||
chassert(header.columns() == chunk.getNumColumns());
|
||||
for (size_t i = 0; i < header.columns(); ++i)
|
||||
prepareColumnForWrite(
|
||||
chunk.getColumns()[i], header.getByPosition(i).type, header.getByPosition(i).name,
|
||||
options, &columns_to_write);
|
||||
|
||||
if (row_groups_complete.empty())
|
||||
{
|
||||
consumeStaged();
|
||||
staging_chunks.clear();
|
||||
staging_rows = 0;
|
||||
staging_bytes = 0;
|
||||
base_offset = out.count();
|
||||
writeFileHeader(out);
|
||||
}
|
||||
|
||||
std::vector<parquet::format::ColumnChunk> column_chunks;
|
||||
for (auto & s : columns_to_write)
|
||||
{
|
||||
size_t offset = out.count() - base_offset;
|
||||
writeColumnChunkBody(s, options, out);
|
||||
auto c = finalizeColumnChunkAndWriteFooter(offset, std::move(s), options, out);
|
||||
column_chunks.push_back(std::move(c));
|
||||
}
|
||||
|
||||
auto r = makeRowGroup(std::move(column_chunks), chunk.getNumRows());
|
||||
row_groups_complete.push_back(std::move(r));
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::writeRowGroupInParallel(std::vector<Chunk> chunks)
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
|
||||
const Block & header = getPort(PortKind::Main).getHeader();
|
||||
|
||||
RowGroupState & r = row_groups.emplace_back();
|
||||
r.column_chunks.resize(header.columns());
|
||||
r.tasks_in_flight = r.column_chunks.size();
|
||||
|
||||
std::vector<Columns> columnses;
|
||||
for (auto & chunk : chunks)
|
||||
{
|
||||
chassert(header.columns() == chunk.getNumColumns());
|
||||
r.num_rows += chunk.getNumRows();
|
||||
columnses.push_back(chunk.detachColumns());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < header.columns(); ++i)
|
||||
{
|
||||
Task & t = task_queue.emplace_back(&r, i, this);
|
||||
t.column_type = header.getByPosition(i).type;
|
||||
t.column_name = header.getByPosition(i).name;
|
||||
|
||||
/// Defer concatenating the columns to the threads.
|
||||
size_t bytes = 0;
|
||||
for (size_t j = 0; j < chunks.size(); ++j)
|
||||
{
|
||||
auto & col = columnses[j][i];
|
||||
bytes += col->allocatedBytes();
|
||||
t.column_pieces.push_back(std::move(col));
|
||||
}
|
||||
t.mem.set(bytes);
|
||||
}
|
||||
|
||||
startMoreThreadsIfNeeded(lock);
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::reapCompletedRowGroups(std::unique_lock<std::mutex> & lock)
|
||||
{
|
||||
while (!row_groups.empty() && row_groups.front().tasks_in_flight == 0 && !is_stopped)
|
||||
{
|
||||
RowGroupState & r = row_groups.front();
|
||||
|
||||
/// Write to the file.
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (row_groups_complete.empty())
|
||||
{
|
||||
base_offset = out.count();
|
||||
writeFileHeader(out);
|
||||
}
|
||||
|
||||
std::vector<parquet::format::ColumnChunk> metadata;
|
||||
for (auto & cols : r.column_chunks)
|
||||
{
|
||||
for (ColumnChunk & col : cols)
|
||||
{
|
||||
size_t offset = out.count() - base_offset;
|
||||
|
||||
out.write(col.serialized.data(), col.serialized.size());
|
||||
auto m = finalizeColumnChunkAndWriteFooter(offset, std::move(col.state), options, out);
|
||||
|
||||
metadata.push_back(std::move(m));
|
||||
}
|
||||
}
|
||||
|
||||
row_groups_complete.push_back(makeRowGroup(std::move(metadata), r.num_rows));
|
||||
|
||||
lock.lock();
|
||||
|
||||
row_groups.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::finalizeImpl()
|
||||
void ParquetBlockOutputFormat::startMoreThreadsIfNeeded(const std::unique_lock<std::mutex> &)
|
||||
{
|
||||
if (!file_writer && staging_chunks.empty())
|
||||
/// Speculate that all current are already working on tasks.
|
||||
size_t to_add = std::min(task_queue.size(), format_settings.max_threads - threads_running);
|
||||
for (size_t i = 0; i < to_add; ++i)
|
||||
{
|
||||
Block header = materializeBlock(getPort(PortKind::Main).getHeader());
|
||||
auto job = [this, thread_group = CurrentThread::getGroup()]()
|
||||
{
|
||||
if (thread_group)
|
||||
CurrentThread::attachToGroupIfDetached(thread_group);
|
||||
SCOPE_EXIT_SAFE(if (thread_group) CurrentThread::detachFromGroupIfNotDetached(););
|
||||
|
||||
consume(Chunk(header.getColumns(), 0)); // this will make staging_chunks non-empty
|
||||
try
|
||||
{
|
||||
setThreadName("ParquetEncoder");
|
||||
|
||||
threadFunction();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
background_exception = std::current_exception();
|
||||
condvar.notify_all();
|
||||
--threads_running;
|
||||
}
|
||||
};
|
||||
|
||||
if (threads_running == 0)
|
||||
{
|
||||
/// First thread. We need it to succeed; otherwise we may get stuck.
|
||||
pool->scheduleOrThrowOnError(job);
|
||||
++threads_running;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// More threads. This may be called from inside the thread pool, so avoid waiting;
|
||||
/// otherwise it may deadlock.
|
||||
if (!pool->trySchedule(job))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!staging_chunks.empty())
|
||||
{
|
||||
consumeStaged();
|
||||
staging_chunks.clear();
|
||||
staging_rows = 0;
|
||||
staging_bytes = 0;
|
||||
}
|
||||
|
||||
auto status = file_writer->Close();
|
||||
if (!status.ok())
|
||||
throw Exception(ErrorCodes::UNKNOWN_EXCEPTION, "Error while closing a table: {}", status.ToString());
|
||||
}
|
||||
|
||||
void ParquetBlockOutputFormat::resetFormatterImpl()
|
||||
void ParquetBlockOutputFormat::threadFunction()
|
||||
{
|
||||
file_writer.reset();
|
||||
std::unique_lock lock(mutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (task_queue.empty() || is_stopped)
|
||||
{
|
||||
/// The check and the decrement need to be in the same critical section, to make sure
|
||||
/// we never get stuck with tasks but no threads.
|
||||
--threads_running;
|
||||
return;
|
||||
}
|
||||
|
||||
auto task = std::move(task_queue.front());
|
||||
task_queue.pop_front();
|
||||
|
||||
if (task.column_type)
|
||||
{
|
||||
lock.unlock();
|
||||
|
||||
IColumn::MutablePtr concatenated = IColumn::mutate(std::move(task.column_pieces[0]));
|
||||
for (size_t i = 1; i < task.column_pieces.size(); ++i)
|
||||
{
|
||||
auto & c = task.column_pieces[i];
|
||||
concatenated->insertRangeFrom(*c, 0, c->size());
|
||||
c.reset();
|
||||
}
|
||||
task.column_pieces.clear();
|
||||
|
||||
std::vector<ColumnChunkWriteState> subcolumns;
|
||||
prepareColumnForWrite(
|
||||
std::move(concatenated), task.column_type, task.column_name, options, &subcolumns);
|
||||
|
||||
lock.lock();
|
||||
|
||||
for (size_t i = 0; i < subcolumns.size(); ++i)
|
||||
{
|
||||
task.row_group->column_chunks[task.column_idx].emplace_back(this);
|
||||
task.row_group->tasks_in_flight += 1;
|
||||
|
||||
auto & t = task_queue.emplace_back(task.row_group, task.column_idx, this);
|
||||
t.subcolumn_idx = i;
|
||||
t.state = std::move(subcolumns[i]);
|
||||
t.mem.set(t.state.allocatedBytes());
|
||||
}
|
||||
|
||||
startMoreThreadsIfNeeded(lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
lock.unlock();
|
||||
|
||||
PODArray<char> serialized;
|
||||
{
|
||||
WriteBufferFromVector buf(serialized);
|
||||
writeColumnChunkBody(task.state, options, buf);
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
|
||||
auto & c = task.row_group->column_chunks[task.column_idx][task.subcolumn_idx];
|
||||
c.state = std::move(task.state);
|
||||
c.serialized = std::move(serialized);
|
||||
c.mem.set(c.serialized.size() + c.state.allocatedBytes());
|
||||
}
|
||||
|
||||
--task.row_group->tasks_in_flight;
|
||||
|
||||
condvar.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void registerOutputFormatParquet(FormatFactory & factory)
|
||||
|
@ -2,8 +2,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#if USE_PARQUET
|
||||
# include <Processors/Formats/IOutputFormat.h>
|
||||
# include <Formats/FormatSettings.h>
|
||||
|
||||
#include <Processors/Formats/IOutputFormat.h>
|
||||
#include <Processors/Formats/Impl/Parquet/Write.h>
|
||||
#include <Formats/FormatSettings.h>
|
||||
#include <Common/ThreadPool.h>
|
||||
|
||||
namespace arrow
|
||||
{
|
||||
@ -28,25 +31,129 @@ class ParquetBlockOutputFormat : public IOutputFormat
|
||||
{
|
||||
public:
|
||||
ParquetBlockOutputFormat(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings_);
|
||||
~ParquetBlockOutputFormat() override;
|
||||
|
||||
String getName() const override { return "ParquetBlockOutputFormat"; }
|
||||
|
||||
String getContentType() const override { return "application/octet-stream"; }
|
||||
|
||||
private:
|
||||
void consumeStaged();
|
||||
struct MemoryToken
|
||||
{
|
||||
ParquetBlockOutputFormat * parent;
|
||||
size_t bytes = 0;
|
||||
|
||||
explicit MemoryToken(ParquetBlockOutputFormat * p, size_t b = 0) : parent(p)
|
||||
{
|
||||
set(b);
|
||||
}
|
||||
|
||||
MemoryToken(MemoryToken && t)
|
||||
: parent(std::exchange(t.parent, nullptr)), bytes(std::exchange(t.bytes, 0)) {}
|
||||
|
||||
MemoryToken & operator=(MemoryToken && t)
|
||||
{
|
||||
parent = std::exchange(t.parent, nullptr);
|
||||
bytes = std::exchange(t.bytes, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~MemoryToken()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
void set(size_t new_size)
|
||||
{
|
||||
if (new_size == bytes)
|
||||
return;
|
||||
parent->bytes_in_flight += new_size - bytes; // overflow is fine
|
||||
bytes = new_size;
|
||||
}
|
||||
};
|
||||
|
||||
struct ColumnChunk
|
||||
{
|
||||
Parquet::ColumnChunkWriteState state;
|
||||
PODArray<char> serialized;
|
||||
|
||||
MemoryToken mem;
|
||||
|
||||
ColumnChunk(ParquetBlockOutputFormat * p) : mem(p) {}
|
||||
};
|
||||
|
||||
struct RowGroupState
|
||||
{
|
||||
size_t tasks_in_flight = 0;
|
||||
std::vector<std::vector<ColumnChunk>> column_chunks;
|
||||
size_t num_rows = 0;
|
||||
};
|
||||
|
||||
struct Task
|
||||
{
|
||||
RowGroupState * row_group;
|
||||
size_t column_idx;
|
||||
size_t subcolumn_idx = 0;
|
||||
|
||||
MemoryToken mem;
|
||||
|
||||
/// If not null, we need to call prepareColumnForWrite().
|
||||
/// Otherwise we need to call writeColumnChunkBody().
|
||||
DataTypePtr column_type;
|
||||
std::string column_name;
|
||||
std::vector<ColumnPtr> column_pieces;
|
||||
|
||||
Parquet::ColumnChunkWriteState state;
|
||||
|
||||
Task(RowGroupState * rg, size_t ci, ParquetBlockOutputFormat * p)
|
||||
: row_group(rg), column_idx(ci), mem(p) {}
|
||||
};
|
||||
|
||||
void consume(Chunk) override;
|
||||
void finalizeImpl() override;
|
||||
void resetFormatterImpl() override;
|
||||
void onCancel() override;
|
||||
|
||||
void writeRowGroup(std::vector<Chunk> chunks);
|
||||
void writeUsingArrow(std::vector<Chunk> chunks);
|
||||
void writeRowGroupInOneThread(Chunk chunk);
|
||||
void writeRowGroupInParallel(std::vector<Chunk> chunks);
|
||||
|
||||
void threadFunction();
|
||||
void startMoreThreadsIfNeeded(const std::unique_lock<std::mutex> & lock);
|
||||
|
||||
/// Called in single-threaded fashion. Writes to the file.
|
||||
void reapCompletedRowGroups(std::unique_lock<std::mutex> & lock);
|
||||
|
||||
const FormatSettings format_settings;
|
||||
|
||||
/// Chunks to squash together to form a row group.
|
||||
std::vector<Chunk> staging_chunks;
|
||||
size_t staging_rows = 0;
|
||||
size_t staging_bytes = 0;
|
||||
|
||||
const FormatSettings format_settings;
|
||||
|
||||
std::unique_ptr<parquet::arrow::FileWriter> file_writer;
|
||||
std::unique_ptr<CHColumnToArrowColumn> ch_column_to_arrow_column;
|
||||
|
||||
Parquet::WriteOptions options;
|
||||
Parquet::SchemaElements schema;
|
||||
std::vector<parquet::format::RowGroup> row_groups_complete;
|
||||
size_t base_offset = 0;
|
||||
|
||||
|
||||
std::mutex mutex;
|
||||
std::condition_variable condvar; // wakes up consume()
|
||||
std::unique_ptr<ThreadPool> pool;
|
||||
|
||||
std::atomic_bool is_stopped{false};
|
||||
std::exception_ptr background_exception = nullptr;
|
||||
|
||||
/// Invariant: if there's at least one task then there's at least one thread.
|
||||
size_t threads_running = 0;
|
||||
std::atomic<size_t> bytes_in_flight{0};
|
||||
|
||||
std::deque<Task> task_queue;
|
||||
std::deque<RowGroupState> row_groups;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ public:
|
||||
|
||||
struct PathWithInfo
|
||||
{
|
||||
PathWithInfo() = default;
|
||||
PathWithInfo(const String & path_, const std::optional<PathInfo> & info_) : path(path_), info(info_) {}
|
||||
String path;
|
||||
std::optional<PathInfo> info;
|
||||
};
|
||||
|
@ -243,6 +243,15 @@ void GinIndexStore::finalize()
|
||||
{
|
||||
if (!current_postings.empty())
|
||||
writeSegment();
|
||||
|
||||
if (metadata_file_stream)
|
||||
metadata_file_stream->finalize();
|
||||
|
||||
if (dict_file_stream)
|
||||
dict_file_stream->finalize();
|
||||
|
||||
if (postings_file_stream)
|
||||
postings_file_stream->finalize();
|
||||
}
|
||||
|
||||
void GinIndexStore::initFileStreams()
|
||||
@ -319,13 +328,8 @@ void GinIndexStore::writeSegment()
|
||||
current_segment.segment_id = getNextSegmentID();
|
||||
|
||||
metadata_file_stream->sync();
|
||||
metadata_file_stream->finalize();
|
||||
|
||||
dict_file_stream->sync();
|
||||
dict_file_stream->finalize();
|
||||
|
||||
postings_file_stream->sync();
|
||||
postings_file_stream->finalize();
|
||||
}
|
||||
|
||||
GinIndexStoreDeserializer::GinIndexStoreDeserializer(const GinIndexStorePtr & store_)
|
||||
|
@ -10,9 +10,16 @@
|
||||
#include <Disks/WriteMode.h>
|
||||
#include <Disks/IDisk.h>
|
||||
|
||||
#include <Common/Exception.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ABORTED;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@ -231,6 +238,11 @@ std::pair<MergeTreePartInfo, bool> MergeTreeDeduplicationLog::addPart(const std:
|
||||
return std::make_pair(info, false);
|
||||
}
|
||||
|
||||
if (stopped)
|
||||
{
|
||||
throw Exception(ErrorCodes::ABORTED, "Storage has been shutdown when we add this part.");
|
||||
}
|
||||
|
||||
chassert(current_writer != nullptr);
|
||||
|
||||
/// Create new record
|
||||
@ -261,6 +273,11 @@ void MergeTreeDeduplicationLog::dropPart(const MergeTreePartInfo & drop_part_inf
|
||||
if (deduplication_window == 0)
|
||||
return;
|
||||
|
||||
if (stopped)
|
||||
{
|
||||
throw Exception(ErrorCodes::ABORTED, "Storage has been shutdown when we drop this part.");
|
||||
}
|
||||
|
||||
chassert(current_writer != nullptr);
|
||||
|
||||
for (auto itr = deduplication_map.begin(); itr != deduplication_map.end(); /* no increment here, we erasing from map */)
|
||||
|
@ -328,7 +328,10 @@ MergeTreePrefetchedReadPool::PartsInfos MergeTreePrefetchedReadPool::getPartsInf
|
||||
for (const auto & range : part.ranges)
|
||||
part_info->sum_marks += range.end - range.begin;
|
||||
|
||||
part_info->approx_size_of_mark = getApproximateSizeOfGranule(*part_info->data_part, column_names);
|
||||
const auto & columns = settings.merge_tree_determine_task_size_by_prewhere_columns && prewhere_info
|
||||
? prewhere_info->prewhere_actions->getRequiredColumnsNames()
|
||||
: column_names;
|
||||
part_info->approx_size_of_mark = getApproximateSizeOfGranule(*part_info->data_part, columns);
|
||||
|
||||
const auto task_columns = getReadTaskColumns(
|
||||
part_reader_info,
|
||||
@ -369,9 +372,9 @@ MergeTreePrefetchedReadPool::PartsInfos MergeTreePrefetchedReadPool::getPartsInf
|
||||
}
|
||||
if (prewhere_info)
|
||||
{
|
||||
for (const auto & columns : task_columns.pre_columns)
|
||||
for (const auto & cols : task_columns.pre_columns)
|
||||
{
|
||||
for (const auto & col : columns)
|
||||
for (const auto & col : cols)
|
||||
{
|
||||
const size_t col_size = part.data_part->getColumnSize(col.name).data_compressed;
|
||||
part_info->estimated_memory_usage_for_single_prefetch += std::min<size_t>(col_size, settings.prefetch_buffer_size);
|
||||
|
@ -73,8 +73,10 @@ MergeTreeReadPool::MergeTreeReadPool(
|
||||
size_t total_marks = 0;
|
||||
for (const auto & part : parts_ranges)
|
||||
{
|
||||
total_compressed_bytes += getApproxSizeOfPart(
|
||||
*part.data_part, prewhere_info ? prewhere_info->prewhere_actions->getRequiredColumnsNames() : column_names_);
|
||||
const auto & columns = settings.merge_tree_determine_task_size_by_prewhere_columns && prewhere_info
|
||||
? prewhere_info->prewhere_actions->getRequiredColumnsNames()
|
||||
: column_names_;
|
||||
total_compressed_bytes += getApproxSizeOfPart(*part.data_part, columns);
|
||||
total_marks += part.getMarksCount();
|
||||
}
|
||||
|
||||
|
@ -1803,7 +1803,7 @@ std::map<int64_t, MutationCommands> ReplicatedMergeTreeQueue::getAlterMutationCo
|
||||
|
||||
Int64 part_data_version = part->info.getDataVersion();
|
||||
Int64 part_metadata_version = part->getMetadataVersion();
|
||||
LOG_DEBUG(log, "Looking for mutations for part {} (part data version {}, part metadata version {})", part->name, part_data_version, part_metadata_version);
|
||||
LOG_TEST(log, "Looking for mutations for part {} (part data version {}, part metadata version {})", part->name, part_data_version, part_metadata_version);
|
||||
|
||||
std::map<int64_t, MutationCommands> result;
|
||||
/// Here we return mutation commands for part which has bigger alter version than part metadata version.
|
||||
|
@ -156,7 +156,7 @@ public:
|
||||
void checkTableCanBeDropped() const override {}
|
||||
|
||||
private:
|
||||
mutable std::mutex nested_mutex;
|
||||
mutable std::recursive_mutex nested_mutex;
|
||||
mutable GetNestedStorageFunc get_nested;
|
||||
mutable StoragePtr nested;
|
||||
const bool add_conversion;
|
||||
|
@ -42,10 +42,12 @@ const char * auto_contributors[] {
|
||||
"Alex",
|
||||
"Alex Bocharov",
|
||||
"Alex Cao",
|
||||
"Alex Cheng",
|
||||
"Alex Karo",
|
||||
"Alex Krash",
|
||||
"Alex Ryndin",
|
||||
"Alex Zatelepin",
|
||||
"AlexBykovski",
|
||||
"Alexander Avdonkin",
|
||||
"Alexander Bezpiatov",
|
||||
"Alexander Burmak",
|
||||
@ -232,6 +234,7 @@ const char * auto_contributors[] {
|
||||
"CheSema",
|
||||
"Chebarykov Pavel",
|
||||
"Chen Yufei",
|
||||
"Chen768959",
|
||||
"Cheng Pan",
|
||||
"Chienlung Cheung",
|
||||
"Christian",
|
||||
@ -485,6 +488,7 @@ const char * auto_contributors[] {
|
||||
"John",
|
||||
"John Hummel",
|
||||
"John Skopis",
|
||||
"John Spurlock",
|
||||
"Jonatas Freitas",
|
||||
"Jonathan-Ackerman",
|
||||
"Jordi",
|
||||
@ -659,6 +663,7 @@ const char * auto_contributors[] {
|
||||
"Mikhail Gaidamaka",
|
||||
"Mikhail Guzov",
|
||||
"Mikhail Korotov",
|
||||
"Mikhail Koviazin",
|
||||
"Mikhail Malafeev",
|
||||
"Mikhail Nacharov",
|
||||
"Mikhail Salosin",
|
||||
@ -815,6 +820,7 @@ const char * auto_contributors[] {
|
||||
"Roman Vasin",
|
||||
"Roman Vlasenko",
|
||||
"Roman Zhukov",
|
||||
"Rory Crispin",
|
||||
"Roy Bellingan",
|
||||
"Ruslan",
|
||||
"Ruslan Savchenko",
|
||||
@ -832,7 +838,9 @@ const char * auto_contributors[] {
|
||||
"Salvatore Mesoraca",
|
||||
"Sami Kerola",
|
||||
"Samuel Chou",
|
||||
"Samuel Colvin",
|
||||
"San",
|
||||
"Sanjam Panda",
|
||||
"Saulius Valatka",
|
||||
"Sean Haynes",
|
||||
"Sean Lafferty",
|
||||
@ -883,6 +891,7 @@ const char * auto_contributors[] {
|
||||
"SmitaRKulkarni",
|
||||
"Snow",
|
||||
"Sofia Antipushina",
|
||||
"Song Liyong",
|
||||
"Sorck",
|
||||
"Stanislav Dobrovolschii",
|
||||
"Stanislav Pavlovichev",
|
||||
@ -893,6 +902,7 @@ const char * auto_contributors[] {
|
||||
"Stepan Herold",
|
||||
"Stephan",
|
||||
"Steve-金勇",
|
||||
"StianBerger",
|
||||
"Stig Bakken",
|
||||
"Storozhuk Kostiantyn",
|
||||
"Stupnikov Andrey",
|
||||
@ -977,6 +987,7 @@ const char * auto_contributors[] {
|
||||
"Vitaliy Karnienko",
|
||||
"Vitaliy Kozlovskiy",
|
||||
"Vitaliy Lyudvichenko",
|
||||
"Vitaliy Pashkov",
|
||||
"Vitaliy Zakaznikov",
|
||||
"Vitaly",
|
||||
"Vitaly Artemyev",
|
||||
@ -1029,6 +1040,7 @@ const char * auto_contributors[] {
|
||||
"Yakov Olkhovskiy",
|
||||
"YalalovSM",
|
||||
"Yangkuan Liu",
|
||||
"Yarik Briukhovetskyi",
|
||||
"Yatian Xu",
|
||||
"Yatsishin Ilya",
|
||||
"Yağızcan Değirmenci",
|
||||
@ -1053,6 +1065,7 @@ const char * auto_contributors[] {
|
||||
"Yury Karpovich",
|
||||
"Yury Stankevich",
|
||||
"Yusuke Tanaka",
|
||||
"Zach Naimon",
|
||||
"ZhiYong Wang",
|
||||
"Zhichang Yu",
|
||||
"Zhichun Wu",
|
||||
@ -1143,6 +1156,7 @@ const char * auto_contributors[] {
|
||||
"changvvb",
|
||||
"chasingegg",
|
||||
"chen",
|
||||
"chen768959",
|
||||
"chen9t",
|
||||
"chengy8934",
|
||||
"chenjian",
|
||||
@ -1179,6 +1193,7 @@ const char * auto_contributors[] {
|
||||
"detailyang",
|
||||
"dfenelonov",
|
||||
"dgrr",
|
||||
"dheerajathrey",
|
||||
"dimarub2000",
|
||||
"dinosaur",
|
||||
"divanorama",
|
||||
@ -1329,6 +1344,7 @@ const char * auto_contributors[] {
|
||||
"lanfz",
|
||||
"larryluogit",
|
||||
"laurieliyang",
|
||||
"lcjh",
|
||||
"lehasm",
|
||||
"leosunli",
|
||||
"leozhang",
|
||||
@ -1455,6 +1471,7 @@ const char * auto_contributors[] {
|
||||
"pawelsz-rb",
|
||||
"pdai",
|
||||
"pdv-ru",
|
||||
"pedro.riera",
|
||||
"pengxiangcai",
|
||||
"peshkurov",
|
||||
"peter279k",
|
||||
@ -1548,8 +1565,10 @@ const char * auto_contributors[] {
|
||||
"teng.ma",
|
||||
"terrylin",
|
||||
"tesw yew isal",
|
||||
"therealnick233",
|
||||
"tianzhou",
|
||||
"tiger.yan",
|
||||
"timfursov",
|
||||
"tison",
|
||||
"topvisor",
|
||||
"tpanetti",
|
||||
@ -1563,6 +1582,7 @@ const char * auto_contributors[] {
|
||||
"usurai",
|
||||
"vahid-sohrabloo",
|
||||
"vdimir",
|
||||
"velavokr",
|
||||
"velom",
|
||||
"vesslanjin",
|
||||
"vgocoder",
|
||||
@ -1587,17 +1607,21 @@ const char * auto_contributors[] {
|
||||
"wuxiaobai24",
|
||||
"wzl",
|
||||
"xPoSx",
|
||||
"xiao",
|
||||
"xiaolei565",
|
||||
"xiedeyantu",
|
||||
"xieyichen",
|
||||
"xinhuitian",
|
||||
"xlwh",
|
||||
"xmy",
|
||||
"xuelei",
|
||||
"yakkomajuri",
|
||||
"yakov-olkhovskiy",
|
||||
"yandd",
|
||||
"yang",
|
||||
"yangshuai",
|
||||
"yaqi-zhao",
|
||||
"yariks5s",
|
||||
"yeer",
|
||||
"ygrek",
|
||||
"yhgcn",
|
||||
|
@ -128,6 +128,7 @@
|
||||
02581_share_big_sets_between_mutation_tasks_long
|
||||
02581_share_big_sets_between_multiple_mutations_tasks_long
|
||||
00992_system_parts_race_condition_zookeeper_long
|
||||
02818_parameterized_view_with_cte_multiple_usage
|
||||
02790_optimize_skip_unused_shards_join
|
||||
01940_custom_tld_sharding_key
|
||||
02815_range_dict_no_direct_join
|
||||
|
4
tests/performance/prepare_hash_before_merge.xml
Normal file
4
tests/performance/prepare_hash_before_merge.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<test>
|
||||
<query>SELECT COUNT(DISTINCT Title) FROM test.hits SETTINGS max_threads = 24</query>
|
||||
<query>SELECT COUNT(DISTINCT Referer) FROM test.hits SETTINGS max_threads = 22</query>
|
||||
</test>
|
@ -9,7 +9,7 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
${CLICKHOUSE_CLIENT} --multiquery --query "DROP TABLE IF EXISTS t; CREATE TABLE t (x UInt64) ENGINE = Memory;"
|
||||
|
||||
# Rate limit is chosen for operation to spent more than one second.
|
||||
seq 1 1000 | pv --quiet --rate-limit 1000 | ${CLICKHOUSE_CLIENT} --query "INSERT INTO t FORMAT TSV"
|
||||
seq 1 1000 | pv --quiet --rate-limit 500 | ${CLICKHOUSE_CLIENT} --query "INSERT INTO t FORMAT TSV"
|
||||
|
||||
# We check that the value of NetworkReceiveElapsedMicroseconds correctly includes the time spent waiting data from the client.
|
||||
${CLICKHOUSE_CLIENT} --multiquery --query "SYSTEM FLUSH LOGS;
|
||||
|
@ -0,0 +1,12 @@
|
||||
-- Run a query with query cache not enabled
|
||||
124437993
|
||||
QueryFinish SELECT 124437993; None
|
||||
-- Run a query with query cache enabled
|
||||
124437994
|
||||
QueryFinish SELECT 124437994 SETTINGS use_query_cache = 1; Write
|
||||
-- Run the same query with query cache enabled
|
||||
124437994
|
||||
QueryFinish SELECT 124437994 SETTINGS use_query_cache = 1; Write
|
||||
QueryFinish SELECT 124437994 SETTINGS use_query_cache = 1; Read
|
||||
-- Throw exception with query cache enabled
|
||||
SELECT 124437995, throwIf(1) SETTINGS use_query_cache = 1; None
|
67
tests/queries/0_stateless/02494_query_cache_query_log.sql
Normal file
67
tests/queries/0_stateless/02494_query_cache_query_log.sql
Normal file
@ -0,0 +1,67 @@
|
||||
-- Tags: no-parallel
|
||||
-- Tag no-parallel: Messes with internal cache
|
||||
|
||||
SYSTEM DROP QUERY CACHE;
|
||||
|
||||
-- DROP TABLE system.query_log; -- debugging
|
||||
|
||||
|
||||
|
||||
SELECT '-- Run a query with query cache not enabled';
|
||||
SELECT 124437993;
|
||||
|
||||
SYSTEM FLUSH LOGS;
|
||||
|
||||
-- Field 'query_cache_usage' should be 'None'
|
||||
SELECT type, query, query_cache_usage
|
||||
FROM system.query_log
|
||||
WHERE current_database = currentDatabase()
|
||||
AND query = 'SELECT 124437993;'
|
||||
AND type = 'QueryFinish'
|
||||
ORDER BY type, query_cache_usage;
|
||||
|
||||
|
||||
|
||||
SELECT '-- Run a query with query cache enabled';
|
||||
SELECT 124437994 SETTINGS use_query_cache = 1;
|
||||
|
||||
SYSTEM FLUSH LOGS;
|
||||
|
||||
-- Field 'query_cache_usage' should be 'Write'
|
||||
SELECT type, query, query_cache_usage
|
||||
FROM system.query_log
|
||||
WHERE current_database = currentDatabase()
|
||||
AND query = 'SELECT 124437994 SETTINGS use_query_cache = 1;'
|
||||
AND type = 'QueryFinish'
|
||||
ORDER BY type, query_cache_usage;
|
||||
|
||||
|
||||
|
||||
SELECT '-- Run the same query with query cache enabled';
|
||||
SELECT 124437994 SETTINGS use_query_cache = 1;
|
||||
|
||||
SYSTEM FLUSH LOGS;
|
||||
|
||||
-- Field 'query_cache_usage' should be 'Read'
|
||||
SELECT type, query, query_cache_usage
|
||||
FROM system.query_log
|
||||
WHERE current_database = currentDatabase()
|
||||
AND query = 'SELECT 124437994 SETTINGS use_query_cache = 1;'
|
||||
AND type = 'QueryFinish'
|
||||
ORDER BY type, query_cache_usage;
|
||||
|
||||
|
||||
|
||||
SELECT '-- Throw exception with query cache enabled';
|
||||
SELECT 124437995, throwIf(1) SETTINGS use_query_cache = 1; -- { serverError FUNCTION_THROW_IF_VALUE_IS_NON_ZERO }
|
||||
|
||||
SYSTEM FLUSH LOGS;
|
||||
|
||||
-- Field 'query_cache_usage' should be 'None'
|
||||
SELECT query, query_cache_usage
|
||||
FROM system.query_log
|
||||
WHERE current_database = currentDatabase()
|
||||
AND query = 'SELECT 124437995, throwIf(1) SETTINGS use_query_cache = 1;'
|
||||
AND type = 'ExceptionWhileProcessing';
|
||||
|
||||
SYSTEM DROP QUERY CACHE;
|
@ -5,6 +5,8 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=../shell_config.sh
|
||||
. "$CURDIR"/../shell_config.sh
|
||||
|
||||
set -o pipefail
|
||||
|
||||
$CLICKHOUSE_LOCAL -q "select * from numbers(10) format Parquet settings output_format_parquet_compression_method='none'" | $CLICKHOUSE_LOCAL --input-format=Parquet -q "select count() from table"
|
||||
$CLICKHOUSE_LOCAL -q "select * from numbers(10) format Parquet settings output_format_parquet_compression_method='lz4'" | $CLICKHOUSE_LOCAL --input-format=Parquet -q "select count() from table"
|
||||
$CLICKHOUSE_LOCAL -q "select * from numbers(10) format Parquet settings output_format_parquet_compression_method='snappy'" | $CLICKHOUSE_LOCAL --input-format=Parquet -q "select count() from table"
|
||||
|
21
tests/queries/0_stateless/02676_to_decimal_string.reference
Normal file
21
tests/queries/0_stateless/02676_to_decimal_string.reference
Normal file
@ -0,0 +1,21 @@
|
||||
2.00000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
2.12
|
||||
-2.00000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
-2.12
|
||||
2.987600000000000033395508580724708735942840576171875000000000
|
||||
2.15
|
||||
-2.987600000000000033395508580724708735942840576171875000000000
|
||||
-2.15
|
||||
64.1230010986
|
||||
64.2340000000
|
||||
-64.1230010986
|
||||
-64.2340000000
|
||||
-32.345
|
||||
32.34500000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
32.46
|
||||
-64.5671232345
|
||||
128.78932312332132985464
|
||||
-128.78932312332132985464
|
||||
128.78932312332132985464000000000000000000000000000000000000000000000000000000000
|
||||
128.7893231233
|
||||
-128.78932312332132985464123123789323123321329854600000000000000000000000000000000
|
41
tests/queries/0_stateless/02676_to_decimal_string.sql
Normal file
41
tests/queries/0_stateless/02676_to_decimal_string.sql
Normal file
@ -0,0 +1,41 @@
|
||||
-- Regular types
|
||||
SELECT toDecimalString(2, 77); -- more digits required than exist
|
||||
SELECT toDecimalString(2.123456, 2); -- rounding
|
||||
SELECT toDecimalString(-2, 77); -- more digits required than exist
|
||||
SELECT toDecimalString(-2.123456, 2); -- rounding
|
||||
|
||||
SELECT toDecimalString(2.9876, 60); -- more digits required than exist (took 60 as it is float by default)
|
||||
SELECT toDecimalString(2.1456, 2); -- rounding
|
||||
SELECT toDecimalString(-2.9876, 60); -- more digits required than exist
|
||||
SELECT toDecimalString(-2.1456, 2); -- rounding
|
||||
|
||||
-- Float32 and Float64 tests. No sense to test big float precision -- the result will be a mess anyway.
|
||||
SELECT toDecimalString(64.123::Float32, 10);
|
||||
SELECT toDecimalString(64.234::Float64, 10);
|
||||
SELECT toDecimalString(-64.123::Float32, 10);
|
||||
SELECT toDecimalString(-64.234::Float64, 10);
|
||||
|
||||
-- Decimals
|
||||
SELECT toDecimalString(-32.345::Decimal32(3), 3);
|
||||
SELECT toDecimalString(32.345::Decimal32(3), 77); -- more digits required than exist
|
||||
SELECT toDecimalString(32.456::Decimal32(3), 2); -- rounding
|
||||
SELECT toDecimalString('-64.5671232345'::Decimal64(10), 10);
|
||||
SELECT toDecimalString('128.78932312332132985464'::Decimal128(20), 20);
|
||||
SELECT toDecimalString('-128.78932312332132985464123123'::Decimal128(26), 20); -- rounding
|
||||
SELECT toDecimalString('128.78932312332132985464'::Decimal128(20), 77); -- more digits required than exist
|
||||
SELECT toDecimalString('128.789323123321329854641231237893231233213298546'::Decimal256(45), 10); -- rounding
|
||||
SELECT toDecimalString('-128.789323123321329854641231237893231233213298546'::Decimal256(45), 77); -- more digits required than exist
|
||||
|
||||
-- Max number of decimal fractional digits is defined as 77 for Int/UInt/Decimal and 60 for Float.
|
||||
-- These values shall work OK.
|
||||
SELECT toDecimalString('32.32'::Float32, 61); -- {serverError CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER}
|
||||
SELECT toDecimalString('64.64'::Float64, 61); -- {serverError CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER}
|
||||
SELECT toDecimalString('88'::UInt8, 78); -- {serverError CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER}
|
||||
SELECT toDecimalString('646464'::Int256, 78); -- {serverError CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER}
|
||||
SELECT toDecimalString('-128.789323123321329854641231237893231233213298546'::Decimal256(45), 78); -- {serverError CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER}
|
||||
|
||||
-- wrong types: #52407 and similar
|
||||
SELECT toDecimalString('256.256'::Decimal256(45), *); -- {serverError ILLEGAL_COLUMN}
|
||||
SELECT toDecimalString('128.128'::Decimal128(30), 'str'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||
SELECT toDecimalString('64.64'::Decimal64(10)); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||
SELECT toDecimalString('64.64'::Decimal64(10), 3, 3); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
55
tests/queries/0_stateless/02735_parquet_encoder.reference
Normal file
55
tests/queries/0_stateless/02735_parquet_encoder.reference
Normal file
@ -0,0 +1,55 @@
|
||||
u8 Nullable(UInt8)
|
||||
u16 Nullable(UInt16)
|
||||
u32 Nullable(UInt32)
|
||||
u64 Nullable(UInt64)
|
||||
i8 Nullable(Int8)
|
||||
i16 Nullable(Int16)
|
||||
i32 Nullable(Int32)
|
||||
i64 Nullable(Int64)
|
||||
date Nullable(UInt16)
|
||||
date32 Nullable(Date32)
|
||||
datetime Nullable(UInt32)
|
||||
datetime64 Nullable(DateTime64(3, \'UTC\'))
|
||||
enum8 Nullable(Int8)
|
||||
enum16 Nullable(Int16)
|
||||
float32 Nullable(Float32)
|
||||
float64 Nullable(Float64)
|
||||
str Nullable(String)
|
||||
fstr Nullable(FixedString(12))
|
||||
u128 Nullable(FixedString(16))
|
||||
u256 Nullable(FixedString(32))
|
||||
i128 Nullable(FixedString(16))
|
||||
i256 Nullable(FixedString(32))
|
||||
decimal32 Nullable(Decimal(9, 3))
|
||||
decimal64 Nullable(Decimal(18, 10))
|
||||
decimal128 Nullable(Decimal(38, 20))
|
||||
decimal256 Nullable(Decimal(76, 40))
|
||||
ipv4 Nullable(UInt32)
|
||||
ipv6 Nullable(FixedString(16))
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
1 2 1
|
||||
1 2 2
|
||||
1 3 3
|
||||
1 1000000 1
|
||||
3914219105369203805
|
||||
4 1000000 1
|
||||
(1000000,0,NULL,'100','299')
|
||||
(1000000,0,NULL,'0','-1294970296')
|
||||
(1000000,0,NULL,'-2147483296','2147481000')
|
||||
(100000,900000,NULL,'100009','999999')
|
||||
[(2,0,NULL,'','[]')]
|
||||
1 1
|
||||
0 1
|
||||
16159458007063698496
|
||||
16159458007063698496
|
||||
BYTE_ARRAY String
|
||||
FIXED_LEN_BYTE_ARRAY None
|
||||
BYTE_ARRAY None
|
||||
BYTE_ARRAY None
|
||||
BYTE_ARRAY String
|
||||
never gonna
|
||||
give you
|
||||
up
|
168
tests/queries/0_stateless/02735_parquet_encoder.sql
Normal file
168
tests/queries/0_stateless/02735_parquet_encoder.sql
Normal file
@ -0,0 +1,168 @@
|
||||
-- Tags: no-fasttest, no-parallel
|
||||
|
||||
set output_format_parquet_use_custom_encoder = 1;
|
||||
set output_format_parquet_row_group_size = 1000;
|
||||
set output_format_parquet_data_page_size = 800;
|
||||
set output_format_parquet_batch_size = 100;
|
||||
set output_format_parquet_row_group_size_bytes = 1000000000;
|
||||
set engine_file_truncate_on_insert=1;
|
||||
|
||||
-- Write random data to parquet file, then read from it and check that it matches what we wrote.
|
||||
-- Do this for all kinds of data types: primitive, Nullable(primitive), Array(primitive),
|
||||
-- Array(Nullable(primitive)), Array(Array(primitive)), Map(primitive, primitive), etc.
|
||||
|
||||
drop table if exists basic_types_02735;
|
||||
create temporary table basic_types_02735 as select * from generateRandom('
|
||||
u8 UInt8,
|
||||
u16 UInt16,
|
||||
u32 UInt32,
|
||||
u64 UInt64,
|
||||
i8 Int8,
|
||||
i16 Int16,
|
||||
i32 Int32,
|
||||
i64 Int64,
|
||||
date Date,
|
||||
date32 Date32,
|
||||
datetime DateTime,
|
||||
datetime64 DateTime64,
|
||||
enum8 Enum8(''x'' = 1, ''y'' = 2, ''z'' = 3),
|
||||
enum16 Enum16(''xx'' = 1000, ''yy'' = 2000, ''zz'' = 3000),
|
||||
float32 Float32,
|
||||
float64 Float64,
|
||||
str String,
|
||||
fstr FixedString(12),
|
||||
u128 UInt128,
|
||||
u256 UInt256,
|
||||
i128 Int128,
|
||||
i256 Int256,
|
||||
decimal32 Decimal32(3),
|
||||
decimal64 Decimal64(10),
|
||||
decimal128 Decimal128(20),
|
||||
decimal256 Decimal256(40),
|
||||
ipv4 IPv4,
|
||||
ipv6 IPv6') limit 10101;
|
||||
insert into function file(basic_types_02735.parquet) select * from basic_types_02735;
|
||||
desc file(basic_types_02735.parquet);
|
||||
select (select sum(cityHash64(*)) from basic_types_02735) - (select sum(cityHash64(*)) from file(basic_types_02735.parquet));
|
||||
drop table basic_types_02735;
|
||||
|
||||
|
||||
drop table if exists nullables_02735;
|
||||
create temporary table nullables_02735 as select * from generateRandom('
|
||||
u16 Nullable(UInt16),
|
||||
i64 Nullable(Int64),
|
||||
datetime64 Nullable(DateTime64),
|
||||
enum8 Nullable(Enum8(''x'' = 1, ''y'' = 2, ''z'' = 3)),
|
||||
float64 Nullable(Float64),
|
||||
str Nullable(String),
|
||||
fstr Nullable(FixedString(12)),
|
||||
i256 Nullable(Int256),
|
||||
decimal256 Nullable(Decimal256(40)),
|
||||
ipv6 Nullable(IPv6)') limit 10000;
|
||||
insert into function file(nullables_02735.parquet) select * from nullables_02735;
|
||||
select (select sum(cityHash64(*)) from nullables_02735) - (select sum(cityHash64(*)) from file(nullables_02735.parquet));
|
||||
drop table nullables_02735;
|
||||
|
||||
|
||||
-- TODO: When cityHash64() fully supports Nullable: https://github.com/ClickHouse/ClickHouse/pull/48625
|
||||
-- the next two blocks can be simplified: arrays_out_02735 intermediate table is not needed,
|
||||
-- a.csv and b.csv are not needed.
|
||||
|
||||
drop table if exists arrays_02735;
|
||||
drop table if exists arrays_out_02735;
|
||||
create table arrays_02735 engine = Memory as select * from generateRandom('
|
||||
u32 Array(UInt32),
|
||||
i8 Array(Int8),
|
||||
datetime Array(DateTime),
|
||||
enum16 Array(Enum16(''xx'' = 1000, ''yy'' = 2000, ''zz'' = 3000)),
|
||||
float32 Array(Float32),
|
||||
str Array(String),
|
||||
fstr Array(FixedString(12)),
|
||||
u128 Array(UInt128),
|
||||
decimal64 Array(Decimal64(10)),
|
||||
ipv4 Array(IPv4),
|
||||
msi Map(String, Int16),
|
||||
tup Tuple(FixedString(3), Array(String), Map(Int8, Date))') limit 10000;
|
||||
insert into function file(arrays_02735.parquet) select * from arrays_02735;
|
||||
create temporary table arrays_out_02735 as arrays_02735;
|
||||
insert into arrays_out_02735 select * from file(arrays_02735.parquet);
|
||||
select (select sum(cityHash64(*)) from arrays_02735) - (select sum(cityHash64(*)) from arrays_out_02735);
|
||||
--select (select sum(cityHash64(*)) from arrays_02735) -
|
||||
-- (select sum(cityHash64(u32, i8, datetime, enum16, float32, str, fstr, arrayMap(x->reinterpret(x, 'UInt128'), u128), decimal64, ipv4, msi, tup)) from file(arrays_02735.parquet));
|
||||
drop table arrays_02735;
|
||||
drop table arrays_out_02735;
|
||||
|
||||
|
||||
drop table if exists madness_02735;
|
||||
create temporary table madness_02735 as select * from generateRandom('
|
||||
aa Array(Array(UInt32)),
|
||||
aaa Array(Array(Array(UInt32))),
|
||||
an Array(Nullable(String)),
|
||||
aan Array(Array(Nullable(FixedString(10)))),
|
||||
l LowCardinality(String),
|
||||
ln LowCardinality(Nullable(FixedString(11))),
|
||||
al Array(LowCardinality(UInt128)),
|
||||
aaln Array(Array(LowCardinality(Nullable(String)))),
|
||||
mln Map(LowCardinality(String), Nullable(Int8)),
|
||||
t Tuple(Map(FixedString(5), Tuple(Array(UInt16), Nullable(UInt16), Array(Tuple(Int8, Decimal64(10))))), Tuple(kitchen UInt64, sink String)),
|
||||
n Nested(hello UInt64, world Tuple(first String, second FixedString(1)))
|
||||
') limit 10000;
|
||||
insert into function file(madness_02735.parquet) select * from madness_02735;
|
||||
insert into function file(a.csv) select * from madness_02735 order by tuple(*);
|
||||
insert into function file(b.csv) select aa, aaa, an, aan, l, ln, arrayMap(x->reinterpret(x, 'UInt128'), al) as al_, aaln, mln, t, n.hello, n.world from file(madness_02735.parquet) order by tuple(aa, aaa, an, aan, l, ln, al_, aaln, mln, t, n.hello, n.world);
|
||||
select (select sum(cityHash64(*)) from file(a.csv, LineAsString)) - (select sum(cityHash64(*)) from file(b.csv, LineAsString));
|
||||
--select (select sum(cityHash64(*)) from madness_02735) -
|
||||
-- (select sum(cityHash64(aa, aaa, an, aan, l, ln, map(x->reinterpret(x, 'UInt128'), al), aaln, mln, t, n.hello, n.world)) from file(madness_02735.parquet));
|
||||
drop table madness_02735;
|
||||
|
||||
|
||||
-- Merging input blocks into bigger row groups.
|
||||
insert into function file(squash_02735.parquet) select '012345' union all select '543210' settings max_block_size = 1;
|
||||
select num_columns, num_rows, num_row_groups from file(squash_02735.parquet, ParquetMetadata);
|
||||
|
||||
-- Row group size limit in bytes.
|
||||
insert into function file(row_group_bytes_02735.parquet) select '012345' union all select '543210' settings max_block_size = 1, output_format_parquet_row_group_size_bytes = 5;
|
||||
select num_columns, num_rows, num_row_groups from file(row_group_bytes_02735.parquet, ParquetMetadata);
|
||||
|
||||
-- Row group size limit in rows.
|
||||
insert into function file(tiny_row_groups_02735.parquet) select * from numbers(3) settings output_format_parquet_row_group_size = 1;
|
||||
select num_columns, num_rows, num_row_groups from file(tiny_row_groups_02735.parquet, ParquetMetadata);
|
||||
|
||||
-- 1M unique 8-byte values should exceed dictionary_size_limit (1 MB).
|
||||
insert into function file(big_column_chunk_02735.parquet) select number from numbers(1000000) settings output_format_parquet_row_group_size = 1000000;
|
||||
select num_columns, num_rows, num_row_groups from file(big_column_chunk_02735.parquet, ParquetMetadata);
|
||||
select sum(cityHash64(number)) from file(big_column_chunk_02735.parquet);
|
||||
|
||||
-- Check statistics: signed vs unsigned, null count. Use enough rows to produce multiple pages.
|
||||
insert into function file(statistics_02735.parquet) select 100 + number%200 as a, toUInt32(number * 3000) as u, toInt32(number * 3000) as i, if(number % 10 == 9, toString(number), null) as s from numbers(1000000) settings output_format_parquet_row_group_size = 1000000;
|
||||
select num_columns, num_rows, num_row_groups from file(statistics_02735.parquet, ParquetMetadata);
|
||||
select tupleElement(c, 'statistics') from file(statistics_02735.parquet, ParquetMetadata) array join tupleElement(row_groups[1], 'columns') as c;
|
||||
|
||||
-- Statistics string length limit (max_statistics_size).
|
||||
insert into function file(long_string_02735.parquet) select toString(range(number * 2000)) from numbers(2);
|
||||
select tupleElement(tupleElement(row_groups[1], 'columns'), 'statistics') from file(long_string_02735.parquet, ParquetMetadata);
|
||||
|
||||
-- Compression setting.
|
||||
insert into function file(compressed_02735.parquet) select concat('aaaaaaaaaaaaaaaa', toString(number)) as s from numbers(1000) settings output_format_parquet_row_group_size = 10000, output_format_parquet_compression_method='zstd';
|
||||
select total_compressed_size < 10000, total_uncompressed_size > 15000 from file(compressed_02735.parquet, ParquetMetadata);
|
||||
insert into function file(compressed_02735.parquet) select concat('aaaaaaaaaaaaaaaa', toString(number)) as s from numbers(1000) settings output_format_parquet_row_group_size = 10000, output_format_parquet_compression_method='none';
|
||||
select total_compressed_size < 10000, total_uncompressed_size > 15000 from file(compressed_02735.parquet, ParquetMetadata);
|
||||
|
||||
-- Single-threaded encoding and Arrow encoder.
|
||||
drop table if exists other_encoders_02735;
|
||||
create temporary table other_encoders_02735 as select number, number*2 from numbers(10000);
|
||||
insert into function file(single_thread_02735.parquet) select * from other_encoders_02735 settings max_threads = 1;
|
||||
select sum(cityHash64(*)) from file(single_thread_02735.parquet);
|
||||
insert into function file(arrow_02735.parquet) select * from other_encoders_02735 settings output_format_parquet_use_custom_encoder = 0;
|
||||
select sum(cityHash64(*)) from file(arrow_02735.parquet);
|
||||
|
||||
-- String -> binary vs string; FixedString -> fixed-length-binary vs binary vs string.
|
||||
insert into function file(strings1_02735.parquet) select 'never', toFixedString('gonna', 5) settings output_format_parquet_string_as_string = 1, output_format_parquet_fixed_string_as_fixed_byte_array = 1;
|
||||
select columns.5, columns.6 from file(strings1_02735.parquet, ParquetMetadata) array join columns;
|
||||
insert into function file(strings2_02735.parquet) select 'give', toFixedString('you', 3) settings output_format_parquet_string_as_string = 0, output_format_parquet_fixed_string_as_fixed_byte_array = 0;
|
||||
select columns.5, columns.6 from file(strings2_02735.parquet, ParquetMetadata) array join columns;
|
||||
insert into function file(strings3_02735.parquet) select toFixedString('up', 2) settings output_format_parquet_string_as_string = 1, output_format_parquet_fixed_string_as_fixed_byte_array = 0;
|
||||
select columns.5, columns.6 from file(strings3_02735.parquet, ParquetMetadata) array join columns;
|
||||
select * from file(strings1_02735.parquet);
|
||||
select * from file(strings2_02735.parquet);
|
||||
select * from file(strings3_02735.parquet);
|
@ -0,0 +1,2 @@
|
||||
('::2.2.2.2','2.2.2.2')
|
||||
('::1.1.1.1','1.1.1.1')
|
13
tests/queries/0_stateless/02811_ip_dict_attribute.sql
Normal file
13
tests/queries/0_stateless/02811_ip_dict_attribute.sql
Normal file
@ -0,0 +1,13 @@
|
||||
CREATE TABLE src ( id UInt64, ip4 IPv4, ip6 IPv6 ) Engine=Memory AS
|
||||
SELECT * FROM VALUES( (1, '1.1.1.1', '::1.1.1.1'), (2, '2.2.2.2', '::2.2.2.2') );
|
||||
|
||||
CREATE DICTIONARY dict ( id UInt64, ip4 IPv4, ip6 IPv6 )
|
||||
PRIMARY KEY id
|
||||
LAYOUT(HASHED())
|
||||
SOURCE (CLICKHOUSE ( table src))
|
||||
lifetime ( 10);
|
||||
|
||||
SELECT dictGet('dict', ('ip6', 'ip4'), arrayJoin([2,1]));
|
||||
|
||||
DROP DICTIONARY dict;
|
||||
DROP TABLE src;
|
@ -0,0 +1,2 @@
|
||||
3 2
|
||||
3 2 3
|
@ -0,0 +1,16 @@
|
||||
create view test_param_view as
|
||||
with {param_test_val:UInt8} as param_test_val
|
||||
select param_test_val,
|
||||
arrayCount((a)->(a < param_test_val), t.arr) as cnt1
|
||||
from (select [1,2,3,4,5] as arr) t;
|
||||
|
||||
select * from test_param_view(param_test_val = 3);
|
||||
|
||||
create view test_param_view2 as
|
||||
with {param_test_val:UInt8} as param_test_val
|
||||
select param_test_val,
|
||||
arrayCount((a)->(a < param_test_val), t.arr) as cnt1,
|
||||
arrayCount((a)->(a < param_test_val+1), t.arr) as cnt2
|
||||
from (select [1,2,3,4,5] as arr) t;
|
||||
|
||||
select * from test_param_view2(param_test_val = 3);
|
@ -0,0 +1 @@
|
||||
0
|
@ -0,0 +1,7 @@
|
||||
|
||||
drop table if exists t1;
|
||||
create table t1 as remote('localhost', 'system.one');
|
||||
rename table t1 to t2;
|
||||
select * from t2;
|
||||
rename table t2 to t1;
|
||||
drop table t1;
|
@ -1,3 +1,4 @@
|
||||
v23.7.1.2470-stable 2023-07-27
|
||||
v23.6.2.18-stable 2023-07-09
|
||||
v23.6.1.1524-stable 2023-06-30
|
||||
v23.5.4.25-stable 2023-06-29
|
||||
|
|
Loading…
Reference in New Issue
Block a user