ClickHouse release 26.10, 2026-10-22
Backward Incompatible Change
- The query analysis that preceded the analyzer is removed. It has not been selectable since 26.9, when
enable_analyzerbecame obsolete; now a server no longer uses it for a query another server sends either, so a cluster whose initiator is older than 26.10 gets the analyzer on this server regardless of what the initiator asks for. Such a mixed cluster can seeNOT_FOUND_COLUMN_IN_BLOCKon the old initiator, because the two analyses name the result columns differently; setenable_analyzer = 1on every server before upgrading any of them. Theuse_analyzer_for_mutationsserver setting is removed, andparallel_replicas_only_with_analyzeris obsolete. #120311 (Alexey Milovidov). - The predicate push-down that the query analysis preceding the analyzer performed on the AST is removed, and
enable_optimize_predicate_expressionis now obsolete and has no effect. Push-down of a predicate into a subquery is performed by the analyzer as a query plan optimization and is not affected; push-down into a distributed subquery still happens on the AST level and is controlled byallow_push_predicate_ast_for_distributed_subqueries. The visible difference is thatEXPLAIN SYNTAXof a query that is not aSELECT, for exampleEXPLAIN SYNTAX INSERT INTO ... SELECT ..., no longer prints a predicate copied into a subquery, a non-aggregateHAVINGconjunct moved toWHERE, or the right-hand table of aJOINwrapped into a subquery. #121465 (Alexey Milovidov). system.metric_lognow uses thebucketedschema by default: all profile events and current metrics are stored in a singlemetricscolumn of typeMap(Enum16(...), Int64)with the bucketedMapserialization and a constant number of 128 buckets, so the table has a few columns instead of thousands, zero values are not stored, and reading one metric reads only one of the 128 buckets. Every metric is also exposed as anALIAScolumn, so queries such asSELECT ProfileEvent_Query FROM system.metric_logcontinue to work unchanged. On upgrade the existing table is renamed tometric_log_0, as with any other change of the structure of a system log table, and the built-in dashboards readmerge('system', '^metric_log'), so they keep showing the data collected before the upgrade. Add<schema_type>wide</schema_type>to the<metric_log>section of the server configuration to keep the previous schema. #118318 (Alexey Milovidov). #124016 (Raúl Marín).clickhouse-servercan now apply aseccompsystem call filter at startup. Theseccompsetting controls refused system calls:logonly records them, whiletrap,kill, anderrnoenforce the policy;disabledinstalls no filter. Theconfig.xmlshipped with the server packages and the Docker image now setsseccomptotrap, so a server that runs in a sandbox which refuses theseccompsystem call must switch it tologordisabledbefore the upgrade. Extended-attribute probes used by some hostname-resolution libraries are rejected withENOSYSinstead of the configured seccomp action, so server startup still succeeds under the defaulttrapmode. You might need to disable seccomp when using executable user-defined functions. #119545 (Alexey Milovidov). #122577 (Alexey Milovidov). #124856 (Azat Khuzhin).- Settings constraints and
allow_feature_tierare now enforced for users, roles and settings profiles defined by SQL. A statement is refused if it changes a restricted setting of some user indirectly (such asGRANT,DROP ROLE,DROP SETTINGS PROFILEorCREATE USER OR REPLACE), sets a value outside its author’s constraints, or removes a setting its author is constrained on. A user defined by SQL whose stored settings, roles or assigned settings profiles violate the constraints orallow_feature_tiercan no longer log in. Thecompatibilitysetting no longer applies values that settings constraints orallow_feature_tierrefuse; such settings keep their current value. Login checks use the user’s resolved constraints, preserving bounds inherited from the default profile. Closes #124966. #119472 (Raúl Marín). #125582 (Raúl Marín). - Overriding a key that is stored in a named collection now requires
SHOW NAMED COLLECTIONS SECRETSon that collection. This also applies to overrides through an alias (including flatkafka_*settings over nestedkafka.*keys), through aSETTINGSclause of a table engine or table function, and through keys in a dictionary source (checked when the dictionary is created). Resolving a relativeurlstored in a named collection againsts3_baseorurl_basealso counts as an override ofurl. Adding a key that the collection does not store remains allowed, and keys markedNOT OVERRIDABLEcannot be overridden. Theallow_named_collection_override_by_defaultsetting is obsolete. Existing tables whoseSETTINGSor alias arguments override aNOT OVERRIDABLEkey cannot be loaded after the upgrade, and the server does not start: before upgrading, recreate such tables without the override, or make the key overridable. #123133 (Nikita Mikhaylov). max_bytes_before_external_joinandmax_bytes_ratio_before_external_joinare now the spill threshold for every hash-basedjoin_algorithm, includinggrace_hash, which previously ignored them and spilled onmax_rows_in_join/max_bytes_in_joininstead. Those two settings are a hard cap again for every algorithm: they no longer cause spilling, and a join that spills no longer exceeds them. All join algorithms remain available;join_algorithm = 'grace_hash'now needs a non-zero spill threshold, and is skipped in favour of the next algorithm in the list when it has none. Setlegacy_join_size_limits_trigger_spilling = 1(orcompatibilityto 26.8 or older) to restore the previous behavior. #117356 (Yarik Briukhovetskyi). #119335 (Alexey Milovidov).arrayCountnow returnsUInt64instead ofUInt32, so it stays exact for arrays with more than 4294967295 matching elements. Setarray_count_legacy_uint32_result = 1(orcompatibility = '26.9') to restore the previous result type. During a rolling upgrade, enablearray_count_legacy_uint32_resulton upgraded servers for the users under which shard-side queries execute, so distributed queries initiated by not-yet-upgraded servers keep the previous behavior on upgraded shards; remove it after the upgrade is complete. In addition,length(arrayFilter(func, arr))is now rewritten toarrayCount(func, arr), which is up to 1.29x faster on long arrays, controlled byoptimize_rewrite_array_filter_length_to_array_count. #113023 (Alexey Milovidov).accurateCastfromStringorFixedStringto aNullabletarget now throws the error its non-Nullabletarget already raised (CANNOT_PARSE_TEXT,TOO_LARGE_STRING_SIZE, …) instead of returningNULL, and no longer throws for a row the source markedNULL. This affects every use ofaccurateCast:DeltaLakewrites stop committing an unrepresentable value asNULL,dictGetOrDefaultrejects a default itsNullableattribute cannot hold and now converts only the defaults it uses,INundertransform_null_in = 1no longer matches an unparsable key against aNULLin the set, andcast_ipv4_ipv6_default_on_conversion_erroryields the type’s default for an unparsable address.CAST,accurateCastOrNull,accurateCastOrDefault, and ordinaryINSERTare unchanged, as is what a non-text source does with a value it cannot represent; useaccurateCastOrNullfor the previous behavior. Closes #120524. #120674 (Groene AI).SELECT ... FINALfromSummingMergeTreeno longer removes the rows whose summed columns are all zero, unlike background merges. Before, this removal looked only at the columns the query read, so results depended on them: for example,SELECT count() FROM table FINALcould return fewer rows thanSELECT * FROM table FINAL. Background merges andOPTIMIZE TABLE ... FINALstill remove such rows, so filter out the all-zero rows explicitly if a query relied on their removal. #115032 (Alexey Milovidov).- A read of a
DistributedorRemotetable withskip_unavailable_shards = 1now fails withALL_CONNECTION_TRIES_FAILEDwhen every shard was skipped before returning any data, instead of returning an empty result, matching what already happens when the only shard is local. Previously an aggregate withoutGROUP BYsilently returned zero rows instead of one. The error fails the whole query, so a query that combines such a read with other data, for example aUNION ALLwith local rows, no longer returns those rows. When a shard is itself aDistributedtable whose shards were all skipped, the outer query now fails even if another shard answered;skip_unavailable_shards_mode = 'unavailable_or_exception_before_processing'keeps the partial result in that case. No setting restores the previous empty result. Closes #115646. #115775 (Groene AI). - A
MATERIALIZEDcolumn computed from a column with aTTLis now recomputed when theTTLresets that column, both during a merge and inALTER TABLE ... MATERIALIZE TTL. Previously it kept the pre-expiry value forever. If the dependent expression is not defined on the expired column’s default (for exampleintDiv(100, x)whenxexpires to0), theTTLmerge now throws instead of writing the stale value; make the expression total on the default (intDivOrZero,if(x = 0, ...)) if such a table must keep merging. Closes #117310. #117815 (Alexey Milovidov). - With
input_format_null_as_default = 0, a JSONnullfor a non-Nullablenumeric column now raises an exception instead of being silently stored as0(ornan), consistent with other types and formats. Keepinput_format_null_as_defaultat its default1to insert the column default instead. #122137 (Alexey Milovidov). ALTER TABLE ... ADD COLUMNandMODIFY COLUMNnow apply thedata_type_default_nullablesetting the same wayCREATE TABLEdoes: with the setting enabled, a column type written without an explicitNULLorNOT NULLmodifier becomesNullable, so the rows that existed beforeADD COLUMNreadNULL,ADD COLUMN x Int32 DEFAULT NULLis accepted, andMODIFY COLUMN x Int64keeps aNullablecolumnNullableinstead of failing. As inCREATE TABLE, anArray,Map,LowCardinality, or another type that cannot be insideNullablethen requiresNOT NULL, and so does aMODIFY COLUMNof a sorting key column. To keep the previous result of such anALTER, writeNOT NULLexplicitly or run it withdata_type_default_nullable = 0. Closes #124504. #124597 (Groene AI).arrayJoinis now lowered to anARRAY JOINstep by default (settingquery_plan_lower_array_join_function). The expansion streams through the pipeline instead of being materialized inside the projection, filters on the joined elements are applied before the rows are multiplied, and queries with severalarrayJoincalls no longer build the whole cross product in memory. As a consequence, a non-deterministic function such asrandorgenerateUUIDv4next toarrayJoinin the sameSELECTis now evaluated once per output row, as with theARRAY JOINclause, instead of once per source row. Setarrayjoin_nondeterministic_functions_before_expansion = 1(orcompatibilityto 26.9 or older) to keep the previous behavior. #117882 (Yarik Briukhovetskyi). #120390 (Yarik Briukhovetskyi). #122240 (Yarik Briukhovetskyi).- A function that depends on blocks or row order, such as
runningDifference,neighbororrowNumberInBlock, next to thearrayJoinfunction now sees the blocks of the expansion, like with theARRAY JOINclause. Setlegacy_array_join_function_nondeterministic_evaluation = 1to get the previous behavior. #123143 (Yarik Briukhovetskyi). - A row policy on a
Distributedtable (or another table that processes the query itself) read through aMergetable now makes queries to theMergetable fail withILLEGAL_PREWHEREfor the users the policy applies to, like queries to that table itself. Before, theMergetable applied such a policy after the table had already sorted, limited and computedextremes, so queries could return wrong rows and show values of hidden rows inextremes. Define the row policy on the underlying tables of the remote servers and on the local child tables instead. This also fixesNOT_FOUND_COLUMN_IN_BLOCKon every query over aMergetable whose child has a row policy when theMergetable also reads aDistributedtable. #125765 (Groene AI). clickhouse-local --ignore-errornow reports a statement that failed at execution instead of skipping it silently: previously it printed no message and no exception code, so a failing multi-statement script looked exactly like a passing one, whileclickhouse-client --ignore-errorreported every error all along.clickhouse-clientalso ignored the option entirely when it was combined with--interactiveand--query/--queries-fileon a terminal, and now applies it to those queries too. The exit code ofclickhouse-client --ignore-errorchanges accordingly: it used to be the code of whichever error the last statement of the batch happened to hit, which made the result depend on the position of the failing statement rather than on the batch as a whole, and it is now a success code, matching whatclickhouse-local --ignore-errorhas always returned. Scripts that relied on the old exit code to detect failures should drop--ignore-errorso that the run stops and fails at the first error, or check the reported errors onstderr. #119572 (Yakov Olkhovskiy).ATTACH TABLE ... FROM '<path>'now requiresREAD ON FILEandWRITE ON FILEon the source directory inuser_files, in addition toCREATE TABLE, because the query reads the directory and then moves it out ofuser_fileson success. Previously a user could attach and read staged data without thoseFILEgrants. Grant the correspondingFILEprivileges to users that rely on this form. #120582 (Alexander Gololobov).- A
MySQLdictionary source created with aCREATE DICTIONARYquery can no longer enableenable_local_infile, at the source or at one of itsREPLICAentries; loading such a dictionary fails withBAD_ARGUMENTS, which with the defaultdictionaries_lazy_loadis on first use rather than atCREATE. AREPLICAthat does not set the key inherits the source’s value, as the connection pool does. To keep the option, define the dictionary in a server configuration file;enable_local_infile = 0, and aSOURCE(MYSQL(NAME ...))reference to a named collection where the key was never read, are unaffected. #120972 (Groene AI). - The definitions of disks in
storage_configurationand indiskare validated: an element that nothing reads is reported asUNKNOWN_ELEMENT_IN_CONFIGinstead of being silently ignored, which finds typos and options that do not exist for this disk type, such aspathin anS3disk. If a server does not start after the upgrade because of an element it does not know, remove that element from the configuration, or set<skip_check_for_incorrect_settings>1</skip_check_for_incorrect_settings>. #118440 (Alexey Milovidov). system.*_logtables can now be configured uniformly viasystem_tables.*. Insystem.opentelemetry_span_log,finish_dateis renamed toevent_dateand kept as an alias. Aliases are now supported in configuredPARTITION BY,ORDER BY,TTL,PRIMARY KEY, andSAMPLE BYexpressions, so custom definitions can continue to usefinish_date. Some tables now fall back to the default TTL when none is configured, so setttlexplicitly if that matters. #121563 (Azat Khuzhin). #125564 (Azat Khuzhin).- The setting
validate_mutation_queryis deprecated and ignored: mutation queries (ALTER TABLE ... UPDATE,ALTER TABLE ... DELETE,DELETE FROM) are now always validated before being accepted. It was enabled by default since 24.11, and disabling it did not avoid the failure but only deferred it to the background, where the mutation got stuck and required manual intervention. Setting it to0no longer lets an invalid mutation be accepted: it is rejected when submitted. #121419 (Alexey Milovidov). - Settings
query_plan_read_in_order,query_plan_optimize_prewhere, andquery_plan_aggregation_in_orderare obsolete and no longer have any effect. Useoptimize_read_in_order,optimize_aggregation_in_order, andoptimize_move_to_prewhereinstead. #121390 (Anton Popov). - The setting
use_compact_format_in_distributed_parts_namesis obsolete. The non-compact directory format for the asyncINSERTqueue of aDistributedtable has been removed. The setting was1by default since version 21.1. Before upgrading, set it to1and let the queue drain. #120186 (Alexander Tokmakov). - The
MergeTreesettingsuse_minimalistic_part_header_in_zookeeperanduse_minimalistic_checksums_in_zookeeperare obsolete and have no effect: new data parts ofReplicatedMergeTreetables are always stored in ZooKeeper as a single node with the compact header, the default since 20.1. An explicit0in table metadata or in themerge_treeconfiguration is ignored, and such tables and configurations still load. Part nodes written in the old format by earlier versions are still read. Closes #122744. #122790 (Groene AI). - Settings
s3_max_connectionsand theS3disk’smax_connectionskey are obsolete. They have had no effect since 21.4, when the per-endpoint connection pool of theS3client they bounded was removed, but were still documented as limiting the number of connections per server. Both are still accepted and do nothing. To bound the connections to object storage, use the server settingsdisk_connections_soft_limit,disk_connections_store_limit,disk_connections_warn_limit, anddisk_connections_hard_limitand theirstorage_connections_*andhttp_connections_*counterparts; to bound the request rate, uses3_max_get_rpsands3_max_put_rps. #119550 (Alexey Milovidov). - Removed the zero-argument
yearfunction. Queries that usedyear()must switch totoYear(today())instead. #120268 (Robert Schulze). - Removed the
system.codecs.is_experimentalcolumn. Queries that filtered or selected it should usetier = 'Experimental'instead. #118523 (Raufs Dunamalijevs). - Removed the experimental function
detectTonality. Queries that use it now fail withUNKNOWN_FUNCTION. #123327 (Groene AI). - Update the
zxclibrary to v0.14.0, which changes the compressed block format of the experimentalZXCcodec. Data written withCODEC(ZXC)by earlier versions cannot be read by the new version and fails withCANNOT_DECOMPRESS. If you used the experimentalZXCcodec, re-encode the affected columns to a different codec before upgrading, or re-insert the data after the upgrade. #119097 (Actuele AI). - An aggregate function state that serializes to zero bytes cannot be read back, so the two parameterizations that produced one are now rejected: a
-Resamplecombinator over an empty range (begin >= end, such ascountResample(10, 5, 1)) throwsARGUMENT_OUT_OF_BOUND, andcovarSampMatrix,covarPopMatrix, andcorrMatrixwith no arguments throwNUMBER_OF_ARGUMENTS_DOESNT_MATCH. Both returned an empty array before. No serialized format changes, but a table with such a column no longer loads. Before upgrading, drop the column where the engine supportsDROP COLUMN, and the whole table where it does not (Log,TinyLog,StripeLog,Set,Join,File). #119728 (Groene AI). - A data type naming the state of a function that only works as a window function, such as
AggregateFunction(rank), is now rejected withBAD_ARGUMENTS: such a state has no serialization, so the column could never hold a value. This applies wherever a type is named, including insideArray,Map,Tuple, and another state’s argument list. A table that already stores such a column will no longer attach after the upgrade; drop or rewrite the column before upgrading. #122148 (Groene AI). rankStateand every other-Stateof a function that only works as a window function, such asdenseRankStateIforinitializeAggregation('lagInFrameState', x), are now rejected withBAD_ARGUMENTSwhen the query is analyzed, also where the state is never computed (toTypeName,EXPLAIN, a column the outer query drops), and so is such a type in a binary-encodedNativeheader. Computing such a state always failed, but a view orCREATE TABLE ... AS SELECTcould still store its type. A table whose engine expressions build such a state, for example in a sorting key, partition key, skip index, orTTL, no longer attaches. #122463 (Groene AI).CREATE TABLEand full-definitionATTACH TABLEnow refuse aCONSTRAINTname declared more than once, andALTER TABLE ... ADD CONSTRAINT/MODIFY CONSTRAINTnow refuse an expression containingarrayJoineven when the command would install nothing. A table already stored with a repeated constraint name still attaches and keeps enforcing each of its declarations; give each constraint a unique name in new definitions. #121235 (Groene AI).- The
Remote,RemoteSecure, andClusterdatabase engines now reject an empty remote database name withBAD_ARGUMENTSinstead of creating a database that lists and reads no tables. A server that holds such a database, created by an earlier version, does not start after the upgrade, so drop these databases before upgrading. Closes #122616. #122675 (Groene AI). - Connections to MySQL (the
mysqltable function, theMySQLtable and database engines, andMySQLdictionaries) that setssl_caorssl_ca_pemnow verify the server certificate chain and host name, after updatingmariadb-connector-cto v3.4.10. Previously the CA was not enforced, so a connection to a server whose certificate is signed by another CA, or whose certificate does not list the host name or IP address used to connect, succeeded and now fails withself-signed certificate in certificate chainorHostname verification failed. Before upgrading, make sure the configured CA signs the MySQL server certificate and that the certificate lists the host name or IP address ClickHouse connects to. #119510 (Actuele AI).
New Feature
- Sets built for
INwith a subquery or a table now spill to disk by default once query memory usage exceeds half the available memory under the applicable server or user memory limit, calculated at the start of execution (max_bytes_ratio_before_external_set = 0.5). Themax_bytes_before_external_setsetting can set an absolute threshold (max_memory_usageis not taken into account by the ratio, so use it to spill before that limit is reached), and setting both thresholds to0keeps sets in memory. This feature is now generally available. #123860 (Nihal Z. Miaji). #124907 (Nihal Z. Miaji). - Support parts of the Trino SQL dialect in regular ClickHouse SQL:
TRY_CAST(x AS T), theARRAY[...]array constructor, the type namesARRAY(T)andMAP(K, V), and aliases for Trino functions such asstarts_with,slice,regexp_like,day_of_week,url_extract_host,bitwise_and,arbitrary, andbool_and. #124763 (Alexey Milovidov). - Implemented a generic block nested loop join algorithm.
JOINnow supports an arbitraryONcondition with no equality between the two tables, executing it as a block nested loop join, as slow as aCROSS JOINwith a filter, instead of failing withINVALID_JOIN_ON_EXPRESSION. The new settingallow_block_nested_loop_jointurns it on/off. #123642 (Alexey Milovidov). #123792 (Groene AI). - Added the function-composition operator
f | gand the argument placeholders_,_1,_2, …: for example,arrayMap(plus(_, 1) | multiply(_, 2), [1, 2, 3])returns[4, 6, 8]. A composition can be used wherever a function is expected, including as an argument of a higher-order function. The operands can be lambdas, function names, nested compositions, or expressions with placeholders, which also work on their own, for examplearrayMap(_1 * 2 + 1, [1, 2, 3]). The composition is resolved at query analysis time into an ordinary lambda. Note that|here is not bitwise OR; usebitOrfor that. #116029 (Alexey Milovidov). - The query cache can now store its entries on disk, backed by a preconfigured filesystem cache: this gives the entries more space, makes them survive server restarts, and, with a distributed filesystem cache, provides a way to share them between servers. Select the filesystem cache with the new setting
query_cache_on_disk_cache_name; see also the new settingsquery_cache_on_disk_codec,enable_writes_to_query_cache_on_disk, andenable_reads_from_query_cache_on_disk. Closes #115361. #115382 (Alexey Milovidov). - Added a notebook mode to the Web UI (
/play). After a query is run, a[+]button under the result adds further cells, each either a query with its own result or a block of Markdown text, turning the tab into a notebook in the style of Jupyter or Observable. Cells can be run, reordered, inserted and deleted individually; the query editor collapses to a single line when it is not focused, results are bounded and scroll inside themselves, and the whole notebook is restored on reload. Notebook mode is per tab, so a tab that has only one cell looks and behaves exactly as before. #115378 (Alexey Milovidov). - Added support for reading and writing data in the
SQLiteformat. #104510 (Yue Ni). - Added the
Clusterdatabase engine, which provides real-time access to the tables of a configured cluster database and forwardsSELECTandINSERTqueries to it. #114417 (Alexey Milovidov). - Added the
Overlaydatabase engine:CREATE DATABASE db ENGINE = Overlay(db1, db2, ...)exposes the union of the tables of existing databases, each table working as anAliastable to the table of the first source database that has it. #121878 (Alexey Milovidov). CREATE DATABASEandATTACH DATABASEnow accept aSETTINGSclause without an explicitENGINEclause, defaulting toAtomic, so a database can define its metadata disk inline the same way a single table does. A singleSETTINGSclause can now also mix database-engine settings with ordinary query settings. #118423 (Alexey Milovidov).MergeTreetables inOrdinarydatabases can now be converted toReplicatedMergeTreewithATTACH TABLE ... AS REPLICATEDor theconvert_to_replicatedflag. #118757 (Kirill).- Added query-aware scheduling in workloads: the new workload setting
schedulerselects how queries of a workload are scheduled —fifo(default),fair(weighted fair queueing with per-query weights that can be lowered as a query runs),las(least-attained-service), orpriority(by the query settingworkload_priority). The leaf-nodetypeinsystem.scheduleris nowrequest_queueinstead offifo. #116800 (Sergei Trifonov). - Queries can now spill to disk under memory pressure based on limits set per workload. The
max_memory_before_spillandmax_memory_to_spill_ratiooptions ofWORKLOADdefine a soft memory limit that triggers spilling forORDER BY,GROUP BY,IN,DISTINCT, andJOINwithgrace_hash. #119443 (Azat Khuzhin). - Quotas can now limit the number of rows written by
INSERTqueries with the newwritten_rowsresource, for exampleCREATE QUOTA q KEYED BY ip_address FOR INTERVAL 1 minute MAX written_rows = 100000, query_inserts = 250 TO user. Until now only the written bytes could be limited (written_bytes), which is awkward when the natural unit of the workload is rows. The current and maximum values are exposed aswritten_rowsandmax_written_rowsinsystem.quota_usage,system.quotas_usage, andsystem.quota_limits, and the resource can also be set inusers.xmlas<written_rows>. #118272 (Alexey Milovidov). - Added the settings
max_temporary_tables,max_temporary_table_memory_usage,max_temporary_table_size_bytes_compressed, andmax_temporary_table_size_bytes_uncompressedto limit the number of temporary tables in a session, the memory usage ofMemorytemporary tables, and the size ofMergeTreetemporary tables. #122165 (Alexey Milovidov). - Added the SQL-standard
SIMILAR TOpattern-matching predicate. #101514 (Zhao Zheguang). - Allow
MATERIALIZEDcommon table expressions inside recursiveWITH. A materialized helper CTE is evaluated once and every recursive step reads the snapshot, instead of the subquery being re-evaluated on each iteration. The recursive CTE itself still cannot be materialized. #123452 (Alexey Milovidov). - Query parameters can now be used for primary
USERandROLEnames inCREATE,ALTER, andDROP, and for role and grantee names inGRANTandREVOKE, for exampleGRANT {role:Identifier} TO {user:Identifier}. #109696 (Pervakov Grigorii). SET DEFAULT ROLEnow accepts anON CLUSTERclause, in either position:SET DEFAULT ROLE role1 TO user ON CLUSTER my_clusterandSET DEFAULT ROLE ON CLUSTER my_cluster role1 TO user.CURRENT_USERis resolved on the initiator before the query is distributed.SET ROLEonly affects the current session and still takes noON CLUSTERclause. #118429 (Alexey Milovidov).- Added
CREATE OR REPLACE NAMED COLLECTION ...to replace an existing named collection entirely. #121569 (Pervakov Grigorii). - The
postgresqltable function and thePostgreSQLtable engine can now connect to another ClickHouse server over the PostgreSQL protocol. Thequery(...)variant still needs an explicit column list. Added the PostgreSQL-compatibility functionsformat_typeandcurrent_setting. Also fixed cancellation over the PostgreSQL protocol: a cancel request never cancelled anything. #112940 (Alexey Milovidov). - Disks with the
plain_rewritablemetadata (s3_plain_rewritable, andazure/localobject storages withmetadata_type = plain_rewritable) support hard links if configured with the newenable_hard_linkssetting, which enablesALTERoperations and mutations onMergeTreetables stored on them. Mutations and partition operations share the unchanged blobs between parts instead of copying them. The setting is off by default, because a disk that has hard links cannot be read by older servers. #110939 (yanglongwei). #119304 (Alexey Milovidov). - Added
EXCEPT DATA FROM TABLE/EXCEPT DATA FROM TABLESclauses toBACKUPqueries, so a table’s definition can be backed up without its rows, for any table engine that supports backups. Formatting now quotes keyword table names correctly inEXCEPT DATA FROM TABLES, soBACKUP ... ON CLUSTERround-trips through the formatter. Closes #111827. #111895 (Aditya Kumar). #122468 (David Meng). - Added five columns to
system.query_logdescribing what a query really executed:used_number_of_joins,used_join_algorithms,used_join_kinds,used_join_strictness, andspilled_to_disk. This makes it possible to find problematicJOINpatterns and queries that fall back to external memory across a fleet without reproducing each query. A spillingSELECT DISTINCTnow recordsdistinctinspilled_to_diskinstead of[], and a spilling block nested loop join recordsjoin. #113833 (Matheus Nerone). #121830 (Groene AI). #124681 (David Meng). - Added table function
traceViewthat renders an OpenTelemetry trace fromsystem.opentelemetry_span_logas a call tree with a per-span timeline bar, for debugging where the time of a traced, for example distributed, query was spent. It has ahostcolumn with thehostnameof the server that recorded each span, so the spans of the initiator, remote shards, replicas, and stateless workers can be distinguished and filtered withWHERE host = .... #116325 (Diego Gomes Tomé). #122169 (Diego Gomes Tomé). #123528 (Diego Gomes Tomé). clickhouse-client --logincan now authenticate against arbitrary OAuth/OIDC identity providers via endpoint discovery, with explicit endpoint and scope overrides and improved RFC 8628 device-code handling. On Linux desktops it now also passes the client’s environment toxdg-openwhen opening the identity-provider login page, so the system browser is detected correctly. Closes #120127. #110718 (yanglongwei). #121337 (Konstantin Bogdanov).- Added interactive client commands
/dialect,/lang, and/languagetoclickhouse-clientandclickhouse-local, so you can switch the active SQL dialect before parsing, including when the current dialect cannot express aSETquery, for example to leavekustoorpromql. The current non-default dialect is now shown in the prompt, andSET dialect = ...keeps the prompt in sync. #114568 (Alexey Milovidov). chdigv26.10.1: ZooKeeper browser, per-host summary, and better filters. #124100 (Azat Khuzhin).- Support reading the
ParquetVARIANTtype (unshredded, as written for example by Spark 4.0) intoDynamic, with object values read asJSON. A variant column can also be read directly asJSONif all its values are objects. Shredded variants are not supported yet. #117106 (Konstantin Vedernikov). - Support the
varianttype ofIceberg. Based on theParquetvariant reader in #117106. #117198 (Konstantin Vedernikov). #125458 (Alexey Milovidov). - Support the
ParquetFILElogical type (a reference to bytes stored inline or in an external file): it is read as a namedTuple, and can be written from aTuplewith the corresponding element names with the new settingoutput_format_parquet_write_file_logical_type. #125132 (Alexey Milovidov). - Lazy type hints for the
JSONtype are now generally available under theenable_json_lazy_type_hintssetting. The setting remains disabled by default. #122711 (Pavel Kruglov). - Add a new input format
Freeform, which does schema inference for arbitrary tabular text files. Closes #34006. #43449 (Tri Dao). - The
generateRandomtable function and theGenerateRandomtable engine now supportJSON,Dynamic,Variant,BFloat16,Time, andTime64. GeneratedJSONdocuments have a realistic schema derived from the seed. The new settingsnull_ratio,max_json_depth, andmax_json_keys_per_objectcontrol the share of nulls and absent keys, the nesting depth, and the number of keys per object. Generation respects memory limits.CREATE TABLE ... AS generateRandom(...)also keeps theSETTINGSargument in the stored definition. #107966 (apst41). #124772 (Vadim Lopatin). #123247 (Raúl Marín). - Add the
obfuscatetable function for generating anonymized query results. #115004 (Alexey Milovidov). - Text indexes with the
keyValuePairstokenizer now answermap['key'] IN ('value1', 'value2')directly from the index, as they already did formap['key'] = 'value'. Added the functionmapContainsKeyValue(map, key, value), which returns whether a map contains an entry with the given key and value; in contrast tomap[key] = value, all entries of a repeated key are considered, and such an index evaluates the function directly. ThemergeTreeTextIndextable function returns the decoded parts of each token of such an index in the columnstoken_keyandtoken_value. #120244 (Jimmy Aguilar Mena). #120010 (Jimmy Aguilar Mena). #120183 (Anton Popov). - The
mergeTreeTextIndextable function now returns posting lists and token positions for a text index in the new virtual columnsrow_idandpositions. If one of them is selected, the function returns a row per posting. Thepositionscolumn is available for indexes created withsupport_phrase_search = 1. #125536 (Anton Popov). - Added
mapRemove, which removes all entries with a specified key from a map, andmapEntries, which returns a map’s entries as an array of key-value tuples. #123322 (Minh Vu). #123344 (Minh Vu). - The
-Mapcombinator can now be used with non-Mapcolumns (the key is passed as the last argument, e.g.sumMap(value, key)) and supports aggregate functions with multiple arguments, e.g.argMaxMap(arg, val, key). #123449 (Alexey Milovidov). - The aggregate functions
avg,sum,sumWithOverflow, andsumKahannow support theIntervaldata types. The result is an interval of the same unit. #121458 (Alexey Milovidov). #121600 (Alexey Milovidov). - The linear regression aggregate functions can now also be called under ClickHouse-style names:
regrSlope,regrIntercept,regrR2,regrCount,regrAvgX,regrAvgY,regrSXX,regrSYY, andregrSXY. #119796 (mosya415). - Added the
arrayMinIndexandarrayMaxIndexarray functions. #120097 (Minh Vu). #123686 (Minh Vu). - Added the
arrayRemoveAtarray function. #120445 (Minh Vu). - Added higher-order array functions to pack bits:
arrayPackBitsToUInt64,arrayPackBitsToString,arrayPackBitsToFixedString,arrayPackBitGroupsToUInt64,arrayPackBitGroupsToString, andarrayPackBitGroupsToFixedString. #123478 (Alexey Milovidov). - Added SQL functions
normalizedQueryHashUnorderedandnormalizedQueryHashUnorderedOrNull. UnlikenormalizedQueryHash, they ignore the order of expression lists such as theSELECTlist,GROUP BYkeys, and function arguments, so logically equivalent queries can collapse to one pattern inquery_log; theOrNullvariant returnsNULLinstead of throwing when the input is not valid ClickHouse SQL in the current session. #116345 (Yarik Briukhovetskyi). - Add functions
encodeQuotedPrintableanddecodeQuotedPrintablefor Quoted-Printable encoding (RFC 2045), commonly used in email. #125454 (Jay Pokale). - Added the
sql_compatible_division_for_integerssetting, disabled by default, to make/anddividereturn integer quotients truncated toward zero when both operands are integers. It supports integer types up to 256 bits and checks division by zero and result overflow; division involvingDecimalor floating-point operands is unchanged. #124490 (Ilya Yatsishin). - Added
SYSTEM RESET FILELOG [db.]table [FILE 'file_name' [OFFSET n | TO END]]: aFileLogtable reads all its files again from the beginning, or one file from the beginning, from a given offset, or only from data appended after the command, without recreating the table. Requires the newSYSTEM RESET FILELOGprivilege. #123545 (Groene AI). - The
FileLogtable engine now accepts globs (*,?,{a,b},{N..M}) in the file name of its path, for exampleFileLog('/var/lib/clickhouse/user_files/my_app/*.log', 'JSONEachRow'), and reads only the matching files of that directory, so the compressed fileslogrotateleaves next to the log are not read. A file that is already read keeps being read after it is renamed to a non-matching name, such asapp.logrotated toapp.log.1. #123590 (Groene AI). - Added the
flat_namespacessetting to theDataLakeCatalogdatabase engine. Set it forIcebergREST catalogs that have only single-level namespaces and reject theparentquery parameter of the list-namespaces endpoint, such as Apache Polaris federated to AWS Glue: only top-level namespaces are then listed and sub-namespaces are not requested. #117329 (Konstantin Vedernikov). - Added the ClickHouse Keeper
ListWithOptionsoperation for filtered direct or recursive listing with optional stats, data, limits, and shuffled results. #117521 (Antonio Andelic). - Added the
MergeTreesettingmin_unreserved_disk_space_for_merge: background merge selection subtracts the specified amount from the unreserved disk space, so large merges stop being selected before they can take the last free space and starve inserts. Unlikekeep_free_space_bytes, the protected space remains usable by ClickHouse itself. #115723 (Valery Petrov). - You can now disable reading through the
executabletable function and fromExecutable/ExecutablePooltables with the newallow_executable_tablessetting, for a deployment that must not run arbitrary server-side scripts. It defaults totrue, so existing behavior is unchanged. #120713 (Hanzi Jiang). - Added server setting
ai_function_allow_sql_named_collections. When disabled, AI functions accept only named collections defined in the server configuration file. #124999 (George Larionov). - Added
<openSSL><server><cipherSuites>and<openSSL><client><cipherSuites>settings to restrict which TLS 1.3 cipher suites a TLS port negotiates. Without them,cipherListcontrols only TLS 1.2 and below. An absent or empty value keeps the OpenSSL defaults. Closes #119929. #120480 (Groene AI). - You can now set a custom syslog program name for ClickHouse logs using
logger.syslog.programname, making it easier to distinguish multiple ClickHouse instances in syslog. The default syslog identifier is now command-specific: remote syslog previously sent-as the RFC 5424APP-NAMEand now sends the command name (for exampleclickhouse-server), and the multi-purpose binary started asclickhouse serverorclickhouse keepernow usesclickhouse-server/clickhouse-keeperinstead ofclickhousefor local syslog. #98789 (François Martin). - Added the
Copyevent and thesource_bucketandsource_remote_pathcolumns tosystem.blob_storage_logfor server-side object copies (S3CopyObjectandUploadPartCopy, Azure Blob Storage copies). Azure backups, restores, andAzureQueuemoves now write tosystem.blob_storage_logtoo. Closes #123163. #123178 (Groene AI). - Added an
is_lazycolumn tosystem.dictionaries. It shows whether each dictionary loads on first use, taking into account both itsdictionary_lazy_loadsetting and the server settingdictionaries_lazy_load. This makes it possible to tell a lazy dictionary that has not been used yet from an eager one that has not been loaded yet; both showNOT_LOADED. #124260 (Miсhael Stetsyuk). - Added the
replica_groupcolumn tosystem.clusters. For clusters that belong to aReplicateddatabase, it shows the replica group of each node as published from the server configurationreplica_group_name, or its aliasrole. #120537 (RinChanNOW). - Added
SYSTEM DISABLE ALL FAILPOINTS, which disables every fail point at once and resumes any thread blocked on a pauseable one. #118877 (Alexey Milovidov).
Experimental Feature
- Added an experimental columns cache that keeps deserialized columns of wide
MergeTreeparts in memory, one entry per stripe of granules of a column. Compared with the uncompressed cache, this saves time on deserialization and copying. It is enabled by the experimental settinguse_columns_cache, withenable_reads_from_columns_cacheandenable_writes_to_columns_cacheas beta sub-settings, and it applies to tables in databases that assign UUIDs (AtomicandReplicated). The cache gives its memory back to queries when the server is short of it. #96844 (Alexey Milovidov). - Added experimental
LATERAL JOINsupport, allowing correlated subqueries in theFROMclause. This enables the standard SQL pattern for “top N per group” and per-row aggregation queries. Controlled by theallow_experimental_lateral_joinsetting. #97833 (Dimitri König). - Added an experimental
logsqldialect: LogsQL, the log query language of VictoriaLogs, can now be used to query ClickHouse tables with logs. Enable it withSET enable_logsql_dialect = 1, logsql_table = '<table>', dialect = 'logsql'(pluslogsql_database,logsql_time_column, andlogsql_message_columnas needed). LogsQL queries are translated at parse time into ordinarySELECTqueries, so text filters expectString-backed log columns, while themathpipe applies raw arithmetic and needs numeric operand columns (Stringfield values are not coerced to numbers). #113207 (Alexey Milovidov). #123891 (Alexey Milovidov). - Added the beta
PCOcompression codec for fixed-width numeric columns, based on the pcodec library. Enable it withenable_pco_codec = 1. #110613 (Alexey Milovidov). - Added a new implementation of the
unitycatalog type in theDataLakeCatalogdatabase engine. It serves bothDeltaLakeandIcebergtables from a single Unity Catalog, detecting the format of each table and routingIcebergtables through the Unity CatalogIcebergREST endpoint. Enable it with the database settinguse_unity_catalog_v2, or set the session setting of the same name beforeCREATE DATABASE. Switch an existing database withALTER DATABASE ... MODIFY SETTING use_unity_catalog_v2 = 1. #115879 (Asya Shneerson). - Added an experimental embedded
IcebergREST catalog server with ClickHouse HTTP authentication. It supportsGET /v1/config, listing, creating, and checking the existence of namespaces, stored either in memory or inKeeper, and listing, creating, loading, checking the existence of, and dropping tables, with their metadata files stored inS3. The catalog can also serve TLS viasecure_port, using the certificate and key inopenSSL.server, and correctly handles/in table and namespace names. Closes #125762. #118924 (Asya Shneerson). #123000 (Asya Shneerson). #123331 (Asya Shneerson). #124978 (Asya Shneerson). #125791 (Groene AI). - Added experimental XGBoost dictionaries: the
XGBOOSTlayout trains a gradient-boosted model from the source table at load time, andpredictXGBoostruns inference. Enable it withenable_xgboost. Available only in builds that include the XGBoost contrib library. #109999 (Matheus Nerone). - Added
ipcryptEncrypt,ipcryptDecrypt,ipcryptPrefixEncryptandipcryptPrefixDecryptfunctions for format-preserving encryption of IP addresses following the IPCrypt specification. The deterministic mode produces consistent output for deduplication, while the prefix-preserving mode maintains subnet relationships. Enable withSET enable_ipcrypt = 1. Contributed by Frank Denis. #123680 (Alexey Milovidov). - Added read support for
Icebergv3 deletion vectors stored inPuffinfiles. #110781 (linjiayu1025-collab). - Added experimental support for
ALTER TABLE ... DROP PARTITIONon standaloneIcebergtables andIcebergREST catalogs. On standalone tables, the operation currently requiresIcebergformat-version 2 with a single non-evolved partition spec. Old date-transform spellings in the partition expression are now evaluated with theIcebergtransform semantics too. #111219 (Den Kalantaevskii). #123273 (Groene AI). #122269 (Den Kalantaevskii). parallel_replicas_plan_basedcan now distribute queries with anIN (subquery)predicate instead of falling back to single-node execution. Closes #111876. #114086 (Igor Nikonov).- With
parallel_replicas_plan_basedenabled, distributedINSERT ... SELECTagain uses distributed execution whenparallel_distributed_insert_select = 2, instead of running theSELECTon the initiator alone. Closes #118276. #121097 (Igor Nikonov). - Distributed query plans built with
make_distributed_plannow compress exchanged data withnetwork_compression_method; forZSTD, they also usenetwork_zstd_compression_levelinstead of the server’s default codec settings. #120333 (Alexander Gololobov). - Queries executed with the experimental
make_distributed_plansetting now propagate the OpenTelemetry trace context to stateless workers via thetraceparentandtracestateHTTP headers of the task dispatch request. Each dispatched task produces aStatelessWorkerClient::sendTaskspan on the initiator plusInterserverIOHTTPHandlerandDistributedPlanTask::executespans on the worker, with the task id, initial query id, plan hash, and exchange streams as attributes, so the whole distributed plan is visible as one trace insystem.opentelemetry_span_log. #119010 (Diego Gomes Tomé). - Join runtime filters can now travel across distributed query plan stages with the experimental setting
distributed_plan_join_runtime_filters(default off). Build-side tasks send partial filters to probe-side scans before their shuffle exchange, reducing the number of rows crossing the network. A filter that is lost, late, or never built cannot change results. #114822 (Harikrishnan Prabakaran). - Distributed index analysis is now beta. #123577 (Azat Khuzhin).
- Added the experimental setting
enable_join_seal_gated_reading(default off). When enabled together withenable_join_runtime_filtersand the probe-side join key is a prefix of the table’s primary key, the probe side of a hashJOINstarts reading only after the build side completes, and the completed runtime filter prunes whole mark ranges by the primary key before read tasks are created, instead of only filtering rows after they were read. #113512 (Nikolai Kochetov). - Replaced the experimental settings
query_plan_optimize_join_order_use_conflict_detector_aandquery_plan_optimize_join_order_use_conflict_detector_cwithquery_plan_optimize_join_order_conflict_detector, which takesa,c, or''(the default). #120630 (Fisnik Kastrati). - Adaptive codec selection (
enable_adaptive_codec_selection) also tries each specialized codec followed by the table’s default codec, and makes merges ofFloat32andFloat64columns faster. #121630 (Raufs Dunamalijevs). #122248 (Raufs Dunamalijevs). - Added the setting
json_extract_named_tuples_as_objects(default off): when enabled, theJSONExtractfunctions fill named tuples from JSON objects only. By default a JSON array fills a named tuple positionally, so which element lands in which field depends on the order the fields were declared in. #122637 (Alexey Milovidov). - Experimental
UNIQUE KEYSST probes now batch lookups withMultiGet, so absent keys can be filtered by the SST bloom filter. More unsupportedUNIQUE KEYoperations are now rejected early. #119997 (johnjing). #123002 (Murphy). - The experimental reader executor (
use_reader_executor = 1) now plans filesystem cache reads ahead over a window set byreader_executor_plan_look_aheadinstead of re-checking the cache on every read window. It also no longer fails spuriously withCANNOT_READ_ALL_DATAwhen a concurrent download advances the filesystem cache during a cold read. #115816 (Sema Checherinda). #122214 (Sema Checherinda). - Streaming queries now prefer a
commit_orderprojection when one is available for the current read round. #120420 (Mikhail Artemenko). - PromQL again supports the range functions
present_over_time,absent_over_time,quantile_over_time, andpredict_linear, and now also supportsstddev_over_time,stdvar_over_time,first_over_time,ts_of_first_over_time,ts_of_last_over_time, andmad_over_time. #112355 (Valery Petrov). #120352 (Vitaly Baranov). #121578 (Vitaly Baranov). #121800 (Vitaly Baranov). - Added PromQL functions
min_ofandmax_ofto return the smaller or larger of two scalar values. #121250 (Minh Vu). - PromQL now implements
timestampfor both direct selectors and general expressions, matching Prometheus 3.5.0 semantics. #112356 (Valery Petrov). - Support standalone PromQL
stepandrangescalar functions. The PromQL parser now also accepts bare calls tostart,end,sort_by_label,sort_by_label_desc,double_exponential_smoothing, andlimit_ratio, so these not yet implemented functions are rejected after parsing instead of failing with a parse error. #121118 (Minh Vu). #123589 (James Cunningham). prometheusQuerynow always returnsFloat64values andDateTime64timestamps with at least millisecond precision. The time zone of the returned timestamps comes from itsDateTimeorDateTime64arguments when they agree, and otherwise from the table. #120285 (Vitaly Baranov).- PromQL now treats Prometheus stale markers as absent in instant selectors and omits them from range selectors. #121098 (Minh Vu).
- PromQL now rejects queries that use the same label in both
on(...)andgroup_left(...)orgroup_right(...). #114376 (Minh Vu). - PromQL now rejects vector selectors whose matchers can all match the empty string. #121099 (Minh Vu).
- PromQL’s
stddevandstdvarnow returnNaNinstead of0. #122743 (James Cunningham). - PromQL now returns
NaNfrom date functions when the sample is not finite. #124300 (James Cunningham). - PromQL no longer fails on empty joins. #124362 (James Cunningham).
- Aligned PromQL string and comment parsing with Prometheus: quoted strings cannot contain a line feed, and a line comment can end at the end of the query without a space after
#. Closes #117812. #124584 (Vitaly Baranov). - PromQL range functions over scalars now handle windows with no samples without failing on
NULL, including when used in nested range functions. #124586 (Vitaly Baranov). - Added deduplication caches for
TimeSeriesmetric families and tags, and fixed stale cache entries when the pending rows are full. #121915 (Vitaly Baranov). #122771 (Vitaly Baranov). - The
tagsinner table of theTimeSeriestable engine is split into atagstable withoutmin_timeandmax_timeand a separate table of time ranges. #121924 (Vitaly Baranov). - The inner tables of the
TimeSeriestable engine now use the outer column namemetric_familyinstead ofmetric_family_name. #119226 (Vitaly Baranov). - Fixed
ALIAS_REQUIREDfor a join with aVIEWwritten without an alias under the experimental settinganalyzer_inline_views = 1: the inlined subquery now keeps the view’s name as a table expression name, so it needs no alias and stays usable as a column qualifier, with or without the database name. #118401 (Alexey Milovidov). - Reading subcolumns of the experimental
Quantizedcodec (vec.quantized,vec.product_quantization_codebook) through aMergetable no longer breaks when another child table of theMergelacks the base column. #123895 (Groene AI).
Performance Improvement
- Large hash tables used for
GROUP BY,uniqExact, andJOINnow use up to two times less memory, and aggregation with many keys is faster on many threads. #125001 (Alexey Milovidov). - The query condition cache now serves conditions that involve the current time, e.g.
WHERE time >= now() - INTERVAL 10 DAY, when reading fromMergeTreetables, by deriving a deterministic condition from them with the current-time constant rounded onto a time grid. Closes #115504. #115522 (Alexey Milovidov). - Enabled the setting
apply_string_filters_during_scanby default. Substring search conditions onStringcolumns (LIKE,position,startsWith,endsWith) fromPREWHEREare pushed down into the column scan, and non-matching values are read as empty strings without copying their data. This makes such queries faster and lowers their memory usage when reading fromMergeTreetables and fromParquetpages whose string values use thePLAIN,DELTA_LENGTH_BYTE_ARRAY,DELTA_BYTE_ARRAY, or dictionary encodings, including reads using the uncompressed cache on object storage. #115848 (Alexey Milovidov). #124503 (Alexey Milovidov). #125079 (Groene AI). #124507 (Alexey Milovidov). - Queries
GROUP BY key LIMIT nandGROUP BY key ORDER BY key LIMIT noverMergeTreetables now read much less data: the aggregation publishes the boundary of its top-K heap to the reading step, which drops rows beyond it before reading the other columns and can skip whole granules through the primary key or aminmaxskip index. Controlled by the new settingenable_group_by_top_k_dynamic_filtering. The same primary-key granule skipping now also applies toORDER BY column LIMIT nwhen the column is in the primary key. #121145 (Alexey Milovidov). - Queries with
ORDER BY <column> LIMIT noverParquetfiles now use TopN dynamic filtering withuse_top_k_dynamic_filtering: rows that cannot enter the top-K are filtered inside the reader before the remaining columns are read, and whole row groups are skipped when their min/max statistics prove they cannot contribute. This works through thefileandurltable functions, theFileandURLengines, object storage (s3,Azure,HDFS), and data lake tables such asIceberg. Floating-point sort columns are excluded for now. #115798 (Alexey Milovidov). #122109 (Alexey Milovidov). #124861 (Alexey Milovidov). query_plan_join_shard_by_pk_rangesis enabled by default. Afull_sorting_mergeorparallel_full_sorting_mergeJOINof twoMergeTreetables whose join keys contain a prefix of the primary key of both tables now runs as independent streaming merge joins over primary-key ranges on all threads instead of a single-threaded merge join, several times faster and with several times less memory in our tests. Hash joins are affected only when both join runtime filters and spilling to disk are disabled. Setquery_plan_join_shard_by_pk_ranges = 0to restore the previous behavior. #117856 (Alexey Milovidov). #119925 (Alexey Milovidov).- Enabled the text-index postings cache by default with
use_text_index_postings_cache. On a 1B-row table, a four-token phrase query that previously recomputed posting lists and phrase-search results within one query went from 19 s to 0.12 s. The shared cache is bounded bytext_index_postings_cache_size(2 GiB by default). #120677 (Nikita Fomichev). #123228 (Anton Popov). - With
optimize_aggregation_in_order = 1, or with the defaultoptimize_distinct_in_order = 1, aGROUP BYorDISTINCTwhose keys extend past the table’s sorting key no longer re-packs the whole block’s grouping key once per run of equal sorting-key values. That cost was quadratic inmax_block_sizeonce the sorting prefix is near-unique, soGROUP BY a, bon a table sorted byais up to 130x faster. Closes #45386. #120259 (Groene AI). - Blocks sent back by remote replicas are now marshalled in parallel (
enable_parallel_blocks_marshalling) whenparallel_replicas_plan_basedis enabled. #121642 (Igor Nikonov). GROUP BYwith aNullablekey now uses the adaptive aggregator, except when that key is the only one and is a number of up to 8 bytes, aString, or aFixedString, or when any key isLowCardinality. Schema inference makes such keys common in CSV, JSON, andParquetfiles; high-cardinality aggregations over them become up to 2x faster with up to 2.2x less memory. #124868 (Groene AI).- Queries over
Nullablecolumns now use the same optimizations as over non-Nullableones:length,empty,notEmpty, and comparisons with an empty string onNullable(String)read thesizesubcolumn,sum(x + c)is rewritten tosum(x) + c * count(x), anduniqExactoverNullableis merged in parallel. Some queries become several times faster. #125011 (Alexey Milovidov). - The trivial
GROUP BY ... LIMIT noptimization (settingoptimize_trivial_group_by_limit_query) now also applies to queries with aggregate functions in the projection when theGROUP BYtop-K optimization does not apply, for example abovequery_plan_max_limit_for_top_k_optimization: once any aggregation thread exceedsn + offsetdistinct keys, all threads are restricted to a single shared set of kept keys, so the hash tables stay small while the aggregate values of the returned keys remain exact, with up to 7-9x speedups. The optimization no longer fires for queries withDISTINCT,QUALIFY,LIMIT AFTER,LIMIT UNTIL, window functions,arrayJoin, orexact_rows_before_limit, where it could return wrong or inexact results. #114690 (Alexey Milovidov). - When
max_threadsis not set explicitly, a query is planned with the fair share of CPU slots of the concurrency control instead of all CPU cores. This increases the throughput and lowers the memory usage under many concurrent queries, while a query on an idle server still uses all cores. It can be disabled with the settinguse_concurrency_control_for_max_threads. #125085 (Alexey Milovidov). - A single-level
GROUP BYresult smaller thanmax_block_sizeis now split into several blocks when it was aggregated by several threads, so the steps after it, such as the probe of a following join, run in parallel instead of on one thread. Previously such queries could be several times slower, most visibly undercompatibilityolder than 26.8, which disablesenable_parallel_single_level_mergeandenable_adaptive_aggregator. The result of aGROUP BYon a single 8- or 16-bit integer key is split the same way. #121711 (Pratham Nayak). - Restored the batched hash-and-prefetch insert path for
uniq,uniqCombined, anduniqCombined64in ordinaryGROUP BYqueries, where they had silently fallen back to a per-row loop and were up to 46% slower. Closes #120531. #120578 (Groene AI). - Faster
GROUP BYover keys that have to be serialized, such as several columns that include aString. #122857 (Samuel Krempaský). GROUP BYover multipleLowCardinalitykeys now serializes the keys from the per-block dictionaries instead of copying them into full columns first, reducing CPU time and memory usage of aggregation queries overLowCardinalitydimensions. #121795 (artemkulyk).- Speed up
GROUP BYover severalLowCardinalitykeys when the same key tuples repeat, by caching aggregate states per tuple of dictionary positions in the serialized aggregation method. #121998 (artemkulyk). GROUP BYover a singleStringcolumn with onlycountis faster when the grouping state does not fit in the CPU cache, especially with long strings. #123655 (Groene AI).GROUP BYqueries with many groups that end inORDER BY count() ... LIMIT nand use no other aggregate function are slightly faster when they group by aStringcolumn or by several columns. #124277 (Groene AI).- Share the
GROUP BYtop-K skip boundary between aggregation threads. #116150 (Konstantin Bogdanov). - Allow using fused
GROUP BYtop-K with a serialized query plan. #116163 (Konstantin Bogdanov). - Added a query-plan optimization, controlled by the new setting
query_plan_aggregation_having_prefilter, forHAVING count() <comparison> <constant>over aGROUP BY. While a two-level bucket of the aggregation result is converted to chunks, a group whosecount()cannot satisfy the bound is now skipped before its key columns are materialized, instead of being materialized and then discarded by the filter above. This speeds up “groups above a threshold” queries over a high-cardinalityGROUP BYwith wide keys, where the discarded keys are most of the conversion. A skipped group is neither filtered nor finalized, so aHAVINGconjunct written before the bound, and a sibling aggregate’s finalization, stop being evaluated on the groups the bound rejects: a query that raised an exception from one of those can now return rows instead. Settingquery_plan_aggregation_having_prefilter = 0, orcompatibilityto a version below26.10, keeps the previous behavior. #120510 (Groene AI). optimize_aggregators_of_group_by_keysnow works forLowCardinalityGROUP BYkeys, so aHAVINGpredicate such asHAVING min(s) = 'x'is pushed down to storage and can use skip indexes, as for a plain key. It also eliminatesanyHeavy,quantileExact,quantileExactLow,quantileExactHigh,groupBitAnd, andgroupBitOrof aGROUP BYkey. #110059 (Groene AI).-Ifaggregate functions with oneNullableargument no longer allocate a buffer the size of the whole block for every group withoptimize_aggregation_in_orderor for every window frame. With small groups or frames this makes them 1.7 to 3.1 times faster on x86_64. #122505 (Groene AI).- Speed up
-ForEachaggregate functions such assumForEachandavgForEach: rows are processed in batches instead of callingaddfor each row, and an array of two or more elements is passed to the nested function in one call instead of one call per element. Grouped multi-argument-Ifaggregate functions with aNullableargument or condition are also processed in batches. #121137 (Valery Petrov). #124207 (Groene AI). - Speed up serialization of
AggregateFunctionstate columns with a fixed-size state, such assum,count,avg,min,max, andany, and their-If,-Array,-Merge, andNullablevariants. This affects writes toAggregatingMergeTree, theNativeformat, distributed queries, and spilling aggregate states to disk. #113962 (Manuel). - Speed up reading and merging of
uniqaggregate function states, such asuniqMergeover anAggregatingMergeTree, by 10-35% depending on state sizes and merge shape. #111493 (Manuel). - Faster merging of
uniqCombinedanduniqCombined64states with many distinct values into empty states, e.g. in-Mergecombinators andAggregatingMergeTree: up to 6x faster. #124389 (Manuel). - Reduce memory usage and improve performance of external
DISTINCTby avoiding spills for duplicate-heavy input, writing smaller spill blocks, budgeting tail spilling before the final merge, preserving constant payloads, combining chunks before sorting, and retaining fewer rows while restoring order withLIMIT. #121772 (Nihal Z. Miaji). - Faster sorted-stream processing on a multi-column key whose leading column has long runs, in
LIMIT BY, negativeLIMIT BY,DISTINCTin order,full_sorting_mergeandpartial_mergeJOIN, andReplacingMergeTreeFINALwithout verticalFINAL: the run of a key prefix is now found once instead of again for every group in it. The query from #123700 is about 3.5x faster. #123808 (Groene AI). - Short queries with many keyed aggregations or scalar subqueries over large constant-folded literals are faster because hash-table-stats cache keys no longer hash whole variable-size constant values. #122738 (Nikita Taranov).
- Reduce memory usage of some window functions by precomputing peer-group boundaries instead of keeping earlier blocks in memory. #123737 (Mikhail Artemenko).
- A filter on the
PARTITION BYcolumns of a window function is no longer pushed below the window (this reverts #110114). The push-down made queries up to 8 times slower when the window reads aJOINand the filter removes every row, for exampleINover an empty subquery, because the join built its right side before the filter could stop the query. Closes #123875. #125463 (Groene AI). hashandparallel_hashjoins now copy right-side output columns directly from the stored blocks instead of calling the stored column object once per row. This speeds up every column type, includingString,Array,Tuple,Nullable,Variant,Map,LowCardinality,JSON,Dynamic,AggregateFunction, andQBit. #117460 (Harikrishnan Prabakaran).- Speed up hash join output construction in the row-major layout: output reconstruction is up to 2x faster for joins with many rows per key and about 1.5x for wide or
Nullablepayloads. The row-major layout is now also skipped for payloads too narrow to benefit from it. #121981 (Hechem Selmi). - Hash joins with many matches per key are faster when they output a
LowCardinalitycolumn whose blocks have different dictionaries (several parts,FINAL, or aLowCardinalityvalue computed per block): short ranges from another dictionary are now inserted key by key instead of through temporary columns. Such joins run 4-9x faster, at the 26.6 level or better. #123900 (Groene AI). RIGHTandFULLjoins usinghash,parallel_hash, orgrace_hashskip the search for unmatched right rows when every right key has matched. With 50 million right keys, that search was about 10% of query time forhash(356 ms of 3.6 s) and about 15% forparallel_hash(106 ms of 0.7 s). #124775 (Groene AI).- A
full_sorting_mergejoin now advertises that its result is ordered by the join key, so a sort above it, the pre-sort of the next merge join in a chain or anORDER BY, merges the already sorted streams instead of sorting from scratch. Joining several tables on the same key withfull_sorting_mergeno longer performs one full sort per join. Also fixed the interplay withquery_plan_join_shard_by_pk_ranges, which could otherwise fail with a logical error or return wrong results for such a chain. #117786 (Alexey Milovidov). - A join step that has a condition of its own now also joins on equalities implied through other tables, so for
a.x = b.x AND b.x = c.x, joiningawithcalso usesa.x = c.x. Withquery_plan_optimize_join_order_algorithm = 'dpsize', this makes TPC-H Q02 join its correlated subquery topartsuppon the part key instead of on the supply cost alone. Closes #122396. #122445 (Groene AI). - A
WHEREcondition that no row satisfies is pushed to everyJOINinput again, including the non-preserved side of anOUTER JOINand a side with no column used above the join, so that input is no longer read and hash-built for nothing. For example, aUNION ALLbranch whose constant column fails the outerWHEREis skipped as in 26.6. Closes #123702. Closes #123878. #123829 (Groene AI). - Constant comparison, logical, and null (
IS NULL/IS NOT NULL) filters over materialized constants are now folded and pushed down, reducing unnecessary reads inWHERE,PREWHERE, andUNIONbranches. Always-trueWHEREfilters are replaced with expressions so join reordering still sees all joined tables as one graph. #105987 (Yarik Briukhovetskyi). #124056 (Yarik Briukhovetskyi). OUTER JOINqueries can now be faster: when aWHEREclause or anotherJOINlater in the query would discard the unmatched rows anyway, ClickHouse converts the join to anINNER JOIN. The new settingquery_plan_convert_outer_join_to_inner_join_transitivelycontrols this, and only takes effect whenquery_plan_convert_outer_join_to_inner_joinis enabled. #120253 (Hechem Selmi).- Restored filter push-down over
ANY INNER JOIN, so primary-key pruning works again and such queries no longer read much more data than necessary. BecauseANYkeeps an arbitrary matching row,SELECT ... ANY INNER JOIN ... WHERE ...can now return a different matching row than before. #120765 (Kirill Shokhin). optimize_and_compare_chainagain derives transitive conditions through aDateTimeor lower-scaleDateTime64constant compared with aDateTime64expression, as it did before 26.8. For example,t1.ts < toDateTime('2026-09-16 00:00:00') AND t1.ts >= t2.tsaddst2.ts < toDateTime('2026-09-16 00:00:00'), so the other side of a join can be pruned by its partition and primary key instead of being read in full. Closes #123706. #123796 (Groene AI).- Improve join order selection when column statistics are missing: an equi join without NDV statistics is now treated more like a foreign-key-to-primary-key join instead of a cross product, and the greedy join-order algorithm prefers equi-connected pairs over pairs linked only by non-equi predicates. #120176 (Vladimir Cherkasov). #121075 (Alexey Milovidov).
- Improves
JOINcardinality estimation by propagating join-key distinct-value estimates according to join semantics. Outer joins retain the preserved-side estimate, anti joins keep their input estimates, and semi joins narrow only the output side, preventing underestimation that could lead to suboptimal query plans. #122305 (Christoph Viebig). IEJoinnow treats opposite-direction conditions on unrelated columns as independent conditions instead of as a band, which avoids choosing a join-key pair that passes thousands of times more rows to the residual condition. #120213 (Vladimir Cherkasov).- Function
firstNonDefault, which computes theUSINGcolumns ofFULL JOIN, now copies whole ranges of rows instead of making two virtual calls per row. Queries that use aUSINGcolumn of aFULL JOINafter the join, for example inWHERE, are faster. #123302 (Groene AI). - Enabled
enable_join_runtime_filters_index_analysisby default, so join runtime filters can prune granules during the probe phase. #121859 (Robert Schulze). - Join runtime filters now run after the query’s own
PREWHEREconditions also for tables without column statistics, as they already did with statistics. Before, a runtime filter on a well-compressed join key could run first and read that key for every row, so enablingenable_join_runtime_filterscould make a query read several times more data than without it. #122452 (Groene AI). - The granule pruning of
enable_join_runtime_filters_index_analysisnow also applies when the left side of aJOINis read from a normal projection. The setting description states that the pruning does not happen with parallel replicas, a distributed query plan, orFINAL. #119041 (Alexey Milovidov). - The query condition cache now records the static
WHEREconditions of a join whosePREWHEREalso holds a join runtime filter, so a repeated join skips the granules those conditions exclude instead of reading them again. This helps whenever the runtime filter cannot skip those granules through an index itself, for example when no primary key or skip index covers the join key, or whenenable_join_runtime_filters_index_analysisis disabled. #122380 (Groene AI). - Repeated insertion of empty and single-element
Arrayvalues into in-memory columns is now faster. This happens, for example, during joins. #117321 (Minh Vu). - With
use_top_k_dynamic_filtering = 1(the default), aSELECT ... ORDER BY ... LIMIT ncould read far more data than with the setting off: the internal__topKFiltertook over the read’sPREWHEREslot and displaced the query’s own condition, and an explicitPREWHEREdisabled the feature outright. The threshold filter now sharesPREWHEREwith the other conditions and takes the first slot. It is also no longer installed on a read that a sorting projection already delivers inORDER BYorder, where it forced a full scan. #117968 (Groene AI). - Granules fully filtered by the dynamic threshold of an
ORDER BY ... LIMIT nread are now recorded in the query condition cache, so repeat runs of such queries skip them at the mark-selection stage instead of re-reading and re-filtering most of the table. On the ClickBench Q24/Q26 shapes (SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime LIMIT 10), a warm run drops from about 95 million rows / 12000 granules read to about 1.3 million rows / 160 granules, and from about 15-30 ms to about 8 ms on a 96-core machine. This now also works forORDER BY ... LIMIT nqueries overParquetfiles ofFiletables, with or without aWHEREclause: a repeated query reads only the row groups which can hold rows of its result. #114659 (Alexey Milovidov). #122064 (Alexey Milovidov). - Improve performance of
ORDER BY ... LIMITqueries that use minmax-index top-K pruning (use_skip_indexes_for_top_k) on large tables with many granules. #116512 (Anton Popov). - Queries with
FINALthat sort in reverse order of the sorting key, such asSELECT ... FROM t FINAL ORDER BY key DESC LIMIT n, now read in order throughMergetables overReplacingMergeTreetables too, and thetopKThroughJoinoptimization defers to reverse-order reads below aLEFT JOINwhen the table supports them. This extends #115345. #118008 (Alexey Milovidov). - Fixed a performance regression in
ORDER BYmerge sort: queries with a sort followed byLIMITno longer do redundant per-output-block work in result-block reservation. #108179 (Groene AI). - Setting
optimize_move_to_prewhere_if_finalis now enabled by default, so queries withFINALbenefit from the automaticPREWHEREoptimization. Only deterministic conditions over the sorting key are moved, and query results are not affected. #121350 (Yarik Briukhovetskyi). - With short-circuit evaluation, non-throwing arguments of
andandorare now ordered by measured cost and selectivity, so cheap filters can avoid evaluating expensive expressions on excluded rows. Controlled byshort_circuit_function_evaluation_reorder_arguments, enabled by default. #122508 (Alexey Milovidov). - Fix a performance regression in short-circuit evaluation of
andandorby avoiding expansion of intermediate results that are only used to update the logical mask. #120520 (LB7666). - On a table with no applicable data skipping index, a query no longer stores the same predicate under two query condition cache keys. This halves the number of
O(marks per part)cache entries such a query allocates, and removes one cache lookup per part. Queries withdistributed_index_analysisenabled keep both keys. #116259 (Groene AI). SELECT ... FINALwith a selective skip-index plan is much faster on tables with many granules: theuse_skip_indexes_if_final_exact_moderecovery pass now iterates ranges instead of individual granules. #121799 (Nikolai Kochetov).- Improve primary index analysis in queries that filter both by the primary key and by other columns, for example
WHERE timestamp BETWEEN ... AND level = 'error'wherelevelis not in the primary key. #123535 (Anton Popov). IS NULLandIS NOT NULLpredicates can now pruneMergeTreeparts using theNULLrow count tracked bybasicstatistics onNullablecolumns. #116697 (zoomxi).- A
setskip index on aNullablecolumn again skips granules whose stored set containsNULLbut not the searched value forINand=conditions, restoring the pruning lost in 26.8. Closes #123705. #123778 (Groene AI). - Skip indexes (
text,bloom_filter,tokenbf_v1,ngrambf_v1,minmax) and the primary key are now used when the indexed column or the searched constant is wrapped in a conversion that does not change its value, such astoLowCardinality,toNullable, or aCASTtoNullableorLowCardinality. For example,m['key'] = 'value'onMap(String, LowCardinality(String))andhasToken(s, toLowCardinality('x'))no longer scan all granules.bloom_filterand text indexes also work when aNullableindexed column is cast to the non-Nullabletype, such asCAST(x, 'String')orjson.path::String. #120220 (Anton Popov). #123239 (Anton Popov). #124220 (Anton Popov). - Speed up planning of queries with skip indexes on tables with many parts and pending patch parts of lightweight updates. #124931 (Anton Popov).
- Speed up queries with multiple
PREWHEREconditions on AMD Zen 1 and Zen 2 CPUs. #120283 (Manuel). - Analysis of a query over a
Mergetable no longer traverses every child table for each query-tree node whenoptimize_functions_to_subcolumnsis enabled. The answer is now reused across the query tree, so analysis time grows with the query size plus the number of child tables instead of their product. Closes #113202. #113367 (Groene AI). - Queries to the
mergetable function and creation ofMergetables are faster when the source tables have many columns: combining the source columns no longer takes quadratic time in the number of columns. #124115 (Groene AI). - Faster analysis of queries to tables with many
ALIAScolumns, such assystem.metric_log: the expression of anALIAScolumn is analyzed only if the query uses that column. #123926 (Alexey Milovidov). - Reduce aggregate projection analysis overhead for tables with many subcolumns. #110979 (Rory Shanks).
- A condition such as
name IN ('a', 'b')on the system tables that enumerate tables (system.tables,system.columns,system.parts,system.replicas, and others) now narrows the enumeration instead of walking every table of every database, the same way an equality condition already did. This is most visible for databases whose table list comes from a remote system, such asPostgreSQL,SQLite, and the DataLake catalogs. #117589 (Alexey Milovidov). - Added the
external_storage_push_down_limitsetting to reduce data read from external databases for safeLIMITqueries. Also fixed wrong results whenLIMITplusOFFSETdoes not fit inUInt64:numbers,system.numbers,generate_series,primes,system.primes, and thePostgreSQLtable engine returned no rows for the common “no limit” idiomLIMIT 18446744073709551615 OFFSET n, and aLIMITover aJOINwithnumbers-like sources returned too few rows. #115238 (Alexey Milovidov). #118131 (Groene AI). - Push filters into the query fragment executed by parallel replicas so replicas can filter rows and prune data before sending results to the initiator. This also allows join runtime filters to reach the relevant reads. Controlled by
parallel_replicas_filter_pushdown, now enabled by default;SET parallel_replicas_filter_pushdown = 0restores the behavior before 26.10. #117373 (Nikita Taranov). - With parallel replicas,
optimize_aggregation_in_orderno longer disables projections: aggregate and normal projections, and_minmax_count_projectionforcount()with a partition predicate, are used as withoptimize_aggregation_in_order = 0. Closes #123061. #123098 (Groene AI). - Parallel replicas now apply
enable_join_runtime_filters_index_analysisto prune probe-side granules locally on each replica, reducingJOINread work. #123116 (Nikita Taranov). - Automatic parallel replicas no longer distributes a query when most of its reading would be repeated in full by every replica rather than split between them. The limit is set by the new setting
automatic_parallel_replicas_max_duplicated_read_ratio(default0.5;1disables it). #123332 (Nikita Taranov). - Automatic parallel replicas for multi-read queries now reuse local plan index analysis in the parallel-replicas plan, reducing extra reads when parallel replicas are enabled. #115153 (Nikita Taranov).
- Improve reuse of collected query statistics by automatic parallel replicas for equivalent local and distributed plans. #116781 (Nikita Taranov).
- Automatic parallel replicas now account correctly for the size of aggregated results on more aggregation paths, so the cost model no longer treats shipping aggregate states as free and is less likely to choose parallel replicas when a query is cheaper locally. #119499 (Nikita Taranov).
- Automatic parallel replicas now collect planning statistics for the table read that is actually split between replicas, including after join reordering and with lazy materialization, improving the decision to distribute a query. #122906 (Nikita Taranov).
- Avoid building the parallel replicas candidate plan when cached statistics already show the query should stay on a single replica. #124983 (Nikita Taranov).
- Added quick checks to skip automatic parallel replicas optimization for queries unsupported by parallel replicas, including keyless aggregations whose aggregate state owns memory and therefore never produces the probe statistics the optimization needs. #120861 (Nikita Taranov). #125470 (Nikita Taranov).
- Automatic parallel replicas (
automatic_parallel_replicas_mode) can now be applied to queries withORDER BY ... WITH FILL. #123929 (Alexey Milovidov). - Queries that search for several tokens at once with a text index, such as
hasAllTokens, are now faster. The automatic choice of algorithm for intersecting posting lists is improved too, and is controlled by the new settingtext_index_postings_intersection_algorithm. #121038 (Anton Popov). - Queries that use a text index read large posting lists faster and with fewer disk operations. The improvement is most noticeable for searches for frequent tokens in big tables. #121040 (Anton Popov).
- A query that searches a text index and also selects a column no index covers no longer reads that column for every row of every granule the index selected. On a 1M-row table with a 1055-byte payload and 64 matching rows,
SELECT ts, payload FROM t WHERE hasToken(message, 'needle')now reads 578 KiB instead of 532 MiB. #120517 (Groene AI). - A query that reads a
textindex no longer asks the filesystem for each index substream’s on-disk name and size once per part; both are now taken from the part’s checksums, which already hold them. On an 8M-row table split into 400 parts,SELECT count() FROM logs WHERE hasToken(message, 'needle')drops from a median 12 ms to 9 ms, with 42% less system time. #120875 (Groene AI). - Speed up queries that filter by a text index together with other
PREWHEREconditions, such as the dynamic filter ofORDER BY ... LIMITqueries. #124880 (Anton Popov). - Speed up
LIKE,ILIKE,startsWith, andendsWithevaluated by a text-index dictionary scan (use_text_index_like_evaluation_by_dictionary_scan): the scan now seeks the sorted dictionary to the block range an anchored pattern can match, and tests a block’s tokens for the pattern’s mandatory literal in one pass instead of running the matcher on every token. #120495 (Groene AI). - Repeated broad
LIKEandILIKEqueries over a text index no longer rescan the index dictionary of every part only to abandon the scan again: the decision is cached (settinguse_text_index_pattern_bypass_cache). #113572 (Rory Shanks). - A text index with the
splitByNonAlphaorarraytokenizer now answers single-needlemultiSearchAny,multiSearchAnyUTF8,multiSearchAnyCaseInsensitive, andmultiSearchAnyCaseInsensitiveUTF8with the same dictionary scan thatLIKE '%needle%'uses, so a needle inside a word, such asPointerExcinNullPointerException, no longer reads the whole column. #124520 (Groene AI). multiSearchAnyover a map element can now use amapValues(...)ngram or token text index instead of being rejected by index analysis. #121787 (Groene AI).- Optimize
SELECT count()queries answered from a text index with a compressed posting list codec (bitpacking,pfor). #123294 (Anton Popov). - Reduced the CPU overhead of reading and intersecting text index posting lists in lazy apply mode. #123786 (Anton Popov). #123873 (Anton Popov).
- Merges of tables with a
textindex are now faster. Pages of a source part’s row ids that hold consecutive values are stored as a first value plus a count, so they are neither bit-packed nor decoded per posting row id and need no storage for packed values. #120982 (Groene AI). - Merging positional text indexes is faster: position lists are now merged segment by segment instead of being materialized and sorted in a temporary
roaringishstructure. #121976 (Elmi Ahmadov). - Added the
pforcodec for text-index posting lists. It improves compression ratio and decoding speed. Enable it per index withposting_list_codec = 'pfor', or for all text indexes of a table with thetext_index_posting_list_codecsetting. #118123 (Elmi Ahmadov). - Building text indexes during
INSERTis now faster, especially for indexes with thebitpackingcodec. #113856 (Anton Popov). - Building a text index over a
LowCardinality(String)orArray(LowCardinality(String))column is faster: each distinct value is tokenized once per batch of rows instead of at every occurrence.MATERIALIZE INDEXover a column with 50 distinct values takes about 33% less time. #122409 (Groene AI). - Improve performance of the
ngramstokenizer. This speeds uptokens(s, 'ngrams', N),ngrams(s, N),hasAnyTokens,hasAllTokens, andhasPhrasewith thengramstokenizer, as well as inserts into tables with anngrambf_v1ortext(tokenizer = ngrams(N))index.tokens(URL, 'ngrams', 3)over ClickBench URLs takes 26% (aarch64) to 36% (x86_64) less time. #122328 (Groene AI). - Reading columns and subcolumns of
MergeTreetables no longer rebuilds the serialization of a column for every reader: the serialization the data part already holds is reused. The gain is largest forJSONcolumns with many typed paths, where the whole set of path serializations used to be rebuilt per read task and per filter step. #120632 (Pavel Kruglov). - Reduce per-block overhead when reading
MergeTreeparts with small blocks: column-stream names and substream-cache keys are no longer rebuilt for every block, and reads skip patch-part handling when there are none, virtual-column name lookups, and some small-column reallocations. This makes queries with a lowmax_block_sizefaster. #124816 (Alexey Milovidov). #124817 (Alexey Milovidov). - Reduce CPU overhead of reads from
MergeTreetables by not formatting a tracing span name for every block. #124820 (Alexey Milovidov). - Reading many columns from Compact parts is up to 2% faster by avoiding per-call copies of column metadata. #122840 (Samuel Krempaský).
- Restore parallel prefix deserialization when reading an
ObjectorJSONcolumn from a Wide part: marks loading no longer queues behind one mutex. Closes #114136. #114252 (Groene AI). - Queries that read subcolumns of
JSONcolumns with many typed paths are faster: resolving a subcolumn by name visits only the typed paths that can match it. For aJSONcolumn with 500 typed paths, reading subcolumns from 96 parts takes about half the time. #122029 (Rory Shanks). - Reduce serialization construction when reading
JSONsubcolumns fromMergeTreeparts by reusing safe cached subcolumn serializations. #110957 (Rory Shanks). - Improve nested
JSONpath read performance withmap_with_bucketsby reusing thread-local serializations forDynamicvalues. #113344 (Rory Shanks). - Writing
JSONcolumns with many paths in shared data is faster: the writer no longer rebuilds the statistics of the column for every block. For merges of parts with small granules, this saves up to 13% of the merge time. #121987 (Rory Shanks). - Make constructing a
JSONdata type that usesSKIP REGEXPcheaper. The patterns are now compiled once per type instead of once for every declared path, so a column declaring 183 typed paths and 6SKIP REGEXPentries performs 6 regular expression compilations where it previously performed 1098. This matters most for wideJSONschemas, where the patterns are often long alternations that are expensive to compile. #122941 (arc1999). - Read only the matching
Mapsubcolumn for safeLIKEpredicates overMapvalues. #119809 (Minh Vu). - Improve
SELECTperformance by avoiding lock contention when getting mutation snapshots with many concurrent background fetches. #102382 (c-end). - Support
PREWHERE(including the automatic move ofWHEREconditions byoptimize_move_to_prewhere) forMemorytables: only the columns of the conditions are read at first, and the remaining columns are read only for the blocks where some rows pass, and only for the passing rows. This is especially beneficial for tables withSETTINGS compress = true, because for a selective condition most columns are never decompressed. Additionally,SELECT count() FROM tableon aMemorytable is now served from metadata, andsystem.columnsshows real per-column sizes forMemorytables. #116248 (Alexey Milovidov). PREWHEREover aMemorytable is evaluated in multiple steps, like forMergeTree(enable_multiple_prewhere_read_steps): the columns of each next condition are read only for the rows that passed the previous ones. For a table withcompress = true, a condition on a wide column next to a selective one no longer decompresses that column for every block, which makes such queries up to several times faster. #122604 (Alexey Milovidov).- Queries with
ORDER BY ... LIMIT noverMemorytables use TopN dynamic filtering: rows that cannot get into the result are dropped while reading, before the other columns are read or decompressed withcompress = true. #123787 (Alexey Milovidov). - Queries whose only aggregate functions are
minandmaxof columns ofParquetfiles read with thefiletable function or theFileengine, withoutGROUP BYor filters (for example ClickBench Q7), now take the values from the column chunk statistics instead of reading the data. Controlled by the new settingoptimize_min_max_from_files. #124201 (Groene AI). ORDER BY ... LIMITover a singleParquetfile reads first the row groups whose min/max statistics are best for the result, so the top-K threshold skips the other row groups:SELECT URL FROM file('hits.parquet') ORDER BY UserID DESC LIMIT 10skips 207 of its 226 row groups at 4 threads. New profile eventParquetTopKSkippedRowGroups. #123639 (Groene AI).- Row group pruning by dictionaries in the
Parquetreader is faster for an equality or a shortINlist on a column with large dictionaries, such asWHERE UserID = ...over ClickBenchhits.parquet: the hashes of the dictionary values are no longer sorted unless a column chunk is checked against many values. #123579 (Groene AI). Parquetreaders now check a column chunk’s bloom filter before reading its dictionary page. A row group that the bloom filter rules out no longer reads the much larger dictionary page to reach the same conclusion, soinput_format_parquet_dictionary_filter_push_downcosts nothing on files that carry both, while pruning as much as before. #120907 (Alexey Milovidov).Parquetfooter-size reads are now tuned by storage type: remote and object-storage reads use more optimistic footer-size estimates to fetch the footer in one read instead of two, reducing footer-read latency, while local-file reads again use a 64 KiB tail so short queries over many localParquetfiles read less data. #115686 (UnamedRus). #124883 (Groene AI).- Avoid a redundant object-storage GET request when reading random-access formats from object storage. The generic from-start read-ahead is no longer issued for files larger than a single read buffer, where it could not reach the footer. Also,
input_format_allow_seeks = 0is now honored by theParquetreader, which previously sought regardless of the setting: with seeks disabled the whole object is read sequentially instead, which can raise memory usage for queries that set it. #115681 (UnamedRus). - Speed up writing
Parquetbloom filters: instead of deduplicating the value hashes in a hash set to determine the filter size, the writer now builds a filter sized for the number of values and folds it down to the size implied byoutput_format_parquet_bloom_filter_bits_per_value. This removes the worst-case slowdown on data that is adversarial for the hash set, and lowers the worst-case memory usage. #119230 (Armin Braun). - Parse some GeoParquet metadata lazily. #122693 (Konstantin Vedernikov).
- Snappy decompression on AArch64 now uses NEON for short-offset copies, as upstream snappy does by default, which makes reading Snappy-compressed
Parquetwith repetitive string columns up to ~9% faster on ARM servers. The ARMv8.0 compatibility build (NO_ARMV81_OR_HIGHER) is unchanged. #124608 (Groene AI). - Reading
CSVwithinput_format_csv_trim_whitespaces = 0no longer prevents the parser from scaling across CPU cores. Each field used to copy ashared_ptrshared by all parsing threads, turning its reference counter into a contention point. On a 96-core machine, reading 200 million rows became 4.6 times faster and used 23 times less CPU. #117251 (Alexey Milovidov). Icebergpartition pruning now uses the partition value of aday,month,year, orhourtransform for a filter that wraps the partition source column in a monotonic function, such asWHERE toDate(ts) = '2024-01-20', including for partition values from before 1970. Closes #103433. #118606 (Konstantin Vedernikov). #119302 (Alexey Milovidov).- Faster planning of queries to
Icebergtables with many manifest files: when a manifest file header has theschema-idkey and that schema is already known frommetadata.json, the schema copy stored in the manifest header is no longer parsed and compared with it. ClickHouse now also writes theschema-idkey into the headers of manifest files it creates. #122574 (Konstantin Vedernikov). - An
INSERTinto anIcebergtable that loses the commit race now reuses its manifests on retry and rewrites only the manifest list and the metadata file, instead of regenerating all manifests. #122096 (Asya Shneerson). - Restore the summary-based trivial
count()optimization forIcebergtables when the snapshot summary contains a safe row count. The optimization is skipped when equality deletes are present, because their recorded count is not the number of deleted rows. #123267 (Konstantin Vedernikov). Icebergmin/max hyperrectangles are now built only for columns the filter uses. #122681 (Konstantin Vedernikov).- Restore min/max pruning of
Icebergdata files for aDecimal(38, 38)column. A manifest bound of magnitude above roughly 0.7 could not be widened insideInt128and was dropped, leaving the column without a min/max condition; it is now saturated at the largest magnitude the precision allows, which is still outside every value the file can hold. #119712 (Alexey Milovidov). - Queries to
system.iceberg_historywith filters ontablenow avoid listing unrelated data lake catalog namespaces. #113867 (Den Kalantaevskii). - Improve HTTP upload and download efficiency for
S3,Azure, theurltable function and engine, dictionaries, and data lake catalogs. Uploads use 1 MiB chunks instead of 8 KiB chunks, reducing the number of system calls for a 15 MB body from 1817 to 15 and avoiding redundant copies. Reads fromAzurealso avoid an intermediate 8 KiB buffer. #116222 (Alexey Milovidov). - Reading from object storage with
remote_filesystem_read_method = 'read'now keeps full-size network reads. Before, a short read at the end of one range capped every later read of the same file, which could make a scan hundreds of times slower, for example a compact part on an encryptedS3disk without the filesystem cache. #123777 (Groene AI). - Reads that are served from the OS page cache no longer consume the budget of the local read bandwidth throttler (
max_local_read_bandwidth_for_serverandmax_local_read_bandwidth), so a query over cached data is not slowed down to the configured disk bandwidth. This works with the defaultlocal_filesystem_read_method = 'pread_threadpool', withpread, and for the files of the filesystem cache; thereadmethod cannot detect cached reads and is accounted as before. #118495 (Alexey Milovidov). - Populating the filesystem cache on a cache miss is faster: the writer now reserves space ahead instead of taking the cache lock on every write. #123255 (Kseniia Sumarokova).
- Loading the metadata of a large
s3_plain_rewritabledisk is several times faster. Previously it made oneListObjectsrequest per directory and enumerated the__metadirectory by a single paginated listing, so a disk with tens of thousands of directories needed tens of thousands of sequential-ish requests. The listings are now split by key prefix and run in parallel, and the files of all directories are collected by a few listings of the whole disk. For a disk with 36 thousand directories holding half a million objects, the load time dropped from 116 to 37 seconds. #121412 (Alexey Milovidov). - Metadata transactions of unrelated tables on a
plain_rewritabledisk no longer wait for each other: the disk-wide lock used to be held across all object storage requests of a commit, so one longMOVE PARTITION,DROP TABLE, or part removal blocked every merge, insert, andCREATE TABLEon the same disk. The lock is now taken per affected path, and the in-memory metadata is updated by replaying the recorded changes. Also fixes a permanent leak of objects when the server was killed duringDROP TABLE(or another removal) on aplain_rewritabledisk: the leftovers of such a removal are now marked and deleted when the disk metadata is loaded on the next start. #118490 (Alexey Milovidov). - Removing data parts from a disk with
metadata_type = plain_rewritable(cleanup of outdated parts,TRUNCATE,DROP PARTITION,DROP TABLE) no longer copies every file of the part to a temporary object before deleting it, and no longer holds the disk metadata lock for those copies. The part directory is removed with one batched delete request. Closes #123275. #123303 (Groene AI). - Reduce metadata update cost and lock contention for
s3_plain_rewritabledisks with many parts by sharing unchanged directory entries between snapshots. #119625 (Rory Shanks). - Avoid object reads for unchanged directories when a plain-rewritable disk refreshes its metadata. #119760 (Rory Shanks).
OPTIMIZE TABLE ... FINALon a non-replicatedMergeTreetable now assigns and runs the merges for all partitions at once instead of processing them one partition at a time. #109004 (Alexey Milovidov).TTL DELETEmerges can now use the vertical merge algorithm onReplacingMergeTree,CollapsingMergeTree, andVersionedCollapsingMergeTree, wherevertical_merge_optimize_ttl_deletepreviously applied only to plainMergeTree. #119886 (Murphy).- Allow vertical merges to produce
Wideparts withPackedstorage instead of forcing the horizontal merge algorithm. #125760 (alesapin). - Improved merge performance for
SummingMergeTreetables by skipping unnecessary aggregate-column materialization. #120852 (Eduard Karacharov). - Many queued lightweight deletes with an
INcondition that reach the same part in one mutation are now applied together, instead of evaluating eachINpredicate over the whole part separately. Controlled by the newMergeTreesettingenable_row_mask_update_coalescing. #122718 (Sergey Kuznetsov). - Optimize the insert backpressure path in
MergeTreeby short-circuiting the parts-count check. #114754 (johnjing). - Reduced merge-selection work when all storage volumes allow merges. #119782 (Rory Shanks).
- Reduce merge-selection CPU overhead for tables with column TTLs by avoiding copies of TTL descriptions. #119644 (Rory Shanks).
- Speed up decompression of codec chains. The first codec now reads the compressed block in place and the last codec writes the result in place, unless that codec requires a padded buffer (
LZ4,ZXC). #120043 (Raufs Dunamalijevs). - Faster decompression of
T64-encoded columns. #120414 (Raufs Dunamalijevs). #122442 (Raufs Dunamalijevs). - A query with
arrayJoinand a smallLIMITagain shrinks the read block size instead of reading whole blocks on every thread for a few output rows, fixing a regression from 26.6. Closes #119193. #120214 (Yarik Briukhovetskyi). - Chained
ARRAY JOINs no longer materialize the whole block of a lazily replicated array column before expanding it, which cuts their peak memory by several times. #121397 (Yarik Briukhovetskyi). - Avoid copying whole columns when slicing them, including in
ARRAY JOIN. #118788 (Nikita Mikhaylov). - Improve
ARRAY JOINperformance for queries with wide columns that are not expanded, by avoiding unnecessary copies and preserving lazy replication through filtering and sorting. #124727 (Yarik Briukhovetskyi). - Reduced the peak memory usage of
RESTOREand of incrementalBACKUP: the metadata file of a backup is now parsed while it is read, instead of being read into memory whole first. For backups of millions of files this saves gigabytes. #125712 (Julia Kartseva). - Faster startup of
clickhouse-localand other tools. Time zone lookup tables are built 2.4 to 5.6 times faster and use half the memory (2.3 MiB instead of 4.6 MiB per loaded time zone). Theclickhousebinary also starts faster when it is not in the page cache, with a 1.40x speedup measured forclickhouse local. #125665 (Raúl Marín). #125672 (Raúl Marín). - A full scan of a complex-key
hashed,sparse_hashed,hashed_array, orrange_hasheddictionary (SELECT ... FROM <dictionary>or thedictionarytable function) is faster: each reading stream now deserializes only the keys of its own block instead of one thread deserializing all keys before reading starts. A scan withLIMITdeserializes only the blocks it reads. A full scan also no longer keeps all deserialized keys in memory at once. #123883 (Groene AI). - Added the
SIEVEcache eviction policy for in-memory caches such as the mark cache and the uncompressed cache. Enable it with the corresponding*_cache_policyserver settings, for examplemark_cache_policyoruncompressed_cache_policy. It is not available for the filesystem cache. #123435 (Alexey Milovidov). - The symbolized stack trace of a failed query is now built only when the error message will be logged or the trace will be stored in
system.query_log. Previously each failingclickhouse-localinvocation built the symbol index of the whole binary to produce a string that was then discarded. #120660 (Groene AI). - Reduces the CPU overhead of the workload scheduler thread by updating the
system.schedulerintrospection metrics more cheaply. A saturated scheduler can now serve about 15% more resource requests per second. #121958 (Sergei Trifonov). - PromQL now copies label matchers across binary operators for the labels the operator matches series by, so
b / on(job) a{job="x"}reads only the matching series ofb. As in Prometheus, duplicate left series of a one-to-one match in a group the right side does not have no longer fail the query. The new settingpromql_push_down_label_matchersturns this off. #122972 (Valery Petrov). #125267 (Groene AI). - Accelerate exact PromQL label matching on
TimeSeriestables with a text index on thetagsmap. #120083 (Nikita Mikhaylov). - Use more compact codecs for generated
timestampandvaluecolumns in the samples and recent samples tables of theTimeSeriesengine:Delta,T64, andZSTD(3)fortimestamp, andALPplusZSTD(3)forvalue. #120454 (Nikita Mikhaylov). - Reduce memory usage of the
timeSeries*ToGridaggregate functions. #124773 (Valery Petrov). - Filtering and sorting are now faster: the helpers that build filter masks, count filter bytes, and check for an identity permutation use AVX2 or AVX-512 on x86 instead of SSE2, and are vectorized on ARM where they were not. #121403 (Raúl Marín).
- Faster filtering of numeric columns on ARM (up to 1.28x) and on AMD Zen 4 (up to 2.8x), speeding up queries with
WHEREand multi-stepPREWHERE. #122893 (Raúl Marín). - Filters on numeric columns that keep few rows are faster. #124024 (Raúl Marín).
- Filtering numeric columns no longer over-allocates the result buffer (by up to 2x) when the size of the result is known in advance. Closes #123546. #123576 (Raúl Marín).
- Vectorized comparisons of
UUID,IPv4, andIPv6columns with columns or constants of the same type, which makes such comparisons several times faster. Comparisons ofFixedString(16)values are now branchless too, making them faster when it is unpredictable whether the values are equal. #120193 (Manuel). - Comparisons
<,>,<=, and>=ofIPv6andFixedString(16)values are 1.4 to 1.8 times faster on CPUs with AVX-512. #125151 (Groene AI). LIKE,ILIKE,match, and their variants are faster when the pattern is not a constant, up to 5 times with 8 threads. #122764 (Groene AI). #122843 (Samuel Krempaský).- Faster
multiMatchAnyand related functions with non-constant needles whenreject_expensive_hyperscan_regexpsis disabled. #122842 (Samuel Krempaský). CASTof strings toNullable(Bool)(alsoaccurateCastOrNull(s, 'Bool')andtoBoolof aNullable(String)) is up to 7 times faster with 8 threads, andarrayIntersect,arrayUnion,arraySymmetricDifference, andarrayJaccardIndexover non-numeric elements such asDateTime64,UUID, orTupleare up to 18 times faster with 8 threads: they no longer allocate memory and update profile events for every row.multiMatchAnyand the other multi-regexp functions with non-constant needles now add their cache hit and miss counts once per block. #122920 (Groene AI).- Speed up extracting a value from a
MapwithLowCardinalitykeys. The key is now resolved to its dictionary position once instead of being compared against every entry of a row, so the cost ofm[key]no longer grows with the position of the key in the row. Also fix extracting a value from aMapwhose key isNaN, or holds aNULLinside a composite key: such a key used to compare equal to every other key. #120453 (Pavel Kruglov). L2DistanceTransposed,cosineDistanceTransposed,dotProductTransposed, and their...Quantizedvariants with precision1are now computed directly from the packed sign bit plane with per-byte lookup tables, 2 to 3 times faster than before. The new settingqbit_one_bit_symmetric_distanceadditionally reduces the reference vector to its signs and derives the result from the Hamming distance between the two sign vectors, computed with XOR and popcount, which is up to 10 times faster. #120594 (Alexey Milovidov).- Speed up
randomHadamardTransformand vector quantization for vector dimensions of the form 2^k × 12 or 2^k × 20, such as 768 or 1536, on x86 with AVX2: 1.9x to 2.5x higher throughput and 50% to 60% lower median latency. #120874 (Jingxin (Philip) Li). hasAllandhasAnyon integer arrays use SIMD on both x86 and ARM, includingNullablearrays andhasAny, which previously used a scalar loop.hasAnyis up to 15x faster, andhasAllbecomes several times faster on ARM. #123420 (Groene AI).hasAnyoverArray(String)looks each element up in a hash set, instead of comparing it with every string, when its second argument is a constant array of four or more strings of up to 256 bytes and a block has enough rows to pay for building the set. With 32 strings this uses 87% less CPU. Closes #122333. #122507 (Groene AI).- Vectorize
leastandgreatestforNullablenumeric arguments and for three or more numeric arguments, andclampfor numeric arguments. These cases were previously evaluated row-by-row and are now 3-7 times faster. #109783 (Manuel). - Speed up
round,roundBankers,floor,ceil, andtruncwith a scale argument onFloat32andFloat64columns by using AVX2 on x86 instead of SSE4.1, and speed up rounding of integers narrower than 64 bits on ARM by vectorizing it. #122032 (Raúl Marín). moduloandmoduloOrNullof two unsigned integers of different widths are faster again, as before 26.9, when the wider one isUInt128(about 3 to 4 times, for exampleUInt128 % UInt16) or the dividend isUInt256(1.6 to 2 times). #123170 (Groene AI).exp10is up to 2x faster by splitting its argument withtruncinstead of themodflibrary call, with bitwise-identical results. #122263 (Konstantin Bogdanov).- Speed up
entropyand multi-argumentuniqExacton short strings by optimizingSipHashfor short inputs. Hash values are unchanged. #123658 (Groene AI). sumMap,minMap,maxMap,sumMapWithOverflow, andsumMapFilteredover arrays are up to 2.3 times faster for integer,Enum,Date,Date32, andDateTimekeys. #124340 (Groene AI).h3PolygonToCellsandh3PolygonToCellsWithContainmentare several times faster on polygons much smaller than a cell (9x on the query from the issue). This bringsh3PolygonToCellsback to the speed it had on such polygons before 26.8.12 and 26.9. Closes #123877. #123911 (Groene AI).isValidUTF8validates aStringorFixedStringcolumn with onesimdutfcall over the whole column instead of one call per row, which makes it up to 2.8 times faster on short strings. #123835 (Groene AI).- Speed up
lowerUTF8andupperUTF8on text whose non-ASCII characters are mostly two-byte UTF-8 (U+0080toU+07FF, e.g. Latin-1, Greek, Cyrillic): the column is processed in one pass, these characters are mapped from a table built from ICU, and ICU is called only for the rest of a row that contains other characters. #123867 (Groene AI). lower,upper, and the ASCII path oflowerUTF8andupperUTF8are now faster by using AVX2 or AVX-512 depending on the CPU. #121374 (Manuel).- Speed up
lengthUTF8and otherUTF-8functions on long strings by counting code points 64 bytes at a time, on both x86 and ARM. #122049 (Raúl Marín). - Fixed ARM performance regressions in
indexOfwith a constant needle and in text output formats over non-ASCII strings. Closes #123338. Closes #123346. #123377 (Raúl Marín). - UTF-8 string functions such as
substringUTF8are faster on long ASCII strings on CPUs with AVX-512. #120088 (Minh Vu). - Improved performance of functions
extractKeyValuePairsandextractKeyValuePairsWithEscaping. #119361 (Anton Popov). - Function
mortonEncodenow resolves the type of each argument and the ratios of a constant range mask once per block instead of once per row, which makes it up to 2x faster. #123354 (Groene AI). - Speed up
mortonDecodeon AArch64 by decoding with compile-time shift-and-mask sequences instead of a lookup table. The output is unchanged on every architecture. #116205 (Groene AI). encryptandaes_encrypt_mysqlare faster on values shorter than 16 bytes in theaes-*-ecbandaes-*-cbcmodes (up to 2x forencryptwithaes-128-ecb). #124103 (Groene AI).- Speed up
hexandunhexwith optimizedAVXandAVX2implementations when they are available. #123511 (Alexey Milovidov). - Faster
toMillisecond,toMicrosecond, andtoNanosecondonDateTime64. #122852 (Samuel Krempaský). - Speed up
reverseforStringandFixedStringvalues. #119462 (Minh Vu). arrayDistinctis faster: it now does a single hash-table lookup per element instead of two, andDecimalarrays use a specialized fast path. #113966 (Manuel). #121646 (Minh Vu).- Specialize
hasandindexOfsearches in non-nullable numeric arrays when the needle is constant. #119090 (Minh Vu). arrayFilteris faster when the lambda keeps all or none of the elements of a block. #119816 (Minh Vu).- Improve performance of
bitmapAndCardinality,bitmapOrCardinality,bitmapXorCardinality,bitmapAndnotCardinality, andbitmapHasAnyforUInt64andInt64bitmaps, which previously had to materialize the intersection to compute the result. On AArch64,bitmapAndCardinality,bitmapOrCardinality,bitmapXorCardinality, andbitmapAndnotCardinalityno longer hit a rare code-layout-dependent slow path. #120615 (Ashish kumar choubey). #123675 (Groene AI). - Restored the existing
Decimalfast paths inarrayCompact. #121245 (Minh Vu). uniqUpTonow stops hashing after it exceeds its threshold. #121247 (Minh Vu).- Restored the
FixedStringfast path forarrayEnumerateUniqandarrayEnumerateDense. #121338 (Minh Vu). arrayReverseis now faster forDecimaland wide integer arrays. #121342 (Minh Vu). #121644 (Minh Vu).- Avoid copying
Stringcolumns forsubstring(s, 1). #119820 (Minh Vu). - Skip KMP preprocessing for impossible
hasSubstrsearches. #119824 (Minh Vu). - Speed up
arrayMinandarrayMaxforDecimalandDateTime64arrays. #123507 (Minh Vu). - Speed up
arrayUniqforDecimal32,Decimal64, andDecimal128arrays. #122121 (Minh Vu). - Allow a single condition to constrain multiple key columns during index analysis. For example, if the primary key is
(toYYYYMMDD(dt), toDate(dt), dt)and the query hasWHERE dt >= toDateTime('2026-01-10 00:00:00'), all three key columns are now used for pruning, instead of only one of them as before. This behavior is controlled by the settinganalyze_index_with_multiple_key_columns_per_condition(enabled by default). #96225 (Nihal Z. Miaji). - Left-side columns absent from a hash join’s output (for example the join key in
SELECT count() ... LEFT JOIN ...) are now pruned when only a spill threshold is set, as with the defaultmax_bytes_ratio_before_external_join, instead of being carried through the pipeline. #108191 (Groene AI). - Joins on null-safe comparison (
<=>) of nullable keys use fixed-width hash keys instead of a serialized tuple. #120596 (Manuel). - Fixed a quadratic slowdown of
JOINwithjoin_algorithm = 'hash'whenONhas a non-equality condition or severalORconditions. #121209 (nt). - Faster parsing of floating-point numbers from text formats. Update
fast_floatto v8.3.2. #121383 (Actuele AI). - Query plan optimizations can now use the sort order reported by any table engine, not only
MergeTree, avoiding unnecessary sorting. #121858 (Ivan Zhukov). - Slightly reduce the per-block overhead of aggregation by not copying the columns of the block when preparing the aggregate function instructions. #124819 (Alexey Milovidov).
GROUP BYby several keys, which requires the serialization of keys, serializes the keys of a block in chunks that fit in the CPU cache instead of all at once. This makes such queries faster when many threads are used, for example, ClickBench Q18 is 37% faster on a 96-core machine. #124955 (Alexey Milovidov).- Added the setting
cluster_function_wait_for_replica_ms(default0, disabled), which lets cluster table functions wait for the replica assigned a file to connect before giving that file to another replica. This improves file distribution when replicas start at different times. Work stealing now takes files from the active replica with the most remaining bytes without scanning all unprocessed files. #125611 (Konstantin Vedernikov). - The
SLRUfilesystem cache policy now moves a partially downloaded file segment to the protected queue on a cache hit, as it does for a fully downloaded one. Before, a scan could evict the data of narrow reads from the probationary queue. #125657 (Sema Checherinda).
Improvement
- Lightweight updates (the
UPDATEstatement and patch parts) are now generally available instead of Beta. Theenable_lightweight_updatesetting is now in the production feature tier. #125719 (Alexey Milovidov). - Cluster discovery is no longer experimental: clusters with a
discoverysection inremote_serverswork without enablingallow_experimental_cluster_discovery. The setting is now obsolete. #123917 (Alexey Milovidov). - The Kusto (KQL) and Trino query dialects were promoted from experimental to beta. They are still enabled with the
allow_experimental_kusto_dialectandenable_trino_dialectsettings. #124750 (Alexey Milovidov). - Tables and databases can now be addressed through URL paths in the HTTP interface by default:
curl http://localhost:8123/my_db/my_table.csvnow works without extra configuration. The settingshttp_allow_path_requests,http_allow_database_as_path,http_allow_table_as_file, andhttp_allow_filters_as_pathare enabled by default;http_allow_filters_as_unrecognized_url_parametersstays disabled. #121143 (Alexey Milovidov). - The
all_...union tables over the system log tables (system.all_query_log,system.all_text_log, and so on) are now created by default: the default server configuration enables thecreate_union_system_log_tablessection withmerge_rotated_tables, so queries over the rotated versions of a log no longer have to remember constructs likemerge(system, '^query_log'). Theclustersetting is shown as a commented-out example, because the table definitions would reference the cluster and require it to exist. #117943 (Alexey Milovidov). - In a
DataLakeCatalogdatabase withallow_experimental_iceberg_compaction = 1, onlyIcebergtables are now cached.DeltaLakeandPaimontables no longer keep the first schema they saw, soSELECT *andDESCRIBEpick up added columns without recreating the database or restarting the server. Closes #122548. #122568 (Groene AI). - The background memory worker now corrects the global memory tracker from real memory usage on every tick (server setting
memory_worker_correct_memory_tracker, enabled by default). Previously the tracker was a pure counter that was re-baselined only at startup and when it went negative, so upward accounting drift was permanent: servers were observed refusing every query withMEMORY_LIMIT_EXCEEDED, reporting more than 100 GiB in use while actually using 7 GiB, until restart. The drift itself remains visible as the difference between theMemoryTrackingUncorrectedandMemoryTrackingmetrics. #118094 (Alexey Milovidov). - The AI function per-query quotas are now disabled by default:
ai_function_max_input_tokens_per_query,ai_function_max_output_tokens_per_query, andai_function_max_api_calls_per_querydefault to0, meaning no limit. To keep the previous caps, set the three settings explicitly or usecompatibility = '26.9'. #121424 (George Larionov). - Named
Tuplecolumns inPrettyformats are now displayed as subcolumns, with the element names shown in additional header and footer lines. Controlled by the new settingoutput_format_pretty_named_tuples_as_subcolumns(enabled by default). A named tuple rendered inside one cell, for example nested in anArrayor when the setting is disabled, is still displayed according tooutput_format_pretty_named_tuples_as_json. #78927 (Engel Danila). - Show the query result in
Prettyformats as soon as it arrives. Previously a query that returns a few rows early and then keeps reading, such asSELECT DISTINCTover a large table, displayed nothing until it finished or was cancelled. A later fix prevents a background write error after the query has finished from surfacing as a lateLOGICAL_ERROR. #117005 (Alexey Milovidov). #125028 (Groene AI). - Display non-printable control characters as Unicode “Control Pictures” in the
VerticalandPretty*output formats by default, so they are no longer silently swallowed and no longer deform the table.TAB, the line feed, andESCare excluded, because a terminal interprets them rather than swallowing them. The new settingoutput_format_pretty_display_control_characterscan be disabled to restore raw-byte output. #101774 (Yash ). - Expired authentication methods are now removed from a user automatically. Every
ALTER USERdrops the authentication methods whoseVALID UNTILdeadline has already passed and keeps all the others, so short-lived credentials can be rotated indefinitely withALTER USER ... ADD IDENTIFIED WITH ... VALID UNTIL ...without the expired ones accumulating againstmax_authentication_methods_per_user. A method added by the same statement is not affected, and a user whose every method is expired keeps them rather than being left with no way to authenticate. #118880 (Alexey Milovidov). - On
ReplicatedMergeTree, the sync value3(mutations_sync,lightweight_deletes_sync,alter_sync) now waits for the active replicas, as documented, instead of all of them, so an inactive replica no longer causesUNFINISHED. This also affectsOPTIMIZE,TRUNCATE,DROP/DETACH PARTITION,REPLACE PARTITION, andMOVE PARTITION TO TABLE. #120592 (Nikolay Degterinsky). - A number written directly as the first argument of
CASTis now read with the target type when that type reads it more precisely than the number itself carries it, such as aDecimalor an integer wider than 64 bits.Nullable,Array, andLowCardinalityof those types take the same exact path. #116043 (Alexey Milovidov). TTL ... GROUP BY (a, b, c)is now accepted and means the same asTTL ... GROUP BY a, b, c, matching howORDER BY (a, b, c)works. Previously the parenthesized form was rejected withTTL Expression GROUP BY key should be a prefix of primary key. #118426 (Alexey Milovidov).sequenceMatch,sequenceCount, andsequenceMatchEventsnow accept aDateTime64timestamp instead of failing. Events are ordered at the column’s full precision, so two events within the same second are no longer ambiguous. #118427 (Alexey Milovidov).argMinandargMaxnow consistently return the value from the first row among rows with the same minimum or maximum within a block, matchingargMinIfandargMaxIf. #122892 (Raúl Marín).- Added the setting
analyzer_compatibility_allow_cte_redefinition. When enabled, a CTE name may be defined more than once in a singleWITHclause; a later definition shadows the earlier one as the query analysis before 24.3 did.MATERIALIZEDCTEs and CTEs inWITH RECURSIVEcannot be redefined. #121623 (Dmitry Novik). - Added settings
semi_join_include_columns_from_both_sidesandanti_join_include_columns_from_both_sides(enabled by default) forSEMIandANTIjoins in the analyzer. When enabled, behavior is unchanged: columns from both sides are accessible after the join. Disable either setting to enforce SQL-standard semantics, where only the preserved side’s columns are visible after the join. #96662 (Zhang Yifan). - The setting
aggregate_function_input_formatwith the valuesvalueandarraynow works in every input format, includingRowBinary,Native, andParquet, and forAggregateFunctionnested inArray,Tuple, andMap. In the JSON formats the value is now a JSON value, for example{"x": [1, 2, 3]}, not a string containing it. #121120 (Alexey Milovidov). - Compression codec names and their keyword arguments are now matched case-insensitively, so
CODEC(zstd)works likeCODEC(ZSTD)andALP(std)likeALP(STD). Previously a codec whose name is mixed-case, such asDelta,DoubleDelta,GorillaorQuantized, could not be used in thedefault_compression_codec,marks_compression_codecandprimary_key_compression_codecsettings, nor in the<compression>section of the server configuration, because those paths upper-cased the codec name. #119313 (Alexey Milovidov). - Added aliases
allow_suspicious_indexes,ignore_data_skipping_indexes,force_data_skipping_indexes, andsecondary_indexes_enable_bulk_filteringfor the settings spelled withindices, so both plural forms are accepted. #122565 (Mohammed Sohail). APPLY (f, 'prefix')now keeps the table qualifier in generated column names. #122702 (Groene AI).- Async insert now supports eligible single-block local
INSERT ... SELECTqueries, with synchronous fallback for larger, multi-block, empty, transactional, or non-parallel-quorum inserts. #111663 (Mikhail f. Shiryaev). - Added the opt-in
optimize_row_order_if_no_order_bysetting forMergeTreetables with an empty sorting key (ORDER BY ()/ORDER BY tuple()). When enabled, it applies row-order optimization automatically to inserts into such tables. #104591 (Alexey Milovidov). WHATIFcan now estimate hypothetical projections without reading the whole table: pastmax_rows_to_scanrows it estimates from a sample of granules and reports the resulting range inmarks_span,max_rows_to_readlowers that budget, and it follows(prefer|force)_optimize_projection. It now also uses the real projection-optimizer weighing logic, so its verdicts, reasons, and pruned ranges track the optimizer more closely. #118233 (Yarik Briukhovetskyi). #121766 (Yarik Briukhovetskyi). #122060 (Yarik Briukhovetskyi). #123540 (Yarik Briukhovetskyi). #123587 (Yarik Briukhovetskyi).- Added the setting
parallel_replicas_for_queries_with_multiple_tables(defaulttrue) to control whether parallel replicas are used for queries joining multiple tables. When disabled, parallel replicas are not used for queries withJOIN, where the non-leftmost side is read in full on every replica. The setting does not affect aUNIONquery without aJOIN, where each branch is an independent single-table read, norARRAY JOIN. #76595 (Igor Nikonov). max_joined_block_size_rowsandmax_joined_block_size_bytesnow also bound the result blocks ofparallel_hashandgrace_hashjoins: squashing of the join output no longer merges blocks past these limits. Closes #124198. #124304 (Groene AI).- Added the setting
query_plan_filter_push_down_below_limit_by(default1), controlling whether filters onLIMIT BYkey columns are pushed below theLIMIT BYstep. Setting it to0restores the plan shape used before 26.7, for queries where the pushed predicate makes index analysis costlier than the scan it saves. #121675 (Groene AI). - Added the
use_aggregation_memory_trackersetting to choose howGROUP BYmeasures memory when deciding on two-level aggregation.compatibilitybelow26.9restores the measurement used before 26.7. #124439 (Hechem Selmi). system.query_logandsystem.processesnow report the metrics of each task of a distributed query plan (make_distributed_plan = 1) in a row of its own: a task is a secondary query with its ownquery_id, correlated to the statement that started it byinitial_query_id. The initiator’s row reports its own work instead of the volume its tasks read. #120949 (Groene AI).system.query_lognow records the databases, tables, and columns read by a replica that executes a query plan shipped to it, which happens withparallel_replicas_plan_based. #122657 (Igor Nikonov).- Queries with
send_logs_levelnow also forward text logs from statelessmake_distributed_planworkers through the coordinator, so worker-side exception context reaches the client. #118603 (Antonio Filipovic). - The setting
parallel_replicas_insert_select_local_pipelineis obsolete. It was a workaround for a performance problem fixed in 25.5, and it duplicatedparallel_replicas_local_plan, which already decides whether the initiator reads its own share of a distributedINSERT SELECT. Useparallel_replicas_local_plan = 0to leave all the reading to the remote replicas. #121653 (Igor Nikonov). - Distributed
SELECTqueries now emit one OpenTelemetry span per remote shard read, with attributes such asclickhouse.cluster,clickhouse.shard_num,clickhouse.processed_stage,clickhouse.query_id,clickhouse.initial_query_id, andclickhouse.target_host, so slow or failed shards can be identified directly fromsystem.opentelemetry_span_log. #115784 (Diego Gomes Tomé). - Reads with parallel replicas are now covered by OpenTelemetry spans: a summary span with the totals of the coordination, one span per announcement and per read request handled by the coordinator, and
clickhouse.replica_numon the per-replica spans, so the work distribution between replicas can be inspected insystem.opentelemetry_span_log. #118570 (Diego Gomes Tomé). - Added profile events for network activity:
DNSRequests,DNSRequestMicroseconds, andDNSRequestError;DNSReverseRequests,DNSReverseRequestMicroseconds, andDNSReverseError;TLSHandshakes,TLSHandshakeMicroseconds, andTLSHandshakeErrors;TLSServerHandshakes,TLSServerHandshakeMicroseconds, andTLSServerHandshakeErrors; andHTTPServerConnectionsErrors. DNS now exposes timing as well as error counts, and TLS handshakes are now observable. #116136 (Alexey Milovidov). - Added the
AsyncInsertFlushprofile event. Compare it withAsyncInsertQueryto see how many queries are batched into one asynchronousINSERTflush. #120187 (Sema Checherinda). - Add the
RuntimeFilterLookupsBeforeBuildFinishedprofile event, counting blocks that a JOIN runtime filter passed through unfiltered because its build side had not finished yet (for example withjoin_overflow_mode = 'break'and a finitemax_rows_in_join/max_bytes_in_join). #107108 (Groene AI). - Added
last_error_symbolsandlast_error_linestosystem.errorsandsystem.error_log. Closes #74561. #100374 (Narasimha Pakeer). system.processors_profile_lognow has entries for queries that fail with an exception, and new columnsexception_codeandexception. #121503 (Aleksandr Efimov).DROP TABLEandDROP DATABASEnow write aRemovePartevent tosystem.part_logfor every part of the dropped table, as merges,DROP PARTITION, andTRUNCATEalready do. #122093 (Garrett Thomas).- Added the server setting
min_allocation_size_to_log_stack_trace. When a single charge to the global memory tracker reaches it, the stack trace is written to the server log and tosystem.trace_logwith trace typeMemoryLargeAllocation. This helps attribute a global tracked total that has grown far beyond real memory usage, a state in which the server refuses every allocation while far below its limit. Default0keeps it off. #119527 (Groene AI). - Show throttler and workload IO scheduler wait time in the client progress bar (
ThrottlerSleepMicroseconds,SchedulerIOReadWaitMicrosecondsandSchedulerIOWriteWaitMicrosecondsare summed into thewaitedfigure, and the stalled sections of the bar are colored yellow). #118536 (Azat Khuzhin). EXPLAIN ANALYZE time=1shows more information about time and parallelism of every step. #114786 (Kirill Kopnev).- Peak-memory reporting under
EXPLAIN ANALYZEnow accounts for aggregation correctly. #123324 (Azat Khuzhin). - Removed nine unneeded
ProfileEvents: the eight never-incrementedDistributedIndexAnalysisParts,ParallelReplicasDeniedRequests,WasmMemoryAllocated,S3QueueSetFileProcessingMicroseconds,S3QueueSetFileProcessedMicroseconds,S3QueueSetFileFailedMicroseconds,FileSegmentRemoveMicroseconds, andExternalDataSourceLocalCacheReadBytes, plus the duplicateCachedReadBufferPredownloadedBytes, which always matchedCachedReadBufferPredownloadedFromSourceBytes. This reduces per-query memory and bookkeeping overhead; queries and dashboards should useCachedReadBufferPredownloadedFromSourceBytes. #123040 (Raúl Marín). #123042 (Raúl Marín). - Killing a query that is loading skip-index marks from object storage now stops the read promptly: the remote read path checks query cancellation before each buffer fill, instead of reading on for minutes after the query was already cancelled. #113436 (Groene AI).
- Reduced cancellation latency for
GROUP BY ... WITH TOTALSqueries:KILL QUERYnow interrupts totals accumulation within a single chunk instead of waiting for all aggregate states to be merged. #119470 (Roman Vasin). KILL QUERYand Ctrl+C inclickhouse-clientnow cancel long-running functions insideWHEREandHAVINGfilters instead of waiting for the function to finish. #112705 (Alexey Milovidov).KILL MUTATION,SYSTEM STOP MERGES,DETACH/DROPof a table,REPLACE/ATTACH PARTITION ... FROMand server shutdown now stop a running mutation within a fraction of a second when the mutation’s predicate has anIN (subquery)whose subquery works without reading new data (for example a cross join). Previously they waited until the whole set was built, andREPLACE/ATTACH PARTITION ... FROMgave up withTIMEOUT_EXCEEDEDafter 120 seconds.KILL MUTATIONnow also stops a mutation that is already writing its new part. #124122 (Groene AI).KILL QUERYandmax_execution_time(with the defaulttimeout_overflow_mode = 'throw') now interrupt writing theParquetformat in the middle of a block that is split into many row groups (for example with a smalloutput_format_parquet_row_group_size), instead of only after the whole block is written. #125489 (Groene AI).DROP TABLE,DETACH TABLE, server shutdown, andALTER TABLE ... MODIFY SETTING refresh_statistics_intervalno longer wait for a background refresh of the statistics cache of aMergeTreetable to read every part. On object storage with thousands of parts this wait could take minutes per table and delay a restart. Closes #125136. #125165 (Groene AI).DROP TABLEand other operations that cancel merges and mutations no longer wait for an in-progressvector_similarityindex build to finish. #123062 (Raúl Marín). #123739 (Raúl Marín).KILL QUERY WHERE query_id = '<id>'now cancels the caller’s own query without requiringSELECTonsystem.processes. For a caller holding neither that grant norKILL QUERY, an id that is not running as them cancels nothing and returns no rows. Any otherWHEREcondition keeps requiring the privileges it requires today. #117999 (Groene AI).- Access to
system.jemalloc_profile_text,system.jemalloc_sampled_allocations,system.jemalloc_bins,system.jemalloc_arena_bins, andsystem.jemalloc_statsnow requiresSYSTEM_JEMALLOC; the heap profiles flushed bysystem.jemalloc_profile_textandsystem.jemalloc_sampled_allocationsare also removed after being returned. #121622 (Azat Khuzhin). #121634 (Azat Khuzhin). - Added the
access_control_improvements.readonly_restricts_set_roleserver setting,falseby default. When enabled,SET ROLEis refused withREADONLYin a session or query whosereadonlysetting is not zero. PreviouslySET ROLEwas the only identity-changing statement thatreadonlydid not refuse. #118021 (Groene AI). - Secret arguments of table functions, table engines, database engines, backup engines, and dictionary sources are now declared next to each feature and are masked consistently in
SHOW CREATE, system tables, query logs, andEXPLAIN AST, instead of relying on a central hardcoded parser list. #123364 (Raúl Marín). - The
PostgreSQL,MaterializedPostgreSQL,DataLakeCatalog,Cluster,Remote, andHDFSdatabase engines key the exemption for the server’s replay of its own stored metadata on the metadata loader instead of on the query being internal. AHDFSdatabase restored withRESTORE DATABASEis now checked againstremote_url_allow_hosts. #120280 (Alexey Milovidov). - Allow
remote_url_allow_hoststo match the bucket name of anS3URL. #124453 (Konstantin Vedernikov). - Support proxy credentials in the
http_proxyandhttps_proxyenvironment variables. Previously the userinfo part of the proxy URI was discarded, so ClickHouse could not use an authenticating proxy. Proxy credentials are sent only to the proxy, rather than to the target server inside aCONNECTtunnel. #123069 (Akanshaak). #124396 (Alexey Milovidov). - Interserver authentication failures on a listener that uses the PROXY protocol now record the client address from the PROXY header in
system.session_logwhenauth_use_forwarded_addressis enabled, instead of the proxy address. #125326 (Groene AI). - Added the
tcp_with_proxy_allow_interserver_modeserver setting, which allows disabling the native protocol’s interserver mode ontcp_with_proxy_port. #123188 (Pradeep Chhetri). - Reject unexpected packets in the native protocol before deserializing their payload, avoiding unnecessary processing of data types and aggregate function states before returning
UNEXPECTED_PACKET_FROM_CLIENT. #119368 (Alexey Milovidov). - Added the setting
kill_throw_if_noop, enabled by default, which makes localKILL QUERYandKILL MUTATIONstatements throwNO_QUERY_TO_KILLwhen their selection produces no eligible target.ON CLUSTERexecution remains tolerant of empty matches. Setkill_throw_if_noop = falseto preserve the previous behavior. Related #83348. #85023 (zwy991114). - Merges and queries on
S3disks no longer hold one HTTP connection per open stream for their whole duration once connections are scarce. Previously this let a few merges of tables with many substreams, for example aJSONcolumn, saturatedisk_connections_hard_limit, stall each other, and fail every other request to the disks withHTTP_CONNECTION_LIMIT_REACHED. Once theDiskconnection group is at or abovedisk_connections_soft_limit, reads fromS3disks fetch each buffer fill with a separate request and return the connection to the pool between fills; the new profile eventReadBufferFromS3RequestsCutcounts such requests. #119730 (Alexey Milovidov). #124701 (Groene AI). - The
filesystem_cache_boundary_alignmentsetting can now be changed per query. For disk reads,0means to use the cache configuration’sboundary_alignment; for non-disk reads,0still disables alignment. #118791 (Kseniia Sumarokova). - Added the filesystem cache setting
use_real_disk_size(disabled by default), which accounts for cache reservations in filesystem allocation units instead of raw bytes. It makesFilesystemCacheSize, eviction-size metrics, andcurrent_sizeinsystem.filesystem_cache_settingsapproximate the disk footprint. The accounting is block-aligned rather than exact and can include reserve-ahead bytes of in-flight reads. #79490 (codeworse). - Custom HTTP headers configured for S3 are now handled case-insensitively by name, so a header spelled
X-Amz-Meta-Fooreaches Google Cloud Storage translated tox-goog-meta-foo, asx-amz-meta-fooalready did. #120014 (Sema Checherinda). - Better error messages for S3 request retries: the HTTP response code is no longer printed as
18446744073709551615when the request received no response at all, and the misleading message about a possible time skew is no longer printed on every retry. #118439 (Alexey Milovidov). - Allow
DESCRIBE FILESYSTEM CACHEon the introspection port. #115894 (Groene AI). - Files on encrypted disks now support positional reads, so a table with a
UNIQUE KEYon an encrypted disk can be loaded again after a server restart. #119991 (johnjing). - The
urltable function and theURLtable engine now expand glob patterns lazily instead of materializing every address before the query starts.glob_expansion_max_elementsnow limits how many addresses a query actually generates rather than how large the pattern is, so a query that stops early - for example under aLIMIT- can use a pattern that describes far more addresses than the limit. #115680 (Alexey Milovidov). Icebergmanifest writing now uses sequence-number inheritance:ADDEDentries haveNULLsequence_numberandfile_sequence_numberunless compaction assigns an explicit sequence number. #120031 (Asya Shneerson).Icebergmanifest statistics are now written forbooleanandfixedcolumns. #121548 (Konstantin Vedernikov).- When a table is created through a catalog,
CREATE TABLE catalog.table ENGINE = IcebergS3can now omit explicit credentials and reuse the catalog credentials. #114477 (Konstantin Vedernikov). ALTER TABLE ... EXECUTE expire_snapshotsnow works forIcebergtables in transactional catalogs such as Iceberg REST and Unity. #123248 (alesapin).- A
DataLakeCatalogdatabase whose catalog cannot be built no longer reports its tolerated table-listing failure as an error of the query that enumerated it: the skipped database is now logged atdebuginstead oferror, so a query such asSELECT ... FROM system.tablesorsystem.iceberg_historyno longer sends a server-side exception to a client whosesend_logs_levelincludeserror. Setshow_data_lake_catalogs_in_system_tables = 1to have the real exception raised instead. #121475 (Groene AI). - When a
DeltaLakewrite commit fails, ClickHouse now always reports the commit error rather than an error raised while removing the data files the failedINSERThad already uploaded, and every removal that fails during that cleanup is logged with the path it was left on. Previously the first failing removal replaced the commit error in the response, so the reason nothing was written was lost and no path was logged. Closes #122023. #122123 (Groene AI). - Reading an
Icebergtable whose position delete file has noposorfile_pathcolumn now fails withICEBERG_SPECIFICATION_VIOLATIONnaming the file and the missing column, instead of aLOGICAL_ERROR(missingpos) or a misleadingUNKNOWN_IDENTIFIER(missingfile_path). #123583 (Groene AI). PaimonBOOLEANcolumns are now read asBoolinstead ofInt8, matchingIcebergandDeltaLake.DESCRIBEandtoTypeNamenow reportBool, and text formats render the values asfalseandtrueinstead of0and1. #119404 (JIaQi Tang).- Avro files now include per-column size statistics in their metadata. #121392 (Konstantin Vedernikov).
- The
Parquetreader now rejects a column chunk whose metadata has a negativenum_values,total_uncompressed_size, orunencoded_byte_array_data_byteswithINCORRECT_DATAinstead of failing later with a misleading memory-allocation error. It also caps memory estimates derived from these fields at the reader’s watermarks and ignores pre-allocations too large to ever succeed, so absurdly large values no longer cause an internal error. Closes #124224. #124330 (Groene AI). - Bumped the bundled
ORClibrary so that anORCfile declaring a compression codec the reader does not implement is rejected with an error naming the codec, instead of an internal error that debug and sanitizer builds treat as a failed assertion. #115889 (Groene AI). INSERT ... VALUESover a stream that fails mid-row now reports that read failure directly, instead of retrying the failed read while recovering from a parse error. This affects an HTTP request body that is shorter than its declaredContent-Lengthand is streamed to the input format. #121916 (Groene AI).- ClickHouse Keeper no longer drops the client session when the outgoing request queue stays full for longer than
operation_timeout_ms. The enqueue wait is now three timessession_timeout_ms, so a short burst of backpressure no longer invalidates the session’s ephemeral nodes and watches. #121559 (Kseniia Sumarokova). - ClickHouse Keeper now reports orphaned nodes in a snapshot as
CORRUPTED_DATAinstead of an opaque internal error. Withkeeper_server.remove_orphaned_nodes_on_startup = trueandkeeper_server.digest_enabled = false, it can also remove those nodes during startup so the snapshot still loads. #95761 (Seva Potapov). - The Keeper
rcfgcommand now honors itsretrycount per action, stops oncemax_total_wait_time_msis exhausted, and rejects a negativeretrybefore running any action. #122758 (Groene AI). - Updated
NuRaftto fix handling of abandoned peers when a removed server rejoins. #120736 (Antonio Andelic). - Added the setting
get_zookeeper_lock_acquire_timeout_msso Keeper-backed queries such as reads fromsystem.zookeeper,zookeeperSessionUptime, andSYSTEM RECONNECT ZOOKEEPERcan fail fast while another thread is reconnecting Keeper. #94836 (c-end). - Activating a replica whose
activeoris_activenode inKeeperis still held by another session is now reported asREPLICA_ALREADY_EXISTSinstead ofLOGICAL_ERROR, so it no longer aborts the server in debug and sanitizer builds. The same applies when that node is rewritten while it is being removed. #114408 (Groene AI). - The ZooKeeper client, the Graphite metrics writer, the Redis source,
system.zookeeper_info, the distributed query exchange, and host names inlisten_hostandbind_hostnow resolve through the ClickHouse DNS cache, so these lookups are cached, visible insystem.dns_cacheand subject todns_allow_resolve_names_to_ipv4anddns_allow_resolve_names_to_ipv6. Previously they resolved names on their own, bypassing the cache. #120831 (Alexey Milovidov). - Added the
http_x_clickhouse_format_overrides_output_formatsetting (defaulttrue). When disabled, theX-ClickHouse-FormatHTTP header only setsdefault_format, as it did before 26.8, instead of overriding a query’sFORMATclause viaoutput_format. #121132 (Alexey Milovidov). - The Prometheus HTTP API accepts
RFC3339times withZor a+hh:mmoffset and fractional seconds intime,start, andend, as Prometheus does, so clients like vmalert work. String time arguments ofprometheusQuery,timeSeriesSelector, and thetimeSeries*ToGridfunctions acceptRFC3339too. #122808 (Valery Petrov). - PromQL regex matchers that list plain literals, such as
{job=~"api|web"}, now use the primary key and return exactly the listed values, as in Prometheus. Before, only the first alternative was anchored at the start and only the last at the end, so such a matcher also returned values likeapi-serverormyweb. #122796 (Valery Petrov). - PromQL instant queries now return series in a deterministic order:
topkandbottomkat the root are sorted by value, as Prometheus returns them, and other instant queries are sorted by their labels, like range queries, so repeated requests list the series in the same order. #122347 (James Cunningham). #122976 (Valery Petrov). /api/v1/format_queryand PromQL serialization now print durations in Prometheus units, sosum(rate(x[5m]))formats as itself rather than assum(rate(x[300])). #120939 (Valery Petrov).- PromQL now validates label names in
label_joinandlabel_replace. #118190 (Minh Vu). - A Prometheus remote-write or remote-read request whose body cannot be decompressed is now answered with
400instead of500, and the error names the size of the block and the uncompressed length it declares. #120938 (Valery Petrov). - Added the
merge_selector_min_age_to_disable_right_tail_heuristicMergeTreesetting. It lets theSimpleandStochasticSimplemerge selectors include small parts at the right end of a range in merge candidates once every part in the range is old enough. #122638 (Alexey Milovidov). - Added the
MergeTreesettingsmerge_selector_small_parts_min_count,merge_selector_small_parts_threshold, andmerge_selector_small_parts_max_ageto reduce the number of merge operations under rapid small-part insertion by requiring a minimum batch size before merging small fresh parts. #100436 (Amos Bird). - Calculate projections using the query analyzer and reject missing projection columns rather than writing incomplete projection parts. Row policies and
additional_table_filtersforsystem.oneno longer affect projection calculation. #118375 (Alexey Milovidov). ALTER TABLE ... ADD COLUMN ..., MODIFY ORDER BY ...now rejects a new sorting key that uses a subcolumn of the addedDEFAULTorMATERIALIZEDcolumn, and its error message names whether the expression kind isDEFAULTorMATERIALIZEDinstead of always sayingdefault expression. #121873 (GON).- An unresolved name in a column
DEFAULT,MATERIALIZED, orALIASexpression is now reported by the name the user wrote, instead of an internal<column>_tmp_alter<random>alias that appears nowhere in the query and also broke the “Maybe you meant” hint. A sorting, primary, or partition key that contains a nullable column or a constant now names that column or constant. #116871 (Alexey Milovidov). - Web UI: save and load the list of tabs, their queries, and query parameters as a Markdown file. The tab bar is now always shown, and the connection settings always live behind the key button in its corner. #121234 (Alexey Milovidov).
- Web UI: added a
Formatbutton to the query editor, which formats the query withformatQuery. #121652 (Alexey Milovidov). #122477 (Alexey Milovidov). - Web UI: clicking a cell of a
JSONcolumn pretty-prints the value with two-space indentation and syntax highlighting. #118640 (Alexey Milovidov). - The graph view of the Web UI for
EXPLAIN ... graph = 1now follows the light/dark theme instead of always drawing a white canvas with black lines, and its labels use a sans-serif font instead of the Graphviz default. Rendering a graph also works whenplay.htmlis opened as a local file. #116208 (Alexey Milovidov). - In the Web UI, the digits of a long number in the result table are now grouped by a thin gap, as in
1 234 567, instead of an underline. The gap is an empty element, so selecting or copying the number still yields the digits alone. #119839 (Alexey Milovidov). - Show a checkmark on the Play UI result-table copy button for 1.2 s after a cell value is copied to the clipboard. #120617 (yanglongwei).
- In the Web UI, the browser window title of a renamed query tab is now exactly the tab’s name. #122067 (Alexey Milovidov).
- Web UI: when a login last succeeded with an empty password, a stale password autofilled by the browser’s password manager for that server and user is no longer used. #118638 (Alexey Milovidov).
- The schema visualizer now supports hiding and showing table categories by clicking their legend labels, with a Hide all / Show all control. #124963 (Mark Needham).
- The command-line client no longer shows as-you-type hints on a query recalled from the history or otherwise displayed at once, so pressing Up/Down keeps navigating the history until the line is edited. #115065 (Alexey Milovidov).
- The progress bar in
clickhouse-clientandclickhouse-localno longer flickers when the query result is redirected to a pipe or a file. #123549 (Alexey Milovidov). - A bare table name can now use the archive path syntax in
clickhouse-local, soSELECT * FROM 'archive.tar.zst::data.native'reads a file inside an archive, likeSELECT * FROM file('archive.tar.zst::data.native'). The same applies to tables of aURLdatabase with afile://target and of aFilesystemdatabase. #118170 (Alexey Milovidov). - Clean up client output when a web terminal or SSH session is closed during a running query, avoiding spurious write-buffer errors. #125558 (Groene AI).
- A musl-built ClickHouse binary is now self-contained enough to run in a
FROM scratchcontainer image with no extra files: CA certificates are embedded,localhostresolves to loopback even without/etc/hosts, and DNS no longer falls back to the unreachable localhost when/etc/resolv.confis missing. #115389 (Alexey Milovidov). - Hedged requests are now supported on macOS. Previously
use_hedged_requestswas silently ignored on macOS and distributed queries always used non-hedged connections. #119915 (Raúl Marín). - Determine the number of CPUs from the kernel’s sysfs lists instead of the libc, so per-CPU structures and
autothread counts do not depend on the libc’s interpretation of the affinity mask. #118912 (Konstantin Bogdanov). - Workloads created without a parent workload are now allowed; they become children of an implicit root workload, so several workload trees can coexist. #118578 (Sergei Trifonov).
RANDOMIZE FORis now applied on each replica of a refreshable materialized view independently, so a random replica performs each refresh instead of the same one every time. Replicas no longer agree onnext_refresh_time, so the value reported bysystem.view_refresheson one replica is the time that replica would refresh at, not necessarily when the refresh happens. Closes #78410. #112979 (Groene AI).FileLognow reads a file again from the beginning if, at the next read, it is shorter than the offset already read from it (for example afterlogrotatewithcopytruncate), instead of failing every read of the table withCANNOT_READ_ALL_DATAuntil the file grows back to its old size. #123390 (Groene AI).- A relative path in the
FileLogtable engine is now resolved againstuser_files_path, like in thefiletable function, soFileLog('nginx/', 'JSONEachRow')reads<user_files_path>/nginx/. A relative path that already points insideuser_files_pathfrom the server’s working directory keeps its meaning. #123397 (Groene AI). - Connections from the
MongoDBtable engine, table function, and dictionary source now identify themselves to the MongoDB server with the ClickHouse name and version in the driver handshake metadata. MongoDB operators can tell ClickHouse connections apart from other clients in server logs,currentOpoutput, and monitoring tools. #122205 (bisht2050). - Lookups of
YTsaurusdictionaries can now be throttled. #100044 (MikhailBurdukov). - AI functions using the
openai,huggingface, orteiprovider send the query ID and the initial query ID in theX-ClickHouse-Query-IdandX-ClickHouse-Initial-Query-IdHTTP headers. #123622 (George Larionov). aiFilternow requests structured JSON Schema output. #121526 (Andrew Wilkins).- WebAssembly UDF calls with
ABI BUFFERED_V1now measure the whole input batch instead of one serialization per row, so usage is priced by the stream the guest actually receives for formats whose cost is not additive across rows. #118989 (Vasily Chekalkin). - Allow the
ON CLUSTERclause forRENAME TABLEandEXCHANGE TABLESon aReplicatedor CloudShareddatabase when the cluster name matches the database’s automatic cluster name. The clause is treated as a no-op and the database engine propagates the DDL as usual, which lets scripts written for non-Replicateddatabases be ported without rewritingON CLUSTERclauses. #106192 (Groene AI). - Stored HTTP handler queries no longer break when a request supplies
max_parser_depth,max_parser_backtracks, ormax_query_size, and theCREATE HANDLER,ALTER HANDLER, andDROP HANDLERdocumentation is now published. #114883 (Alexey Milovidov). - Improve memory tracking for query sources, including recursive CTEs and external data sources, so their container allocations count toward memory limits. #124952 (Nikita Taranov).
- A subquery with its own
SETTINGSclause now plansGROUP BYusing the settings after constraints andmax_threadsclamping are applied, instead of reapplying the clause as written. This prevents nestedSETTINGS max_threads = ...from bypassing settings constraints or expanding the aggregation pipeline to an excessive number of streams. #123156 (Groene AI). - Improved the error message of
parseDateTime. #120489 (Robert Schulze). - Restoring an invalid data part from backup now reports
BACKUP_DAMAGEDinstead ofCORRUPTED_DATA. #113085 (Alexander Tokmakov). - Deserializing an aggregate function state that declares an oversized element count now reports
TOO_LARGE_ARRAY_SIZEand names both the offending count and the limit, instead of a barePOCO_EXCEPTIONcarrying no numbers. #121381 (Groene AI). - A setting given a value of the wrong type or out of range now names the setting and the value in the error message. #116882 (Alexey Milovidov).
- When a dictionary with a
PostgreSQLsource and a customQUERYreturns its columns in an order that does not match the dictionary structure, the error now names the destination dictionary column and the column order the query must return, instead of only reporting that a value could not be parsed. #114212 (Groene AI). - A
PostgreSQLdictionary whoseQUERYreturns fewer columns than the dictionary structure now fails to load with aNUMBER_OF_COLUMNS_DOESNT_MATCHerror that names the column order theQUERYmust use, instead of aLOGICAL_ERROR. AQUERYthat returns too many columns gets the same column-order hint. #125397 (Groene AI). - A column matcher (
*,t.*,COLUMNS('...')) insideadditional_table_filters,additional_result_filteror a row policy is now rejected with a clearBAD_ARGUMENTSdiagnostic instead of the obscureUnqualified matcher * cannot be resolved. There are no table sources.CREATE/ALTER ROW POLICYwith a matcher now fails immediately. A matcher inside a subquery of such a filter, for examplex IN (SELECT * FROM allowed), keeps working. #119250 (Alexey Milovidov). - A matcher (
*,t.*,COLUMNS(...)) used as a wholeLIMIT AFTERorLIMIT UNTILboundary is now rejected withUNEXPECTED_EXPRESSION, as inWHERE, instead of failing withstd::out_of_rangeor silently using only its first column. #123309 (Groene AI). CREATE FUNCTIONnow rejects a SQL user-defined function whose lambda arguments cannot be evaluated, instead of storing a function that later fails withBAD_ARGUMENTSon every call. Closes #121197. #121370 (Groene AI).- A correlated subquery in
HAVINGof aWITH TOTALSquery that also usesmax_rows_to_group_bywithgroup_by_overflow_mode = 'any'(andtotals_modeother thanafter_having_exclusive) now fails withNOT_IMPLEMENTEDinstead of a logical error. #122601 (Alexey Milovidov). - The
mergeTreeAnalyzeIndexesandmergeTreeAnalyzeIndexesUUIDtable functions now reject avector_search_index_analysislimit abovemax_limit_for_vector_search_queries, the bound under which the plan optimization rewrites a vector search query. A larger limit previously made the vector similarity index reserve memory proportional to it and exhaust the server’s memory. #122154 (Groene AI). - An unconditioned
CROSS JOINis no longer reported asINNERinEXPLAINand in the join columns ofsystem.query_logwhen thedpsubjoin order algorithm runs with a conflict detector enabled. Query results were not affected. #122236 (Fisnik Kastrati). - Formatting a query where an
INis the left operand of a tuple element ((x IN (1)).1) inside a multi-argument function call is now stable across a format-parse-format round trip. #124325 (Groene AI). - Exchanging
-Mergeaggregate states with older servers now stays compatible: the state version of a-Mergefunction follows the state version of the function it merges only for peers that announce the new protocol revision54494. #123070 (Groene AI). - An aggregate function parameter whose value has no unambiguous bare literal form, such as a
Decimal, a wide integer, aUUID, anIPv4orIPv6, or a non-negativeInt64, is now always printed with an explicit::Typesuffix, and inside an array or tuple parameter the suffix goes on the elements. Such a parameter therefore reads back as the same value for every family, instead of only for the ones that had opted in. The typed form also travels over theNativeprotocol, so an insert into a column whose parameter was spelled without the type is now rejected there too, as it already was locally. #121725 (Groene AI). - Diagnostics about slowly acquired locks are now logged at
Informationlevel instead ofWarning, so they no longer reach clients that usesend_logs_level = 'warning'while still being written to the server log with a stack trace. #123797 (Alexey Milovidov). - Adaptive aggregation now logs less noisily by reducing the severity of its messages. #123312 (Azat Khuzhin).
kqlRangeCountnow rejects theInt256minimum span with step-1instead of incorrectly reporting an empty range. #117212 (Alexey Milovidov).- A distributed query whose shards plan aggregation with the experimental
enable_cascades_optimizerno longer hits the logical errorGroupingAggregatedTransform pushed bucket N twiceon the initiator. #119814 (Alexey Milovidov). - Local execution of distributed query plans (
distributed_plan_execute_locally = 1) now materializes constant columns in its in-memory exchange like serialized exchanges do, fixing a query that could fail with aLOGICAL_ERRORwhen it sorted by a constant expression. #124097 (Groene AI). - The internal function
__bitSwapLastTwonow raises the sameBAD_ARGUMENTSerror for unsupported argument types when the expression is JIT-compiled as when it is interpreted. #117613 (Groene AI). - Fix a UBSan failure during parallel parsing of
TabSeparatedinput with an empty buffer. #122636 (Ray Winkelman). - The
ErrorCoderegistry is now sparse, so ClickHouse can reserve gaps between error codes without preallocating counters for them. #111796 (Maxim Orlovsky). - Fixed a signed integer overflow when a negative or huge
lock_acquire_timeoutvalue is used as the timeout for scheduling a background task. #117898 (Alexey Milovidov). - Cancelled marks-loading background tasks are no longer counted as errors in
system.errorsandsystem.error_log. PreviouslyASYNC_LOAD_CANCELEDwas recorded during normal operation whenever a reader was dropped before its asynchronously loaded marks were needed. #118928 (Alexey Milovidov). ALTER TABLE ... EXECUTE expire_snapshotsforIcebergtables now counts a file as deleted only when its removal succeeds, reports the removals that return an error in a newfailed_deletions_countmetric likeremove_orphan_files, and counts a file that several expired manifests list only once. Closes #125332. #125379 (Groene AI).- Reading an archive that libarchive fails to open without giving a reason (for example a
.tar.gzwith a truncated gzip trailer) now throwsCANNOT_UNPACK_ARCHIVEinstead ofSTD_EXCEPTION(fmt::format_error: string pointer is null). Closes #125620. #125650 (Groene AI). RESTOREfrom a tar backup with a non-emptypasswordsetting now fails withNOT_IMPLEMENTED, likeBACKUPto a tar archive, instead ofLOGICAL_ERROR. Closes #125648. #125666 (Groene AI).
Bug Fix (user-visible misbehavior in an official stable release)
- Fixed silent data loss when writing to an S3 key that already holds an object, for example
INSERT INTO FUNCTION s3(...)withs3_truncate_on_insert = 1. Closes #114348. #118829 (Sema Checherinda). - Fix possible data loss when a part’s
checksums.txtis repaired (recalculated and written on load, or byCHECK TABLE) and the server loses power afterwards. The metadata rewrite is now durable and atomic (write to a temporary file, fsync, atomically rename), and an emptychecksums.txtis now recalculated on load instead of detaching the whole part as broken. #111414 (Groene AI). - Fix a part being detached as broken, losing its rows, when
columns.txtormetadata_version.txtsurvives a power loss at length zero. Such a file is now treated like an absent one, which the load path already handles safely. #119582 (Alexey Milovidov). - Fix data loss when loading a part with a broken projection: a marks file damaged by an interrupted write could be accepted as an empty part instead of being detached as broken. #119586 (Alexey Milovidov).
- Fixed replica recovery of a
Replicateddatabase deleting the data of aKeeperMaptable, for example after the server was killed during anALTERof that table. AKeeperMaptable that still exists in Keeper is now kept or renamed with its data, instead of being dropped and re-created empty. Closes #111957. #122917 (Groene AI). DROP DATABASEof aReplicateddatabase now drops a materialized view withENGINE = TimeSeriesinstead of failing withIt's not initial queryand leaving the database half-dropped. #123663 (Groene AI).- Fixed data loss when a single
ALTER TABLErenamed aNestedmember, or another column with a dot in its name, and modified the renamed column. Such anALTERis now rejected withNOT_IMPLEMENTED, as it already was for other columns. #122794 (Groene AI). - Fixed merges deleting all rows of a part whose rows TTL was never calculated, although none of its rows had expired: a part attached with
ATTACH PARTITION ... FROMfrom a table without that rows TTL, or written beforeMODIFY TTLwithmaterialize_ttl_after_modify = 0added it, for example afterMODIFY COLUMN ... REMOVE TTL. The rows were lost in background TTL merges and in merges with fully expired parts. Closes #121124. #123068 (Groene AI). - Fixed a race in
MergeTreewhere anALTER TABLE ... UPDATEorDELETEmutation submitted concurrently with another mutation could be silently skipped on some parts while being reported as done. #124167 (Murphy). - A mutation on a
Replicated*table whose predicate contains a lambda can no longer prune to too few partitions when a lambda parameter name matches anALIASorEPHEMERALcolumn definition. Previously some matching rows were left unmutated while the mutation still finished successfully. #121193 (Groene AI). - Fix background merges with TTL silently stopping for the whole server. A merge with TTL that was selected and then dropped before it ran — for example because its table was dropped right after the expired rows were inserted — leaked one of the
max_number_of_merges_with_ttl_in_poolslots, which are shared by all tables. After two such merges no table would delete expired rows any more until the server was restarted. #121236 (Alexey Milovidov). - Make the asynchronous startup of a
ReplicatedMergeTreetable robust against a concurrentDETACH, which could previously hang the startup forever or leave background tasks running on a table that was already shut down. #121672 (Alexey Milovidov). - Fix corrupted shared data of nested
JSONobjects after a failed attempt to parse a value during insert. It could lead to errors likeUnexpected version of JSON type binary encodingorUnknown type codewhen reading the data after merges or when serializing it in binary formats. #123898 (Rory Shanks). - The server no longer terminates when a transient error such as
MEMORY_LIMIT_EXCEEDED, a network error, or concurrentSYSTEM RESTART REPLICAhappens while outdated data parts are loading in the background. Such errors are now retried later instead of aborting the server. #117981 (Alexey Milovidov). - Fixed silent row loss when a
MergeTreetable with a projection is read with aWHEREin which anANDis used with negative polarity, under aNOT, as an operand of a comparison, or as the branch condition ofif/multiIf/CASE, and one of thatAND’s conjuncts references a column the projection does not store. #120286 (Groene AI). - Fixed some
SELECTqueries silently returning fewer rows when the table has a projection that exists only in some of its parts, for example one added withALTER TABLE ... ADD PROJECTIONafter data was inserted, andquery_plan_remove_unused_columnsis0, whichcompatibilityup to25.11sets. #124022 (Groene AI). - Fixed wrong query results with skip indexes on
SummingMergeTree,AggregatingMergeTree,CoalescingMergeTree, andGraphiteMergeTreetables: withoptimize_on_insert, the default, anINSERTbuilt every skip index whose expression is not a plain column from the rows before they were merged, so queries using the index could skip granules with matching rows.SummingMergeTreealso no longer keeps rows whose summed columns total zero because of such an index. #123291 (Groene AI). - Fixed wrong results when a
WHEREclause mixingANDandORwas evaluated with skip indexes (use_skip_indexes_for_disjunctions, enabled by default). If aminmaxorsetindex could not evaluate one atom of the predicate for a granule, the per-atom verdicts recorded for that granule were shifted, so one atom’s verdict was applied to another and granules holding matching rows were skipped. #124303 (Groene AI). - Fixed a query silently returning fewer rows after an unrelated
JOINhad run: a join runtime filter moved into a read’sPREWHEREmade the read record a false “no matching rows” verdict in the query condition cache. #119823 (Groene AI). - Fixed the query condition cache serving one session’s granule verdicts to another when the two differ only in a setting a conversion function captured, such as
precise_float_parsing, which silently dropped matching rows from the second session’s result. #119168 (Alexey Milovidov). - Fixed
LEFT,RIGHT,FULL, andANYouterJOINsilently dropping non-matched rows when theWHEREfilter reads aDate32orEnumcolumn of the non-preserved side. Closes #121115. #121181 (Groene AI). - Fixed a join runtime filter silently dropping rows whose join key is a float. When the build side had a single distinct value the filter replaced set membership with
equals, but a hash join compares float keys bitwise, soNaNdid not match itself and0.0matched-0.0. #119720 (Groene AI). - Fix wrong values after lazy materialization expands a sparse column during a
JOIN: rows could receive values from other rows. #124442 (Nikolai Kochetov). ALTER TABLE ... EXECUTE expire_snapshotson anIcebergtable now always keeps the head snapshot of every branch, even when the table propertyhistory.expire.min-snapshots-to-keepis0. Previously such a table could lose all its data files. Closes #124333. #125365 (Groene AI).- Fixed an
ssl_certificateauthentication bypass where an embedded NUL byte in a certificate’s Common Name (for examplejohn\0.evil.com) was truncated server-side tojohn, letting a holder of such a certificate authenticate as a different user. #117403 (Konstantin Bogdanov). - Fixed one failed write to a non-replicated
MergeTreetable’s deduplication log (withnon_replicated_deduplication_windowgreater than zero) making every followingINSERTinto that table fail withCannot write to canceled bufferuntil the server was restarted. The log now replaces a writer that a failed flush left unusable, no longer finalizes such a writer while rotating or shutting down, and no longer stops removing its outdated files, which could also makeALTER TABLE ... MODIFY SETTING non_replicated_deduplication_windowfail. #118350 (Groene AI). - Fixed wrong results after
ALTER TABLE ... MODIFY COLUMN <column> <type> AFTER <other>on a column used inPARTITION BY. Closes #92834. #120862 (Groene AI). - Fixed a merge or a mutation making a table unreadable (
Stream ... is not found) when a column that a part does not hold is dropped and its name is also the name of a subcolumn of another column, for examplea.size0next to anArraycolumna. #118246 (Alexey Milovidov). - Fix wrong rows returned by
ORDER BY ... LIMITover aMergeTreetable read in the order of a function of its sorting key, for exampleORDER BY toStartOfMonth(date) DESC, i, when the sorting-key column uses sparse serialization. #109424 (Groene AI). ALTER TABLE ... DROP PARTITIONand other partition commands with an invalid or out-of-rangeDateorDateTimeliteral, such as'2024-02-30'or'9999-01-01', no longer silently act on a different partition. They now raise an error. #122419 (DeviousCardi).- Fixed wrong query results and unsorted parts in
MergeTreetables whose sorting, primary or partition key reads a subcolumn of a column (for examplePRIMARY KEY cityHash64(`c1.1`)orORDER BY t.a) when a columnTTLor anUPDATEchanges that column. A columnTTLon such a column is now refused as on any other key column,UPDATEof a column that aMATERIALIZEDkey column of this kind is computed from is refused, and TTL merges of a table already stored with such aTTLfail instead of writing unsorted parts. #123628 (Groene AI). - After a canary OOM, only the merges and mutations that are already running are cancelled. Newly scheduled ones now run as usual instead of all later merges and mutations staying cancelled until server restart. Closes #121748. #123870 (Javier G. Sogo).
- Fixed a spurious
Cannot schedule a task: no free thread ... (CANNOT_SCHEDULE_TASK)error that rejected a validSELECTover aMergeTreetable when it had more parts to analyse than the query had threads and their analysis took longer thanlock_acquire_timeout. Index analysis now runs one pool job per thread instead of one per part, which also makes it faster for queries over many parts. #116822 (Groene AI). - Fixed wrong results and
CANNOT_READ_ALL_DATAorINCORRECT_DATAerrors when readingMergeTreeparts in packed storage (min_bytes_for_full_part_storage), for example with parallel replicas, with a patch part of a lightweight update or delete, or when reading aJSONsubcolumn. #116920 (Groene AI). - Fixed
ILLEGAL_COLUMN(Illegal column ... of first argument of function to...) raised by every query touching a column that was dropped and re-added with a different type, for as long as a part still carried the old column. The re-added column now reads as its default, as it does once the drop’s mutation rewrites the part. Queries served from a projection no longer return the old values of such a column. #118585 (Alexey Milovidov). - Fixed reading stale data, or a
Sizes of nested column and null map of Nullable column are not equal/Got empty stream for SerializationLowCardinality keyserror, from a column that was turned intoALIASorEPHEMERAL(or dropped while its partition was detached) and later made physical again, when a mutation that rewrites only some columns (for exampleMATERIALIZE INDEX) ran on a Wide part in between. #124516 (Groene AI). - Fixed a use-after-free (on some versions a crash with
Pure virtual function called!) onINSERT, merge orSELECT ... FINALof aSummingMergeTreetable with aNestedcolumn whose name ends inMapand whose element type hasLowCardinalityinside anArrayorMap, for exampleArray(LowCardinality(String)). #125533 (Groene AI). - Fix a
MergeTreetable with a rowsTTLand atextindex never dropping its expired parts: theTTLDropmerge failed withText index transform for index ... not foundand retried forever. #113385 (Groene AI). - Fixed dropping whole parts with TTL (
ttl_only_drop_parts = 1) still reading all data from large, fully expired parts. #108626 (Michael Jarrett). - Fixed a server crash on
CREATE TABLEorALTER TABLE ... MODIFY TTLwhen aTTLexpression uses the result ofarrayMapwith a constant lambda, such astoString(arrayMap(x -> CAST(1, 'Dynamic'), arr)). #122868 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCK(Not found column _row_exists in block) that permanently blocked all further mutations of aMergeTreetable after a lightweightDELETErun withlightweight_delete_mode = 'lightweight_update'was followed by a heavyweightALTER TABLE ... UPDATEand then by another mutation rewriting all columns. Closes #115570. #115665 (Groene AI). - Fixed
ALTER DELETEandALTER UPDATEsilently skipping rows when the predicate references anALIAScolumn whose definition contains a non-deterministic function such asnow. #117273 (Alexey Milovidov). - Fixed a patch part whose
source_parts.datlost its content to a zeroed block loading as an empty index, which silently unapplied an acknowledged lightweightUPDATEand then let background cleanup delete the only copy of it. Such a part is now detached as broken. #119585 (Alexey Milovidov). - Fixed
ALTER TABLE ... DELETEandALTER TABLE ... UPDATEskipping a whole partition when the parts the initiating replica holds in it are all empty: rows another replica had acknowledged in that partition survived the mutation on every replica. #119149 (Alexey Milovidov). - Fixed a pending lightweight
DELETEread withapply_mutations_on_fly = 1evaluating its predicate over patch parts created after it, which made rows disappear from the result and reappear after the mutation materialized. Closes #118049. #118919 (Alexey Milovidov). #119306 (Alexey Milovidov). - Fixed lightweight
UPDATEfor parts adopted from another table viaREPLACE PARTITIONorATTACH PARTITION FROM: after such a part was cloned again (by a mutation that does not modify it, by a clone instead of a fetch of a replicated mutation, or by a move between disks), applying patch parts could silently drop updated rows in release builds and raise thecurrent_version != existing_versionexception in debug and sanitizer builds. #115979 (Alexey Milovidov). - Fixed lightweight
UPDATE ... ON CLUSTERonReplicatedMergeTreetables running on every replica of a shard instead of once per shard, which applied assignments such asSET v = v + 1once per replica. A plainUPDATEin aReplicateddatabase with more than one shard had the same problem. #122393 (Pratham Nayak). - Fixed a concurrent heavyweight
ALTER TABLE ... UPDATE/DELETEsilently dropping an acknowledged lightweightUPDATEon a plainMergeTreetable. #119155 (Alexey Milovidov). - Fixed mutations such as
ALTER TABLE ... UPDATEfailing withCANNOT_READ_ALL_DATAon every attempt, and never completing, when they read a column together with itsLowCardinalitysubcolumn in a Wide part: aDynamiccolumn and itsLowCardinality(String)subcolumn, or aMapwithmap_serialization_version = 'with_buckets'and itskeysorvaluessubcolumn. The problem appeared in 26.6. #123160 (Groene AI). - Fixed an acknowledged lightweight
UPDATEbeing invisible onReplicatedMergeTreewhen it targets a column whoseRENAME COLUMNmutation has not materialized yet. #119144 (Alexey Milovidov). - Fixed a lightweight
UPDATEmade beforeALTER TABLE ... RENAME COLUMNon aReplicatedMergeTreetable being lost when a merge ran before the rename’s mutation (for example withapply_patches_on_merge = 0): queries returned the old value, and the mutation then dropped the update from disk. #124653 (Groene AI). - Fixed a wrong result of a mutation of a
MergeTreetable when several pending mutations are executed as a single task and a patch part, created by a lightweightUPDATE, has a version in between: the patch was applied before the commands that precede it, so they were evaluated over data they must not see. #119127 (Alexey Milovidov). - Fixed
ReplicatedMergeTreeTTL processing stalling indefinitely when a TTL merge that drops fully expired parts was larger than half the free disk space. Such a merge deletes every row and therefore needs no room for its source parts, but it was postponed on their size, and the postponed entry kept occupying the onlymax_replicated_merges_with_ttl_in_queueslot, so no TTL merge ran and no space was ever freed. It is now admitted when the table’s only TTL is an unconditional rows TTL. Closes #119775. #119983 (Groene AI). - Fixed
ATTACH PARTITIONonReplicatedMergeTreefailing to rename a broken part indetached/aside, so every laterATTACH PARTITIONfor that partition kept failing on it. #116734 (Groene AI). - Fixed the replication queue never draining when a part is present locally but its node in
ZooKeeperis missing: theGET_PARTentry for such a part re-downloaded it and failed withDUPLICATE_DATA_PARTon every retry. #119189 (Alexey Milovidov). - Writing the empty covering part of a replicated table now happens before the covered parts are removed from the working set, so an exception during the operation no longer leaves the table with unexpected data parts and readonly after reload. #122610 (Alexey Milovidov).
- Background Keeper users now retry a
get_zookeeper_lock_acquire_timeout_mstimeout like other Keeper errors, so aReplicatedMergeTreetable attached during a transient Keeper outage no longer stays read-only. #124327 (Groene AI). - A table read by a scalar subquery inside a
CONSTRAINTis now a loading dependency of the table that declares the constraint. Previously such a table could be dropped, after which the server did not start, because attaching the dependent table executes the subquery. #114923 (Alexey Milovidov). - Fixed a server startup failure after creating a table with a
quantile*state column whose level is aDecimal, a wide integer, aUUID, anIPv4, or anIPv6. Such a level was persisted into the metadata as a quoted string, which reparsed as aStringand was rejected, so metadata loading failed withCANNOT_CONVERT_TYPEand the server did not start. The sameCREATEalso failed outright on aReplicateddatabase. #119810 (Groene AI). - A table whose stored definition carries a column
TTLinherited from its source table now loads again on engines that do not supportTTL(Merge,Buffer,Distributed,Remote). Previously such a table could not be loaded, which failed the load of the whole database, and withasync_load_databases = 0the server refused to start. TheTTLstays in the definition and has no effect;ALTER TABLE ... MODIFY COLUMN ... REMOVE TTLremoves it. #122273 (Mohammed Sohail). - Fix a
RemoteorClusterdatabase without a local shard makingSELECT count()through themergetable function return0, and making the server fail to start when a dictionary reads one of its tables. Closes #122612. #122661 (Groene AI). - Fix
Part ... intersects previous part ...when attaching aMergeTreetable afterREPLACE PARTITION, if parts outdated by an earlierDROP PARTwere still on disk. The server could fail to start because of it. #120980 (Alexey Milovidov). - Fix
Part ... intersects next part ...when loading aMergeTreetable afterREPLACE PARTITIONinto it ran concurrently withMOVE PARTITIONfrom it. The server could fail to start because of it. #123780 (Alexey Milovidov). - Fixed
S3,HDFS,AzureBlobStorage, andURLtables over a named collection withformat = 'auto' NOT OVERRIDABLEfailing to load withOverride not allowed for 'format', which could stop the server from starting. The format that ClickHouse inferred and stored atCREATEtime is now accepted when the table is loaded again; a format written by the user over the locked value is still refused. #124215 (Groene AI). - Restored compatibility with Azure Blob Storage endpoints that omit the
ETagheader. #120419 (alesapin). - Fix
Part ... intersects previous part ...when loading aMergeTreetable after aTRUNCATE,DROP PARTITIONorMOVE PARTITION TO TABLEfailed to commit (e.g. because of a memory limit or a disk error) and a merge ran before the restart. The server could fail to start because of it. #122375 (Alexey Milovidov). - A
PROJECTIONthat could not be analyzed when the table was loaded at server startup is no longer deleted from the table’s persisted metadata by the nextALTER, which also orphaned its already-materialized data with no error at any step. While such a declaration is present, anALTERthat rewrites the table metadata is now refused (ALTER TABLE ... DROP PROJECTIONandCLEAR PROJECTIONstill work), so it survives until the cause is removed or the user drops it. #118378 (Groene AI). - Fixed non-deterministic conditions being moved to
PREWHEREinSELECT ... FINALwhenoptimize_move_to_prewhereis enabled. #109538 (Yarik Briukhovetskyi). - Fixes wrong results with
query_plan_optimize_lazy_finalwhen the primary key is nullable and holds aNULL: theNULL-keyed row was silently missing from the result of aFINALquery. #112857 (Groene AI). - Fixed rows silently dropped by index analysis when a
DateTime64column is compared with a constant of another scale and the sorting or partition key contains aCASTof that column, such asORDER BY d::String. #118688 (Alexey Milovidov). - Fix rows silently dropped by partition, primary-key, and skip-index pruning, and by
Icebergpartition pruning, when a string constant is compared with aDateTimeorDateTime64column whose type name carries no time zone and the effectivesession_timezonediffers from the one that column’s type was built with. #120114 (Groene AI). - Fixed a
minmaxskip index, asetskip index, part-level minmax pruning, and statistics-based part pruning dropping rows that hold aNaNwhen the query negates a float comparison, for exampleWHERE NOT (val BETWEEN 0 AND 3). Closes #106533. Closes #106948. #107074 (Groene AI). - Fixed silently missing rows for a range predicate on
toDayOfWeek(key, mode)with the Sunday-first modes2and3over a date primary key. #117683 (Alexey Milovidov). - Fixed
ngrambf_v1,tokenbf_v1, andsparse_gramsskip indexes silently dropping matching rows when anIPv6column is compared with a string literal, as inWHERE ip = '2001:db8::'. #113157 (Groene AI). - Fixed a
setskip index whose expression has typeDynamicorVariant, which includes an undeclaredJSONpath such asj.a, silently returning no rows for!=andIS NULL. #120780 (Groene AI). - Fixed wrong results when a query converts a
DateorDate32column toDateTimeand the column’s values leave the range of day numbers that fits into 32-bit seconds. Key analysis, statistics part pruning, and reading in sorting-key order assumed the conversion preserves order, so a filter could skip parts holding matching rows or answercountfrom metadata without filtering, andORDER BYcould return rows out of order. AffectstoDateTime,toDateTime32,CAST(... AS DateTime), andaccurateCast. #117031 (Groene AI). - Fix rows silently dropped by primary-key pruning when
toDayOfWeekis applied to aDateTimecolumn whose time zone differs from the session one, or over aDate32/DateTime64key that leaves theDaterange.toDayOfWeekwith a Sunday-firstweek_modecan use the primary key again. #118655 (Alexey Milovidov). - Fixed rows silently missing from a query over a table whose primary key is a
Tuplewith aNullableelement holdingNULL: primary-key analysis dropped whole granules of matching rows. #118945 (Alexey Milovidov). - Fix a
JSONAllPathsskip index silently pruning every granule for a filter on a subcolumn inside a declared typed path of aJSONcolumn (for examplejson.a.bforJSON(a JSON)orJSON(a Tuple(b Int64))). Such a filter no longer uses the index. #119321 (Alexey Milovidov). - Fix rows silently dropped by primary key and partition pruning when a
MergeTreekey expression applies a timezone-observing function such astoYYYYMM,toStringor aCASTtoStringto aDateTime/DateTime64column and a compared constant declares a different timezone. Both a scalar comparison constant and anIN-set element are affected, including when the differing timezone sits under anArray,Map,Tuple,Nullable,LowCardinalityorVariantwrapper that only one side carries, when a custom type name such asSimpleAggregateFunctionwraps that composite on one side only, and when a sibling leaf differs only by a custom type name (BoolagainstUInt8). Also fix the same loss when a comparedTupleand the key column’s disagree on explicit element names, whichtoJSONStringrenders as an object against an array; no timezone difference is needed. #113781 (Groene AI). - Fixed rows silently dropped, or counted without being filtered, when a
DateTime64constant of a finer scale than the column is compared with!=,NOT IN, orIN: index analysis truncated the constant and treated the truncated value as the exact point the query asked for, pruning the granule or partition that held a matching row. #118957 (Alexey Milovidov). - Fixed index analysis for a condition that wraps the primary key in a widening integer cast such as
toInt64and then applies another monotonic function such asnegateorabs. Such a condition could silently drop matching rows, or fail withLOGICAL_ERROR: abs's argument does not match the expected data type. Present since 26.5. #116699 (Groene AI). - Fixed wrong results from primary-key analysis for predicates such as
toDate(dt64_key) >= ...andtoDateTime(date32_key) >= ...: at the defaultdate_time_overflow_behavior = 'ignore'the conversion wraps for values the result type cannot hold, so matching rows silently disappeared andcount()could overcount. #117394 (Alexey Milovidov). - Fixed partition pruning skipping a partition whose rows match a filter like
NOT (c <=> f(partition_key))whenfreturnsNULLfor that partition’s key value (for examplemoduloOrNullornullIf). Such queries returned fewer rows than withuse_partition_pruning = 0. #124041 (Groene AI). - Fixed
use_skip_indexes = 0also disabling part pruning by the partition-key min-max index since 26.5, which made such queries read every part of the table. #123403 (Ashish Kumar Choubey). - Fixed missing rows in queries mixing
ANDandORwhen aminmaxorsetskip index over an expression withmortonEncodeorhilbertEncodeis combined with other skip indexes (use_skip_indexes_for_disjunctions, enabled by default). Closes #124452. #124784 (Groene AI). - Fix a query that compared a
DynamicorJSONcolumn with a constant, such asd = '2024-01-05'ord = toDate('2024-01-05'), and returned fewer rows when the table was ordered by a transform of that column, such asORDER BY d::String. Such a comparison no longer uses the primary key; compare the key expression itself, as ind::String = '2024-01-05', to keep using it. #124476 (Ashish Kumar Choubey). - Fixed a
textindex dropping matching rows when aFixedStringis involved in the comparison. #118972 (Alexey Milovidov). - Fixed wrong results of
hasPhrase,hasToken,hasAnyTokens, andhasAllTokensover a text index with apostprocessororpreprocessorwhen direct read from the text index could not answer the function, for exampleNOT hasPhrasewith a phrase whose tokens are all removed by a stop-word postprocessor. #125118 (Groene AI). - Fixed text-index search functions returning wrong results, including silently dropped rows, on a column whose text index declares a preprocessor. #117774 (Elmi Ahmadov).
- Fixed wrong results after a mutation of a wide data part that does not store a column added by a metadata-only
ALTER TABLE ... ADD COLUMN: the mutation wrote a column statistic for that column, so statistics-based part pruning could drop a part holding matching rows andminandmaxcould be answered with the pre-ALTERdefault. #121936 (Groene AI). - Fixed wrong results for
min,max, and filteredcounton aMergeTreecolumn that carries a columnTTL. When theTTLemptied the column, the part kept a statistic for it and queries were answered from that stale statistic instead of from the rows the part stores. #122058 (Groene AI). - Fixed wrong results from
use_query_condition_cache_for_top_k:SELECT ... SAMPLE ... ORDER BY ... LIMIT nno longer reuses cache entries written by the same query withoutSAMPLE, and Top-K query condition cache entries are no longer written for reads with on-the-fly mutations or patch parts. Closes #122564. #122538 (Nikita Fomichev). #122617 (Nikita Fomichev). - Fix an exception
NOT_FOUND_COLUMN_IN_BLOCKand, in other queries, wrong results when a lambda argument has the same name as an identifier of an expression that is bound to an alias outside of that lambda, for exampleSELECT number + 1 AS n, arrayMap(number -> number + n, [1, 2]) FROM numbers(2). #115544 (Alexey Milovidov). - Fixed wrong results when a
GROUP BY,DISTINCT,LIMIT BY, or windowPARTITION BYkey wasplusorminusof a partition column with a non-integer constant. #120182 (Groene AI). - Fixed a regression in 26.8 where columns of a parameterized view could not be qualified by the view name (
SELECT pv.col FROM pv(p = 1)failed withUNKNOWN_IDENTIFIER) and a parameterized view used as aJOINoperand required an explicit alias. Closes #119837. #112481 (Groene AI). #120698 (Dmitry Novik). - Fixed
CANNOT_INSERT_NULL_IN_ORDINARY_COLUMNandCANNOT_PARSE_TEXTwhen aPREWHEREguard predicate and a throwing expression, such as aCASTortoUInt64(substring(...)), end up in the same read step: either because they read subcolumns of the same column, for example aJSONorMapcolumn, or because a JOIN runtime filter’s key computation was merged into the guarded subquery. Such a query used to fail because the throwing expression was evaluated on rows the guard had rejected. #111954 (Groene AI). - Fix wrong window function results when a
QUALIFYcondition, or a comparison derived from it byoptimize_and_compare_chain, turns into anindexHintthat prunes rows below the window. Closes #121177. #122975 (Yarik Briukhovetskyi). - Fixed wrong aggregate values with
optimize_aggregation_in_order_limitwhen theORDER BYis a strict prefix of theGROUP BYkey and a group’s rows span multiple parts. Closes #116849. #117573 (Konstantin Bogdanov). - Fixed wrong results of
sum,min,max, andavgover arithmetic with aDecimaloperand and a constant, for examplemingreater thanmax, a changedsumof a division, or a missingDECIMAL_OVERFLOW:optimize_arithmetic_operations_in_aggregate_functionsno longer moves such arithmetic out of the aggregate. #117779 (Alexey Milovidov). - Fix
<agg>IfOrNullIfand<agg>IfOrDefaultIfignoring the outer condition when used withoutGROUP BYkeys or as a window function with non-Nullablearguments. #122908 (Raúl Marín). - Fixed a possible hang of a distributed
GROUP BYquery withuniqExactanddistributed_aggregation_memory_efficient = 0when merging large states of two-level aggregation. #123352 (Alexey Milovidov). - Fixed missing rows of an empty grouping set
()inGROUP BY GROUPING SETSqueries without aggregate functions. For example,SELECT number FROM numbers(3) GROUP BY GROUPING SETS ((number), ())returned 3 rows instead of 4, andGROUPING SETS (())returned one row per input row. Closes #61461. #123539 (Groene AI). - The
uniqaggregate function returned garbage (for example18446743978444128518) for cardinalities above roughly thirty billion, because its state kept only 32 bits of each hash and the correction formula overflowed. The state now additionally keeps a small sample of full 64-bit hashes (state version1) which the estimate switches to at about two billion elements:SELECT uniq(number) FROM numbers_mt(100000000000)returns99360630405(−0.64%), and the estimate stays accurate (about 1%) up to trillions. Below two billion nothing changes: the estimates, the memory usage, and the state format are exactly as before, and states written by older versions remain readable and merge correctly in mixed-version clusters. #115393 (Alexey Milovidov). - Fix wrong results for
uniq*,GROUP BY,LIMIT n BY,ORDER BYafterGROUP BY, and windowPARTITION BYovertoStringof aDateTime/DateTime64in a time zone with a daylight-saving transition, and overtoFixedStringof aString. Both functions claimed to be injective while mapping distinct arguments onto the same result, and the default-on optimizations that take that claim as a proof then eliminated the wrapper. #117238 (Alexey Milovidov). - Fixed
optimize_rewrite_aggregate_function_with_if(enabled by default) turning a short-circuit-guarded aggregate such assum(if(number = 0, 0, intDiv(42, number)))into a query failure: the rewrittensumIf(intDiv(42, number), number != 0)evaluates its argument for every row, so the guarded expression ran on the rows the condition excluded and threw. The rewrite is now refused when the lifted branch relies on short-circuit evaluation. Closes #85784. #118697 (Groene AI). - Fixed wrong results and errors of
min,max,sum, andavgover an arithmetic operation with a constant withoptimize_arithmetic_operations_in_aggregate_functionsenabled (the default): on anArrayorTupleoperand (min(arr * -1)), on anIPv4orIPv6operand (sum(ip * 1)threwILLEGAL_TYPE_OF_ARGUMENT), foravgof a date, time, or interval (avg(t + INTERVAL 500 MILLISECOND)), for multiplication or division by zero, infinity, orNULL(min(x / -0.0)), and for a day or longer added to aDateTimeor aTime64across a DST change or a month end. Closes #122647. #123908 (Groene AI). - Fixed
hasAll,hasAny,hasSubstr,startsWith, andendsWithreturning wrong results onArray(Nullable(T)). ANULLelement was compared as whatever value was physically stored beneath it, so these functions disagreed withhason identical input:hasAll([1, 2, NULL, 4], [0])returned1whilehas([1, 2, NULL, 4], 0)returned0. Closes #68310. #116239 (Groene AI). - Fixed wrong results from JIT-compiled conversions between integers and
Decimal. With the defaultcompile_expressions = 1, a conversion the destination could not hold silently wrapped instead of raisingDECIMAL_OVERFLOWonce the expression crossedmin_count_to_compile_expression. Closes #118958. #118994 (Groene AI). - Fixed
if,multiIf, andCASEreturning a wrapped value instead of raisingDECIMAL_OVERFLOWonce JIT-compiled, when aDecimal,DateTime64, orTime64branch is lifted to a larger scale (with default settings, after the query had run a few times). #123186 (Groene AI). - Fixed wrong results of
extractandreplaceRegexpAll(and its aliasregexp_replace) under the default-enabledoptimize_rewrite_regexp_functions:extractcould return a different occurrence when a leading greedy^.*was stripped, or a truncated result for a pattern ending with.*$whose only parentheses are an inline flag group, such as(?i)b.*$;replaceRegexpAllcould silently lose replacements when a pattern that can match more than once (with an inline(?m)flag, or a tail that can match the empty string, such aso*$) was rewritten toreplaceRegexpOne; and both mishandled a trailing.*$or$that is literal text inside an unterminated\Q. #117228 (Alexey Milovidov). #117227 (Alexey Milovidov). #118361 (Alexey Milovidov). - Fixed rows silently missing from the result of
matchwith a pattern that has a zero-allowing quantifier behind an inline flag group or an empty\Q\Equote. #118351 (Alexey Milovidov). - Fixed the best-effort date/time parsers reading one byte past the end of the value. The parsed result of a row of a
Stringcolumn could depend on the text of the following row: a valid value was rejected asNULLor zero, oraddMonthsand the rest of the add-interval family returned date and time fields taken from the neighbouring row. #122246 (Groene AI). - Fixed
toStartOfMinute,toStartOfHour,toStartOfDay,toStartOfFiveMinutes,toStartOfTenMinutes,toStartOfFifteenMinutes,timeSlot,toTimeWithFixedDate,toStartOfIntervalanddateTruncreturning a value one second later, possibly in the next interval, for aDateTime64before 1970 with a fractional part. For example,toStartOfMinute(toDateTime64('1969-12-31 23:58:59.500', 3))returned23:59:00. Also fixedtoStartOfIntervalwith an origin and aMONTH,QUARTERorYEARinterval returning a value after its argument when the argument was earlier in the day than the origin, and rounding a bucket start clipped to the end of a shorter month to the previous bucket. #122138 (Alexey Milovidov). - Fixed accepting a column whose two serialization streams map to the same file name (for example
Nullable(JSON(`null` Int64))orTuple(`a` Tuple(`b` UInt64), `a.b` UInt64)). Such a table was created successfully, but its parts were written with both streams in one file and could not be read, merged, or checked. Creating such a column now fails withBAD_ARGUMENTS, as a collision between two different columns already did. Existing tables still attach, with the collision logged. #115632 (Pavel Kruglov). - Fix a valid
JOIN ONquery rejected withTYPE_MISMATCHbyoptimize_redundant_comparisons, which is enabled by default since 26.7. It affects a join expression whoseANDhas aNothing-typed operand, for example a join key compared against anARRAY JOIN []alias. #117476 (Groene AI). - Fixed wrong results, or an
ILLEGAL_COLUMNerror, of aJOINwhose condition equates both a column and an expression of that column (for exampleON t1.k = t2.k AND intDiv(t1.k, 2) = intDiv(t2.k, 2)) when a filter on that expression is pushed down to the other side of the join: the pushed-down copy applied the expression twice. Closes #122613. #122686 (Groene AI). - Fixed
SAMPLEon the first table of aJOINbeing applied to the other joined tables too, which returned too few rows, or failed withSAMPLING_NOT_SUPPORTEDwhen a joined table had no sampling key. #124767 (awss). - Fixed missing rows from a
Distributedorremotequery whoseWHEREhas aNOTover anANDcontaining a conjunct that cannot be converted to an AST, such as a lambda ordictGet: the pushed-down predicate became stronger than the original one. #117620 (Alexey Milovidov). - Fix wrong results when a query selects an
ALIAScolumn together with a window function withenable_analyzer = 1, over aDistributedtable (orremote) with two or more shards, or over a table read with parallel replicas. Values could be returned in the wrong columns with no error, or the query could fail withNUMBER_OF_COLUMNS_DOESNT_MATCHorCANNOT_PARSE_DATETIME. #116498 (Groene AI). - Fixed a distributed
SELECTsilently returning a partial result whenconnection_pool_max_wait_msis set to a finite value andskip_unavailable_shards = 1. A shard whose replica the initiator had no free connection slot for was reported as an unavailable shard and dropped, so a two-shard query could return one shard’s rows with exit code0. Such a shard now fails the query withALL_CONNECTION_TRIES_FAILED, the same error the defaultskip_unavailable_shards = 0already produces. Closes #120832. #120969 (Groene AI). - Fixed asynchronous TLS connections occasionally failing with an unrelated OpenSSL error left by another connection on the same OS thread. This could terminate distributed queries with a misleading network exception. #116692 (Dmitriy Borisenko).
- Fixed a query over a
Distributedtable silently returning too few rows when itsWHEREcallsjoinGet: the condition was sent to the shards, and each one answered the call against its own localJointable rather than the initiator’s.joinGetis now treated as non-deterministic and stays on the initiator. #121822 (Nikita Taranov). - Fix
THERE_IS_NO_COLUMNfor aDistributedquery that has anINover the sharding key outside itsWHERE, in theSELECTprojection, inGROUP BY, inORDER BY, or inLIMIT BY. The default-enabledoptimize_skip_unused_shards_rewrite_inrewrote thatINper shard, which changed the result column’s name, so the initiator could not bind the column the shard returned. #117252 (Alexey Milovidov). - Fixed cancelling a distributed,
s3Clusteror parallel-replicasSELECTtaking up toreceive_timeout(300 s by default) to take effect, and never reaching some of the remote sources, when one of them was draining the packets left over after aLIMITwas satisfied. #118696 (Groene AI). - Fixed a server abort (
vector[] index out of bounds) when reading aDistributedtable withprefer_global_in_and_join = 1and anINexpression that the analyzer shares between two parent expressions. The local toGLOBAL INrewrite now rewrites theINfunction in place, so every reference to a shared node is promoted. #120681 (Groene AI). - Fixed
INSERT INTO <replicated table> SELECT ... FROM url(...), and the same shape withs3orazureBlobStorage, with parallel replicas enabled inserting the data once per replica. Closes #120485. #120488 (Alexey Milovidov). - Fix
INSERT INTO <Distributed table> SELECT ... FROM url(...)(ands3,azureBlobStorage, …) with parallel replicas enabled inserting the data once per shard of the destination cluster: the query forwarded to the shards now names the*Clustertable function with the cluster of theDistributedtable, so every shard reads only its share of the files. Such anINSERTalso no longer writes into the shards’ local tables when the destination has a deterministic sharding key, because the rows a cluster table function hands to a shard cannot satisfy that key and the resulting placement madeoptimize_skip_unused_shardsreturn partial results; it falls back to the ordinaryINSERT ... SELECTinstead, which places the rows through theDistributedsink. #121070 (Igor Nikonov). - Fixed duplicated rows returned by
ANY RIGHT JOINwithany_join_distinct_right_table_keys = 1when parallel replicas are enabled. #123683 (Groene AI). - Fixed
CREATE MATERIALIZED VIEW ... POPULATEandCREATE TABLE ... AS SELECTin aReplicateddatabase with parallel replicas enabled: each replica sent its population to other replicas, so its rows landed in other replicas’ tables (duplicated there, missing on the replica itself), or the query failed withUNKNOWN_TABLE. The population now ignores the query’s parallel replicas andparallel_distributed_insert_selectsettings, so each replica fills only its own table. Closes #124446. #124477 (Groene AI). - Fix
S3client refresh overwriting static authentication settings and breaking subsequent queries. #120433 (alesapin). - Fix a server abort when an Azure Blob Storage endpoint reports an asynchronous blob copy as completed without the optional
x-ms-copy-sourceorx-ms-copy-status-descriptionheader. #120935 (Alexey Milovidov). - Reads from Azure Blob Storage now verify that the returned range starts at the requested offset, so an endpoint or proxy that ignores the request
Rangefails the read withHTTP_RANGE_NOT_SATISFIABLEinstead of delivering the wrong bytes. #120955 (Alexey Milovidov). - A bounded read from Azure Blob Storage whose response ends before the requested right bound is now reopened and, if the endpoint keeps answering short, fails with
UNEXPECTED_END_OF_FILEinstead of silently returning a truncated file. #120963 (Alexey Milovidov). - Fix a buffer over-read on the sequential read path from Azure Blob Storage: an endpoint that answers a ranged request with more data than was requested could deliver bytes from outside the requested range to the caller. The end of a read is now decided by the locally set right bound, not by the
Content-Lengthof the response, and a read is pinned to the listed generation of the blob withIf-Match, so an object replaced during a read fails withAZURE_OBJECT_CHANGED_DURING_READinstead of being truncated (new settingazure_validate_etag_on_read, enabled by default). #120910 (Alexey Milovidov). - Fixed a disk with
object_storage_type = 'local'and a relativepathremoving its own root directory once the last blob in it was deleted. Anything else stored in that directory was lost with it; in particular, a disk whosepathpointed at the directory of its ownlocalmetadata became unusable. #119119 (Alexey Milovidov). - Fixed
S3requests that keep failing with a retryable error being attempted(s3_retry_attempts + 1)^2times instead ofs3_retry_attempts + 1. Fixed an error that a plain-HTTPS3endpoint sends before reading the whole request body (for exampleNoSuchUploadfor an expired multipart upload) being retried as aBroken pipenetwork error instead of being reported. Closes #124326. #124557 (Groene AI). - Fixed a heap use-after-free in the
s3,azureBlobStorage,hdfs, and similar object-storage table functions and engines when an exception such asMEMORY_LIMIT_EXCEEDEDwas thrown while creating the reader of a file in a row input format such asCSV. #125090 (Groene AI). - Fixed exceptions such as
UNKNOWN_CODECwhen readingMergeTreetables through the userspace page cache (use_page_cache_for_disks_without_file_cache = 1withremote_filesystem_read_method = 'read', oruse_page_cache_for_local_disks = 1): files kept inside packed archives (statistics, skip indices, parts in packed storage) were read from the wrong offset. Closes #122157. #122949 (Groene AI). - Fix Parquet
time32/time64columns being read asDateTime64and then silently shifted bysession_timezonewhen inserted into aTime64target column. ParquetTIMElogical types now map directly toTime64, and the missingTime64 -> Timecast is added. #106019 (Shaohua Wang). - Fixed a
Parquetreader bug where a filter on an integer column read with a type hint that reorders the file’s statistics (for exampleUInt32over a plainINT32column,Enum8over aUINT_8one, orIPv4over aUINT_64one) could silently return fewer rows than the file holds. Such statistics are no longer used for row group or page pruning, and aDATEvalue outside the requested type’s range now raises the same error with pruning as without it. Closes #118376. #121033 (Groene AI). - Fixed an infinite loop in the Parquet reader on a ZSTD or Brotli compressed page that decompresses to fewer bytes than its header declares. Such a query could not be stopped by
max_execution_timeorKILL QUERY; it now fails withINCORRECT_DATA. Closes #123274. #123298 (Groene AI). - Fix
Unexpected number of rows in column subchunk(LOGICAL_ERROR) when filtering a Parquet file whoseBoolcolumn is RLE-encoded (pyarrow’s default for data page v2). The filter is now applied while decoding RLE-encoded and dictionary-encoded pages, which also makesPREWHEREover dictionary-encoded columns of Parquet files without a page index faster (ClickBench q31 1.92 s to 1.21 s). Closes #123483. #123618 (Groene AI). - Fixed wrong results when reading a
Parquetfile with a structure hint whose type differs from the stored one. Row-group and page pruning, bloom filters, and dictionary filters now hash and interpret the query constant in the stored physical type rather than the hinted one, which fixes cases such as narrowing, signedness flips,Enum,Date/Date32/Time, length-mismatchedString/FixedString, andBoolover an integer column. Reading aUINT_8column with aBoolhint now also treats every nonzero value astrue, sox = true,x IN (true), andWHERE xagree. #123864 (Groene AI). #121077 (Groene AI). #124285 (Groene AI). - Fixed
Parquetoutput failing withCapacity error: array cannot contain more than 2147483646 bytesorUncompressed page is too bigwhen a batch of rows held more than 2 GiB ofStringorFixedStringdata. A batch is now bounded by bytes as well as by rows, which also lowers the peak memory of the write. #122482 (Alexey Milovidov). - Fixed
SELECT ... FORMAT Arrowfailing withMethod getDataAt is not supportedforJSON,Dynamic, andQBitcolumns, and silently exporting heap addresses instead of the aggregate state forAggregateFunctioncolumns. Added theoutput_format_arrow_unsupported_typessetting (throw/text/binary, defaultbinary), which supersedesoutput_format_arrow_unsupported_types_as_binary. Such columns can now also be read back into their original type, which previously failed or silently corrupted the value.INSERT INTO ... ENGINE = ArrowFlightnow follows this setting too; it previously rejected such columns unconditionally, so an insert that used to fail may now write an opaque column. Setoutput_format_arrow_unsupported_types = 'throw'to keep rejecting it. #115250 (Yakov Olkhovskiy). - Fix
O(n^2)decompression of gzip/zlib/deflate streams whose single DEFLATE block spans the whole stream, the shape zlib-ng produces at compression level 1 (the default of the official .NET SDK): a 24 MiB gzip HTTP body that took 11 s to ingest in 26.7 now takes 0.12 s, identical to a multi-block body, with memory bounded by the buffer size instead of the block size. #114059 (Alexey Milovidov). - Fixed a segmentation fault or
std::length_errorwhen readingTSVformats withinput_format_tsv_crlf_end_of_line = 1if an escape sequence ended exactly at the end of a read buffer. #123861 (Groene AI). - Fixed lost rows when a query over a
MySQL,PostgreSQL,SQLite, or ODBC/JDBC table compares a column, string, number, orDecimal, with anEnumconstant, also inside a tuple, anINlist,Nullable,Variant, orDynamic, at any depth. The filter sent to the external database used theEnum’s number, while ClickHouse compares a string column with theEnum’s name, andPostgreSQLrejected such a query. AnINlist or row ofVariantorDecimalconstants is no longer sent as one quoted string. #123843 (Groene AI). - Fixed wrong results of a negated
INwith aNULLin the list, e.g.x NOT IN (1, NULL)orNOT (x IN (1, NULL)), overMySQL,PostgreSQL,SQLite, andODBCtables: the filter pushed to the external database now leaves theNULLmembers out of the list, the way ClickHouse evaluates the set. #124339 (Groene AI). - Fixed silent data loss when an
EmbeddedRocksDBtable is renamed.RENAME TABLEnow moves the table’sRocksDBdirectory to the table’s new location, so the rows are still there after a server restart. Previously the directory was left behind, and after a restart the table opened a fresh emptyRocksDBwhile the real rows stayed orphaned under the old path. #112224 (Groene AI). optimize_inverse_dictionary_lookup(enabled by default) no longer rewritesdictGet(dict, attr, key) = constwhen aVariant,Dynamic, orJSONappears in the type ofkeyor in the dictionary’s declared key type. The rewritten predicate is not equivalent there, so the query could fail withCANNOT_INSERT_NULL_IN_ORDINARY_COLUMN,ILLEGAL_TYPE_OF_ARGUMENT, orNO_COMMON_TYPE, or return wrong results. #120888 (Groene AI).- Fixed SQL injection through identifiers in the
PostgreSQLintegration: relation, schema, column, publication, and replication-slot names used by thePostgreSQLtable engine, thepostgresqltable function,PostgreSQLdictionary sources, andMaterializedPostgreSQLwere escaped with backslashes, which PostgreSQL does not honour inside a quoted identifier, so a remote name containing a double quote could end the identifier and let the rest execute on the PostgreSQL server. Relations and columns whose names contain a double quote or a backslash can now be read and replicated, including those listed inmaterialized_postgresql_tables_list; an empty element in that setting is now rejected. #119216 (Groene AI). #119103 (Groene AI). - Fixed
PARALLEL WITH,EXECUTE AS, and theQueryRunnertable engine skipping the access checks of theCREATEstatements they execute, which allowed creating tables and databases without the corresponding privileges and defeated thereadonlyandallow_ddlsettings. #119848 (Alexey Milovidov). - Fixed an
HDFSdatabase serving a table from its internal cache without theREAD ON HDFSgrant. The grant and theremote_url_allow_hostsfilter were checked only while a table name was resolved for the first time, so once any user holding the grant had read a name, every user withSELECTon the database was served the contents of the file, and that table kept being served after its host was removed from the allow-list.EXISTS TABLE, which requires onlySHOW TABLES, answered from the same cache and so reported which names other users had resolved. Both checks now run before the cache is consulted, and the existence probe no longer consults it. #119523 (Groene AI). - Fixed filesystem containment checks accepting a path with an embedded NUL byte. A
DeltaLakeLocalorIcebergLocaltable could be pointed outside ofuser_filesthis way. #119846 (Alexey Milovidov). - Fixed several engines disclosing an
Aliastable’s target schema to a user who holds no privilege on that target. Reading the metadata of anAliasthrough any of them now requires table-levelSHOW COLUMNSon its target, which is what aDESCRIBEof the target already requires. #117572 (Groene AI). remote(<cluster name>, 'db', 'table', 'user', 'password'), and the same form ofremoteSecureand of theRemoteandRemoteSecuretable engines, no longer write the password intosystem.query_log,system.text_log, and the server log in cleartext. #121474 (Groene AI).- Fixed SQL injection through identifiers when inserting into a table with the
SQLiteengine. It is now also possible to insert into a SQLite table whose name, or column name, legitimately contains a double quote or a backslash. #117421 (Groene AI). - Fixed credential masking for
nats_url,rabbitmq_address, thejdbcandodbcconnection string, and theformat_avro_schema_registry_url,url_base, ands3_basesettings inSHOW CREATE,system.tables, and the query text insystem.query_log. Closes #121257. #121425 (Groene AI). - Fixed a
Backupdatabase engine printing the credentials of its destination in plaintext.SHOW CREATE DATABASE,system.databases.engine_full,system.query_log, and the messages that reject a malformed locator no longer expose anAzureBlobStorageaccount_key, a connection string, or a presigned URL regardless offormat_display_secrets_in_show_and_select. #117429 (Groene AI). KILL TRANSACTION ... ON CLUSTER,KILL PART_MOVE_TO_SHARD ... ON CLUSTER,SYSTEM STOP THREAD FUZZER ON CLUSTER,SYSTEM START THREAD FUZZER ON CLUSTER, andSYSTEM RESET COVERAGE ON CLUSTERno longer run without checking any privilege. Each now requires what its non-ON CLUSTERspelling has always required. #118360 (Groene AI).- Fixed metadata disclosure through a chain of
Aliastables.DESCRIBE,hasColumnInTable,system.columns,system.tables,system.projections,system.constraints, andsystem.data_skipping_indicesnow require the privilege on every table anAliasresolves through, as reading its rows already did. #118967 (Groene AI). - Fixed a bug where
REVOKE GRANT OPTION FORwas accepted but then omitted fromSHOW GRANTS, fromsystem.grants, and from the persisted access metadata whenever another revoked database, table, column, or named-collection name shared a prefix with it. The grant option therefore came back after a server restart, and the user could pass it on withGRANT CURRENT GRANTS. #122078 (Groene AI). - Fixed settings constraints from a settings profile not being enforced against the other setting assignments in the same statement.
SET profile = 'p', <setting> = <value>could override aCONST,MIN/MAX, orreadonlyconstraint that profilepinstalls. The same escape existed through an in-querySETTINGSclause, HTTP URL parameters, and Arrow Flight session options. #120376 (Raúl Marín). - Fixed row policies on
Memorytables being ignored when a read is executed from a serialized query plan, such as a distributed plan or a parallel-replicas plan. SinceMemorygainedPREWHEREsupport, such reads could return rows the policy excludes. #122503 (Alexey Milovidov). - Fixed an integer underflow in the
MySQLprotocol handshake handler that could cause the server to buffer an unbounded amount of data from an unauthenticated client. #115776 (Dmitrii Tishkin). - Statistics-based part pruning is now disabled for tables with row policies. #122035 (alesapin).
- A row policy on a
Set-engine table was accepted but never applied: the right side ofINread the prebuilt set directly and returned the rows the policy hides. Such a query now fails withACCESS_DENIED, because theSetengine has no read path that could filter those rows, andIN set_tablenow requiresSELECTon all columns of the table. OnReplicateddatabases,ALTER ... DELETE,ALTER ... UPDATE,DELETE, andUPDATEnow run the initiator’s checks as the submitting user, so the same row-policy and access checks apply there too; withON CLUSTER, run the query on a host that has the right-handSettable, or enabledistributed_ddl_use_initial_user_and_roleson every host and setdistributed_ddl_entry_format_versionto at least8. Queries that used aSettable covered by a database-wide row policy ran unfiltered before and now throw. #120312 (Harikrishnan Prabakaran). #122141 (Alexey Milovidov). - Fixed the
KafkaandNATStable engines ignoringremote_url_allow_hosts: broker addresses fromkafka_broker_list,nats_url, andnats_server_listare now checked against the remote host filter. A forbidden address is rejected atCREATE TABLEwithUNACCEPTABLE_URL, as theRabbitMQengine already does. #121825 (János Benjamin Antal). - HTTP headers in
HTTPdictionary sources are now hidden inSHOW CREATE DICTIONARY,system.tables, and query logs, like passwords. They can still be shown withdisplay_secrets_in_show_and_select. #122673 (Matheus Nerone). - Fixed secret settings of
S3QueueandAzureQueuetables written with the legacys3queue_prefix, such ass3queue_after_processing_move_secret_access_key, being shown in cleartext inSHOW CREATE TABLE,system.tables,system.query_log, and the server log. They are now hidden as they are without the prefix. #123060 (Groene AI). - Column-level
SELECTprivileges are now enforced for columns used only insideindexHintand forALIAScolumns referenced inPREWHERE. As inWHERE, referencing anALIAScolumn inPREWHERErequires the grant on the alias name; a grant on its source columns is no longer sufficient. A metadata-onlyALTERthat changes a subcolumn read by aMATERIALIZEDcolumn through anALIASis now refused like a direct reference. #120516 (Shankar Iyer). - Fixed a row policy bypass: a direct
JOINwith anEmbeddedRocksDB,KeeperMap, orRedistable in the legacy analyzer (enable_analyzer = 0) ignored the row policy of the right table and returned hidden rows, andjoinGeton aJointable ignored its row policy in both analyzers. Such a table is now joined through its query plan, which keeps the filter, andJOINorjoinGetagainst aJointable under a row policy throwsACCESS_DENIED. #121398 (Vladimir Cherkasov). CREATE OR REPLACEin aReplicateddatabase or withON CLUSTERnow requires the drop privilege for the kind of the table it replaces, so a user withoutDROP DICTIONARYcan no longer replace a dictionary. #122272 (Nikolay Degterinsky).- A view with
SQL SECURITY DEFINERorSQL SECURITY NONEthat can hide rows is now read as a whole and is opaque to the optimizations of the query that reads it; previously an expression of the outer query could be evaluated on the hidden rows and reveal them, for example through an exception message.EXPLAINshows the plan of such a view only to users who could have created it or who may display secrets, and seeing the plan of such a sealed view now also requires theCREATE VIEWprivilege. #122330 (Alexey Milovidov). #123325 (Alexey Milovidov). - Fix a credential written in cleartext to
system.query_logand the server log when akey = valueargument precedes the positional arguments of themongodb,redis,remote,arrowFlight, andytsaurustable functions or theMongoDB,Redis,Remote,ArrowFlight,ExternalDistributed, andYTsaurustable engines. A positional argument after a named one is now always hidden, and the value of a named-collection override whose key is written as an expression is hidden for every such engine. #122770 (Raúl Marín). - Rewriting the body of a view with
ALTER TABLE ... MODIFY QUERYnow needs the same grants as creating it with its SQL security:SET DEFINERon the definer of aSQL SECURITY DEFINERview, orALLOW SQL SECURITY NONEfor aSQL SECURITY NONEview. AnON CLUSTER MODIFY QUERYfails withUNKNOWN_TABLEunless it runs on a host that has the view. #121629 (Sema Checherinda). - Fixed
GRANT ... ON db*.tablebeing silently rewritten todb.table*, which could cause incorrect privilege grants. The patterndb*.tableis now rejected as a syntax error.CREATE/ALTER/DROP ROW POLICY,SHOW POLICIES, andSHOW CREATE POLICYnow also reject prefix wildcards (db*.*,db.table*,table*), which were previously silently narrowed to the exact name (db.*,db.table,table). #108063 (Aditya Kumar). - Update
mongo-c-driverto 2.5.6 andmongo-cxx-driverto r4.6.0, fixing an out-of-bounds write during MongoDB connection monitoring reconnects (CVE-2026-96746). #119346 (Actuele AI). #124282 (Actuele AI). #124648 (Actuele AI). - Fixed access entities (users, roles, row policies, and others) of the
local_directoryaccess storage being lost after a restart, or a dropped row policy making every query fail withFILE_DOESNT_EXIST. This happened to entities created or dropped within a minute afterSYSTEM RELOAD USERSif the server was then killed, or at any time afterSYSTEM RELOAD USERSfailed to write the storage’s.listfiles. #125058 (Groene AI). - The web terminal and the SSH interface no longer reset the settings of the user (from settings profiles, roles, and
CREATE USER ... SETTINGS) to default values. Previously, restrictions such asreadonly, resource limits, andadditional_table_filterswere not applied in these interfaces. #125515 (Alexey Milovidov). - Update
expatto 2.9.0, fixing a denial of service through a crafted backup manifest duringRESTORE(CVE-2026-66046) and the other 2.8.3–2.9.0 security fixes. #124255 (Actuele AI). - Fixed failures during pipeline expansion, such as external sorting or the merge stage of a
GROUP BY, when the memory limit is exceeded. The query now reports the original exception instead of an inconsistent-pipeline error, a segmentation fault, or a read of freed memory. Closes #125251. #121502 (Alexey Milovidov). #125283 (Groene AI). - Fixed a stored query combining
UNIONwith a parenthesizedINTERSECT/EXCEPTgroup losing its parentheses when serialized, soX UNION ALL (Y EXCEPT Z)was read back as(X UNION ALL Y) EXCEPT Z. Views returned wrong results after a server restart, and a materialized view could end up with metadata the server refuses to load, which prevented it from starting. #111931 (Groene AI). - Fixed the
compatibilitysetting:compatibility = '26.8'no longer reverts five defaults that 26.8 shipped or forcesMergeTreepatch_parts_versionback tov1, andcompatibility = '26.1'no longer disablesuse_skip_indexes_on_data_read, which 26.1 shipped enabled. #118666 (Alexey Milovidov). - Fixed
compatibility = '25.11'incorrectly resolvingquery_plan_max_limit_for_lazy_materializationto10instead of100. #122768 (Raúl Marín). - Setting the obsolete
enable_analyzer(allow_experimental_analyzer) to0is accepted again and replaced with1, instead of failing withSETTING_CONSTRAINT_VIOLATIONorINCORRECT_QUERY. Queries, sessions, settings profiles, and client configurations that still set it keep working after an upgrade, always with the analyzer, including configurations that spell the value as aFloat64literal. #122401 (Nikita Fomichev). #122763 (Raúl Marín). - Fixed a server crash on AArch64 that could happen when the query profiler sampled a thread while it was connecting to a remote server, for example with
remoteorremoteSecure. Capturing stack traces, used for exceptions and by the query profiler, is also several times faster. #122834 (Raúl Marín). - Fixed
listen_host::on hosts without a global IPv6 address, such as a container on an IPv4-only Docker network: it failed with a DNS error, so the official Docker image listened on IPv4 only andlocalhostover::1was refused. The server now listens on the dual-stack wildcard there. gRPC and Arrow Flight use one listener when::is the only wildcard, andhost_regexp/HOST REGEXP/HOST LIKErestrictions match IPv4 clients of a dual-stack listener. #122785 (Groene AI). - Fixed an issue where pressing Ctrl-R and then Ctrl-Z in the web terminal or the SSH interface suspended the whole server process. #125512 (Alexey Milovidov).
- Fixed
TOO_LARGE_STRING_SIZE(Too large sizes of FixedString to deserialize) when reading a correctly written part whoseArray(FixedString(N))column holds more than 1 GiB of elements in one read span. Such a span is now read in bounded steps instead of being rejected, so the affected parts can be read and merged again without being rewritten. Closes #116772. #117385 (Groene AI). - Fixed
CollapsingMergeTreereturning wrong rows when a row’ssignis neither1nor-1. #119900 (Murphy). - Fixed a table that exceeds
max_table_size_rowsnever being able to come back under the limit: every merge threwTABLE_SIZE_LIMIT_EXCEEDED, so the table could not be compacted and its part count grew until inserts started failing. #117229 (Alexey Milovidov). - Fixed a shutdown stall where a background merge or mutation left in a
MergeTreebackground executor’s queue kept holding its table lock, so any table lock taken later during shutdown waited for the fulllock_acquire_timeoutand then failed withDEADLOCK_AVOIDED. #113653 (Groene AI). - Fixed
count()returning the number of default values instead of the number ofNULLs whenoptimize_trivial_count_with_sparsity_filteris used on a column widened toNullableby a metadata-onlyALTER TABLE ... MODIFY COLUMN. #120245 (Raúl Marín). - Fixed
MergeTreetables withnon_replicated_deduplication_windowon object storage failing to load their deduplication log after being detached and attached back without inserts in between, and fixed the deduplication log possibly dropping its active file. #121670 (Alexey Milovidov). - Fixed
ALTER TABLE ... COMMENT COLUMNandALTER TABLE ... RENAME COLUMNmaking reads of anALIAScolumn’s subcolumns, for examplearr.size0, fail withNO_SUCH_COLUMN_IN_TABLEuntil the table was reloaded. Closes #121421. #121449 (Groene AI). - Fixed
CANNOT_READ_ALL_DATA(while reading prefix of column ...) during query planning when aMergeTreetable has an active empty Wide part, left by aTTLdrop or by a mutation that deleted all rows of a part, and the query filters on a subcolumn, such as a key of aMap(LowCardinality(String), String)column. #122756 (Groene AI). - Fixed
ATTACH PARTfailing withCORRUPTED_DATAfor a Compact part whosedefault_compression_codec.txtis missing, for example a part copied or restored without that file. #119114 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR(Sizes of nested column and null map of Nullable column are not equal after deserialization) that made aSELECTof aNestedmember fail withCode: 49until the server was restarted, after anALTER TABLE ... MODIFY COLUMNon that member had been killed and a later mutation hardlinked the column into a new wide part. #121561 (Groene AI). - Wide parts no longer split a fixed-width value across two compressed blocks when
max_compress_block_sizeis not a multiple of the value size. This improves the compression ratio of type-specific codecs on such tables and fixesCANNOT_COMPRESSfromALP. #122841 (Raufs Dunamalijevs). - After
ALTER TABLE ... RENAME COLUMN, the subcolumns of the renamed column, for examplec0.nullora.size0, stayed resolvable under the old name. Reading them through aBufferorMergetable, or using them inOPTIMIZE ... DEDUPLICATE BY, read uninitialized memory, and once a new column reused the old name they returned wrong values instead of throwingUNKNOWN_IDENTIFIER. #122527 (Groene AI). - Fixed excessive memory usage when loading a data part with a corrupted
columns_substreams.txt; such a part is now detached as broken. #124157 (Murphy). - Fixed a
LOGICAL_ERRORand silent data corruption when a column is named into theskp_idx_prefix so that its on-disk stream base equals a skip index’s, making both share one marks file. Such a write is now rejected withINCORRECT_FILE_NAMEnaming both owners. #113093 (Groene AI). - Fixed reads of a renamed
Nestedleaf column returning default values from wide parts while theRENAME COLUMNmutation was still pending. #119134 (Alexey Milovidov). - Fix
CANNOT_COMPRESSon merge or insert for aMapcolumn withwith_bucketsserialization andCODEC(T64). #124695 (Raufs Dunamalijevs). - Fixed a column added by
ALTER TABLE ... ADD COLUMN ... DEFAULT <expression>being filled with the type default instead of the evaluated expression when it is read through a single-conjunct explicitPREWHEREon the expression’s dependency. #117533 (Alexey Milovidov). - Fixed the order of rows in a data part written by a merge or a mutation with
TTL ... GROUP BY ... SETwhen theSETclause assigns a new value to a column the sorting key is calculated from. Closes #108514. #119863 (Alexey Milovidov). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen merging a table that has a rows TTL together with a move (TO DISK,TO VOLUME) or recompression (RECOMPRESS) TTL over a different column. #121536 (Murphy). - Fixed
INSERTinto a table with a constantTTL ... DELETE WHEREwhose condition is not exactlyUInt8, for examplec > 10over aNullablecolumn: a part where no row matched the condition was marked with the delete TTL and later rewritten by a needless TTL merge, and a condition that cannot be a filter, such as anArraycolumn, was accepted instead of being rejected as in the other TTL code paths. #122516 (Groene AI). - Fixed
INSERTinto a table whoseTTLexpression changes its type under a session setting, for example aCASTof aNullablecolumn undercast_keep_nullable = 1, which failed withLOGICAL_ERRORUnexpected type ... of result TTL column. Under such a setting,ALTER TABLE ... MODIFY TTLcould also store aTTLthatCREATE TABLErejects, after which the table could not be attached again. A storedTTLis now analyzed with the server settings inINSERTandALTER, as inCREATE TABLE. #122973 (Groene AI). - Fixed an unsorted part with a primary index that did not match the data after a
TTL GROUP BY ... SETmerge that rewrites the column a subcolumn sorting key (such asORDER BY n.a) is taken from. Queries with a condition on the sorting key could return wrong results. #122373 (Alexey Milovidov). - Fixed
ALTER TABLE ... MODIFY TTLaccepting a TTL whose subquery reads a table function (for examplenumbersorremote), a view over one, a parameterized view, a temporary table, or the table itself. After such anALTERthe table could not be loaded again, so a server with synchronous table loading did not start. Now theALTERfails. #123561 (Groene AI). - Fixed standalone
UPDATE ... SETsubstituting aWITHexpression alias into a nested subquery that cannot resolve it. Where that name is a table name, the statement read the alias instead of the table, or silently succeeded where the equivalentSELECTraisesUNKNOWN_IDENTIFIER. #120026 (Groene AI). allow_non_metadata_alters = 0now also rejects theALTERcommands that reach aMergeTreetable as explicit mutations:UPDATE,DELETE WHERE, the fiveMATERIALIZEforms,APPLY DELETED MASK,APPLY PATCHES, andREWRITE PARTS. #115287 (Groene AI).- Fixed
Cannot convert NULL value to non-Nullable typeinALTER TABLE ... UPDATEwith a scalar subquery when the subquery result isNullableand the updated column is not. #119926 (Alexey Milovidov). ALTER TABLE ... DROP COLUMNandALTER TABLE ... CLEAR COLUMNare now refused when they would leave a part with no columns at all, instead of wedging the mutation queue with a logical error or leaving an unreadable part. #121104 (Alexey Milovidov).- Fixed a mutation such as
ALTER TABLE ... MODIFY COLUMNorRENAME COLUMNcommitting a data part with no columns when the part held only columns the table no longer has (for example a partition detached beforeDROP COLUMNand re-attached after it), after which every read of the table failed with a logical error. Such a mutation now fails withNO_SUCH_COLUMN_IN_TABLE, like reads of that part, and the part and its data are kept. #122400 (Groene AI). - Fixed
ALTER TABLE ... UPDATEandMATERIALIZE COLUMNon aMemorytable afterMODIFY COLUMNof the updated column: later reads failed withILLEGAL_COLUMNor returned wrong values, andBACKUPfailed. #123043 (Groene AI). - Fix
Found patch part ... that intersects mutation with version ...on lightweight updates in a table created withCREATE TABLE ... CLONE ASorATTACH PARTITION ALL FROMa table with lightweight updates. #123620 (Nikolay Degterinsky). - A synchronous mutation (
mutations_sync) on aMergeTreetable no longer reports success when the table is detached before the mutation runs; it fails withUNFINISHED, and the mutation continues after the table is attached again. #124161 (Murphy). DELETE,UPDATEandALTER ... DELETE/UPDATEno longer refuse aMergeTreetable of a database withlazy_load_tablesthat has not been accessed yet, andSYSTEM DROP REPLICA ... FROM ZKPATHno longer skips such a table when checking that the replica being dropped is not a live local one. #118152 (Alexey Milovidov).- Fixed a
ReplicatedMergeTreetable whose metadata carriestable_readonly = 1being unusable: its backup could not be restored, it could not be re-attached afterDETACH, andALTER TABLE ... MODIFY SETTING table_readonly = 0was refused. Converting a table with that setting to replicated is no longer done, by either theconvert_to_replicatedflag orATTACH TABLE ... AS REPLICATED. #119224 (Alexey Milovidov). CHECK TABLEon aReplicatedMergeTreereplica whose Keeper session was lost now fails withABORTEDinstead of returning0, which means that the check found broken data. Nothing was read in that case, so the healthy table was certified as broken. #119381 (Alexey Milovidov).- Fixed the automatic
MergeTreetoReplicatedMergeTreeconversion silently not finishing for a table in a database withlazy_load_tables, which left the table read-only with no metadata in ZooKeeper and the conversion flag in place. #118135 (Alexey Milovidov). - Fix an integer overflow in the DDL log retention check of
Replicateddatabases that could cause premature removal of DDL log entries and replicas being incorrectly declared lost for a very largelogs_to_keep.logs_to_keepis now limited to2147483647, so replicas on older releases also stay safe during a rolling upgrade: out-of-range values are rejected onCREATEand clamped, with a warning, when replayed from existing metadata, server config, or Keeper, and existing databases that hold a larger value in Keeper are fixed automatically when a replica on the new release starts. #118103 (Kirill Shokhin). #123105 (Kirill Shokhin). ALTER DATABASE ... MODIFY COMMENTon a database withENGINE = Backupno longer writes a definition the server cannot read back, which made it refuse to start; metadata already written in that form now loads too. Backward incompatibility: a backup taken by an older server of a database withENGINE = Backupstores the locator quoted into a string literal, and such a definition is no longer accepted from aRESTORE. #118674 (Alexey Milovidov).- Tables in a database with
lazy_load_tableswere missing fromsystem.parts,system.replicasand related system tables, and refused by replica commands, after a restart. #121332 (Nikolay Degterinsky). - Fixed the server failing to start with
TABLE_ALREADY_EXISTSorMapping for table with UUID=... already existsafter it was killed duringCREATE OR REPLACE TABLE,REPLACE TABLE, orCREATE TABLE ... AS SELECTin anAtomicdatabase whose metadata is on aplain_rewritabledisk (database_disk). #123902 (Alexey Milovidov). #123832 (Groene AI). - Fixed
EXISTS TABLEreturning0for a table that is still being loaded asynchronously after server startup. #125729 (Alexey Milovidov). - Fixed
SELECT ... FINALreturning a superseded row when the partition expression distinguishes floating-point values that theFINALmerge comparator treats as equal, such as-0.0versus0.0or differentNaNpayloads.enable_automatic_decision_for_merging_across_partitions_for_finalno longer engages for such a key. #117482 (Alexey Milovidov). - Row policies over floating-point sorting key columns are now applied after
FINAL, withapply_row_policy_after_finalenabled, and such columns are excluded from index analysis of deferred filters. Previously a policy condition distinguishing-0.0from0.0orNaNpayloads could filter out the winning row version before the merge and return stale data. #121782 (Yarik Briukhovetskyi). CREATE TABLEandALTER TABLE ... ADD INDEXnow reject a skip index whose expression cannot be evaluated, such asINDEX i c0 = c1 TYPE set(0)overStringandInt8, and anALTER TABLE ... MODIFY COLUMNthat would leave an existing index in that state is rejected too. Such a declaration used to be accepted, after which everyINSERTand merge failed withNO_COMMON_TYPE, andMATERIALIZE INDEXretried that error forever. Closes #69597. #118373 (Groene AI).- Fixed
SELECT count()returning more rows than the filter accepts when aMergeTreeprimary key is aTupleholding a floating point element and the key data contains anan. For example, withORDER BY tovert Tuple(Float64, Int32),SELECT count() FROM t WHERE t >= (5., 3)returned6whileSELECT * FROM t WHERE t >= (5., 3)returned2rows. Anannested in a tuple is not visible in the granule bounds, so primary key analysis reported a granule of non-matching rows as wholly matching and the exact-count optimization counted its rows without evaluating the filter. Closes #117819. #118683 (Groene AI). - Fixed
WHERE f IN (nan)silently losing theNaNrows of a floating-point column: statistics-based part pruning and theminmaxskip index use ranges that excludeNaN, so a part or granule holdingNaNwas pruned even thoughINmatchesNaN. #117453 (Alexey Milovidov). - Fixed wrong results when a
Stringprimary key column is compared against aFixedStringconstant wrapped inVariantorDynamic. #114353 (Groene AI). - Fixed wrong results for
f = 0.0andf != 0.0over a float column when the primary key is an injective transform of it (for exampleORDER BY toString(f)): the index treated the transformed constant as exact, although the transform distinguishes-0.0from+0.0while the comparison does not. #117722 (Alexey Milovidov). - Comparing an
Enumcolumn with a string literal that is not one of its elements no longer throwsUNKNOWN_ELEMENT_OF_ENUMwhenvalidate_enum_literals_in_operatorsis disabled (the default) and the column is part of the primary key, the partition key, or abloom_filterindex.!=with such a literal now returns true for every row instead of throwing. Closes #122235, #111545. #122672 (Vladimir Cherkasov). - Fixed an exception (such as
Division by zero) thrown from index analysis when a monotonic function chain over a key column cannot be evaluated on a key range endpoint, for exampleSELECT count() FROM t WHERE p != 1 AND intDiv(1, p - 1) > 0withuse_skip_indexes = 0. Also fixed a possible segmentation fault caused by a poisoned entry in the index analysis function result cache. #117355 (Alexey Milovidov). - Fix a
bloom_filterskip index onmapValuesormapKeysthat dropped rows form['k'] IN (...)when the map values are anEnumwith negative values and the set contains the name of the value0. #124232 (Alexey Milovidov). - Fix a wrong order (and wrong rows under
LIMIT) from the read-in-order optimization when theORDER BYexpression maps a storedinftoNaN, as inORDER BY x / inf. #118720 (Alexey Milovidov). - Fixed primary key, partition key, and skip index analysis that could skip or over-count rows, and
ORDER BYoptimization that could return rows in the wrong order, for conditions ontimezoneOffset,toTimeWithFixedDate,toYYYYMMDDhhmmss,toHour, andtoMinuteover aDateTimeorDateTime64column when the key range spans a change of the UTC offset, for example a daylight saving time change inAmerica/New_Yorkor the 30-minute change inAustralia/Lord_Howe. #124474 (Groene AI). #124530 (Groene AI). - Fixed wrong results of
ORDER BYwithoptimize_read_in_order,GROUP BYwithoptimize_aggregation_in_order, andLIMIT BYwith the in-order optimizations when aStringsorting-key column is compared with aFixedStringconstant, also one held by aVariantorDynamicconstant (for exampleWHERE s = toFixedString('a', 2)orWHERE s = CAST(toFixedString('a', 2) AS Dynamic)), or when aVariantorDynamicexpression, such as a JSON path, is compared with a constant (for exampleWHERE j.a = 1overInt64andFloat64values). Such a comparison matches several values that sort differently, but the optimization treated them as one value and skipped sorting by them. #123677 (Ashish Kumar Choubey). #125378 (Samuel Krempaský). - Fixed
count()counting rows that the filter rejects when a whole-tuple comparison against aTupleprimary key involves aNULLor aNaNnested in the constant, or aNaNnested in the key data. #118944 (Alexey Milovidov). - Fixed wrong result order (and wrong rows under
LIMIT) from the read-in-order optimization whenORDER BYis a monotonically decreasing function of aFloatsorting key containingNaN, e.g.ORDER BY negate(x). The opposite request for the same shape,ORDER BY negate(x) ASC NULLS FIRST, is now read in order instead of being sorted. #118469 (Alexey Milovidov). - Fixed repeated reading of text index posting lists in multi-threaded queries when the global text index caches are disabled. #120844 (Anton Popov).
- The
text,tokenbf_v1,ngrambf_v1, andsparse_gramsskip indexes are now used forINwhentransform_null_in = 1and the set contains noNULL. Previously such a query read every granule, and one usingforce_data_skipping_indicesfailed withINDEX_NOT_USED. #121375 (Jimmy Aguilar Mena). - Fixed wrong results and the exception
Column ... already added for readingfor aFINALquery withquery_plan_optimize_lazy_final = 1that reads atextindex directly, when theReplacingMergeTreesorting key isNullable, floating-point, or mixesASCandDESCcolumns. #122534 (Groene AI). - On a column whose
textindex has a postprocessor,hasPhraserejoined the index tokens with a space before matching, so it returned wrong results unless that space matched how the tokenizer splits. AllowinghasPhraseto accept anArray(String)removes joining tokens completely. #120859 (Elmi Ahmadov). - Fixed a
textindex withtokenizer = 'japanese'returning fewer rows than a full scan: over aLowCardinalitycolumn every second row of a run of equal values was not indexed, and two search terms of the same byte length in one query (for examplehasAnyTokens(s, 'エンジン', 'japanese') AND hasAnyTokens(s, '形態解析', 'japanese')) matched no rows. Indexes built before this fix keep the missing rows untilALTER TABLE ... MATERIALIZE INDEXis run. #123389 (Groene AI). - Fixed a query failing with an exception like
Cannot parse UInt64 from Stringon a table with a text index onmapKeysorJSONAllPaths, when the predicate cannot be evaluated on the value of a missing map key or JSON path. #124612 (Anton Popov). - Fixed
count()with a text index search function such ashasToken,hasAnyTokens, orhasAllTokensinWHEREand a constantGROUP BYkey returning a row with0instead of no rows when nothing matches. #124593 (Groene AI). - Fix
hasAnyTokenswith aStringneedle on a text index with thesparseGramstokenizer returning fewer rows than the equivalentArrayneedle. Grams covered by a longer gram of the needle were dropped, which is only valid forhasAllTokens. #124613 (Jimmy Aguilar Mena). - Fixed slow planning of queries with a text index on tables with many parts when other skip indices are stored in the packed
skp_idx.packedarchive. Checking for an absent optional text-index file no longer callsstaton disk for every part. #125381 (Anton Popov). - Fix
ALTER TABLE ... MATERIALIZE STATISTICS/DROP STATISTICSfailing forever and wedging the table’s mutation queue when a server profile setsallow_statistics = 0and the statement enables it per-session, the same opt-inADD STATISTICShonours. Also close a hole whereMATERIALIZE STATISTICSignoredallow_statistics = 0altogether undervalidate_mutation_query = 0. #117351 (Alexey Milovidov). - Fixed a mutation silently dropping one of two swapped columns’ statistics when the part carried a composed
RENAME COLUMNpair that exchanged their names. #118977 (Alexey Milovidov). - When the query cache is unable to store results (with
enable_writes_to_query_cache = 0, inclickhouse-local, or with a zero limit in thequery_cacheserver configuration), queries withuse_query_cache = 1no longer fail withQUERY_CACHE_USED_WITH_NONDETERMINISTIC_FUNCTIONS,QUERY_CACHE_USED_WITH_SYSTEM_TABLEorQUERY_CACHE_USED_WITH_NON_THROW_OVERFLOW_MODE: these checks protect against caching wrong results, which cannot happen then. When aquery_cachelimit is reconfigured to 0, the existing entries are now dropped instead of lingering. #123604 (Konstantin Bogdanov). LIMIT [n] AFTER start_expr UNTIL end_exprnow checksend_expronly afterstart_exprfirst matches. Previously a match ofend_expranywhere before the firststart_exprincorrectly made the result empty. #120514 (Nihal Z. Miaji).- Fixed
SELECT DISTINCTandLIMIT BYover a floating point column returning a different number of rows depending on whether the in-order variant of the operator was used:-0.0and0.0, and distinctNaNpayloads, are no longer merged by the in-order variant. #118198 (Alexey Milovidov). - Fixed a higher-order function with a non-deterministic lambda body, such as
arrayMap(i -> rand64(i), ...), being evaluated once per source row instead of once per output row afterARRAY JOINwhen lazy columns replication is enabled. #120796 (Yarik Briukhovetskyi). - Fixed a performance regression where a query whose
WHERErequires the same expression to equal two different constants stopped being recognized as always false whencompatibilitywas set below26.7, or whenoptimize_redundant_comparisonswas disabled explicitly. Closes #121007. Closes #121012. #121065 (Groene AI). - Fixed
NOT_AN_AGGREGATEbeing thrown for aGROUP BYkey referenced from a window function whengroup_by_use_nullsis enabled together withROLLUP,CUBE, orGROUPING SETS, as inSELECT rank() OVER (PARTITION BY k) FROM t GROUP BY k WITH ROLLUP. #118173 (Groene AI). - Fixed
AMBIGUOUS_IDENTIFIERfor a column qualified with the alias of a table expression when another table of the same query is named like that alias. Such a qualifier now refers to the alias, as it does in the old analyzer, both in a join that reported the ambiguity and in a two-table join that resolved it to the other side. #119082 (Alexey Milovidov). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen a query tree pass rewrites a window function’s aggregate in place. A query whose only reference to aNullablecolumn was a windowedcount, such asSELECT count(n) OVER () FROM t, was rejected at default settings becauseoptimize_functions_to_subcolumnsrewrote it intosum(not(n.null))and lost the node’s window kind.optimize_uniq_to_countcorrupteduniq(n) OVER ()over aSELECT DISTINCTsubquery the same way. Closes #119635. #119681 (Groene AI). - Fix a wrong result from
optimize_injective_functions_in_group_byon the two-argument formtoString(x, timezone).GROUP BY toString(number, NULL)could be rewritten toGROUP BY numberand produce one group per row instead of one. #117197 (Ilya Yatsishin). - Fixed a server crash in
CREATE TABLE ... AS <table function>when an argument of the table function is a scalar subquery with aJOINandenable_join_runtime_filters_index_analysisis enabled in the default settings profile. #122795 (Groene AI). - Fixed table names not being qualified with the database when a
WITHname declared elsewhere in the same query happened to match them: a view whoseUNIONbranch referenced a table with the name of aWITH RECURSIVECTE of another branch could not be read from another database, andALTER TABLE ... UPDATEwith a common table expression referenced from a subquery failed withUNKNOWN_DATABASEor read a table of the session database. #114908 (Groene AI). - Fixed
INagainst a table-backed set (ENGINE = Set), or withtransform_null_in = 1, throwingCANNOT_CONVERT_TYPEfor probe values outside the set key type’s range instead of evaluating them to false, which also made the query succeed or fail depending on how much the plan pruned. #117606 (Alexey Milovidov). - Fixed a crash and wrong results with
convert_query_to_cnf = 1whenWHEREorHAVINGreferences the sameSELECTalias more than once. #123414 (Groene AI). - Fixed wrong results,
Unexpected return type from tupleElementerrors andNOT_FOUND_COLUMN_IN_BLOCKerrors when aNestedcolumn is read throughARRAY JOINwith a numerictupleElementindex (for exampletupleElement(n, 3)) while another subcolumn is unused, and the same expression is reused byORDER BY ALL,GROUP BY ALLor an alias. #123647 (Groene AI). - Fix
UNKNOWN_IDENTIFIERin the analyzer when a table is referenced asdatabase.tableinFROMorJOINand another table expression in the same query uses that database name as its alias, for exampleFROM db.t1 AS db INNER JOIN db.t2 AS t ON .... Closes #122239. #124262 (Dmitry Novik). - Fix a wrong result, a leaked totals row, and a
LOGICAL_ERRORexception withrewrite_in_to_joinwhen the subquery ofINusesWITH TOTALS. #124096 (Alexey Milovidov). - Fix
Unexpected return type from __topKFilterlogical error raised byORDER BY ... LIMITover aMergeTreetable with more than one part when the sort column contains aNullableelement, for exampleTuple(UInt64, Nullable(UInt64)).use_top_k_dynamic_filteringis enabled by default, so no opt-in setting was required to hit this. #113406 (Groene AI). - Reject a duplicate column alias name in a CTE or table expression, which previously could return an incorrect result instead of failing. Closes #114427. #114505 (Yarik Briukhovetskyi).
- Fixed
APPLY lambda(tuple(x), ...)followed by an operator, as inSELECT * APPLY lambda(tuple(x), toString(x)) > '0', which failed withUNKNOWN_IDENTIFIER. A view usingAPPLY (lambda(...))followed by an operator also stopped working after a server restart. #124142 (Groene AI). - Fix a logical error
Equal values are not contiguous within the range assumed to be sorted(and potential wrongDISTINCTresults) whenoptimize_distinct_in_orderis enabled and anORDER BYover anarrayJoin-derived column is followed by anotherARRAY JOINthat reproduces a column of the same name. #110778 (Groene AI). - Fixed wrong results and a
LOGICAL_ERROR(Cannot capture column ... because it has incompatible type) when a matcher such asb.*,*,COLUMNS('...'), orb.* EXCEPT cappears inside a lambda body. A matcher expanded inside a lambda kept its pre-JOINcolumn types, sojoin_use_nulls = 1did not turn columns from theNULLside of aLEFT/FULL/RIGHT JOINintoNullable(unmatched rows produced a value computed over defaults instead ofNULL), andgroup_by_use_nulls = 1withWITH ROLLUP/WITH CUBE/GROUP BY GROUPING SETSfailed withNOT_AN_AGGREGATE. A matcher expanded inside a lambda now carries the same types it would have if the columns were written out explicitly, and a lambda insidePREWHEREis no longer promoted toNullablebyjoin_use_nulls. Also fixed wrong results for a matcher inside a lambda whenanalyzer_compatibility_join_using_top_level_identifier = 1makes aJOIN ... USINGkey resolve to aSELECTprojection alias: the matcher selected the mergedUSINGkey instead of the right table’s column. #111993 (Groene AI). - Fixed wrong results and
NOT_FOUND_COLUMN_IN_BLOCKfor three-argumentmultiIfandif-chainGROUP BYkeys withROLLUP,CUBE, orGROUPING SETSandgroup_by_use_nulls = 1. Also fixed constant-condition keys reused through aliases withenable_identifier_resolve_cache, lost grouping sets when a key collapses to another key, and aBad castexception for a correlated subquery reading that column. Closes #122404. Part of #103419. #123065 (Groene AI). #122512 (Groene AI). - Fixed wrong results of
ORDER BY,LIMIT BY, andGROUP BYwithoptimize_aggregation_in_orderover a function of the sorting key with aNULLconstant argument, such astoString(dt, NULL)ortoString(dt, {tz:Nullable(String)})with aNULLparameter. Such a function returnsNULLfor every row, but reading in order treated it as strictly monotonic and kept the next sorting key column in table order. #125042 (Groene AI). - Fixed a server crash, wrong results, or a rejected query in
ORDER BY ... WITH FILL ... INTERPOLATEwhen oneINTERPOLATEexpression has to be converted to its target type and another item reads the same column or literal, for exampleINTERPOLATE (a AS b, b AS a)with targets of different types. #125129 (Groene AI). - A
WITHlist whose elements refer to the preceding ones, or a chain of common table expressions that read the previous one more than once, now fails withTOO_BIG_ASTpastmax_expanded_ast_elementsinstead of exhausting the server’s memory inEXPLAIN AST optimize = 1,CREATE VIEW, a fullATTACH VIEW ... AS SELECTandALTER TABLE ... MODIFY QUERY. #122362 (Alexey Milovidov). - Fix excessive memory usage for queries with
ARRAY JOINand filters on both rows and array elements: the row filter is now applied before expanding the array. #125577 (Konstantin Vedernikov). - Fixed
ORDER BY ... LIMITover a column of anIntervaltype (orNullable,LowCardinality,TupleorArrayof one) failing withTYPE_MISMATCHwhenuse_top_k_dynamic_filteringis enabled, which is the default. Closes #125197. #125221 (Groene AI). - Fixed a heap-use-after-free when a correlated subquery reading a
Mergetable was planned insideEXPLAIN, a subquery inFROM, a view, or anINsubquery. #122475 (Groene AI). - Fix a correlated scalar subquery used as the whole
WHERE,HAVING, orQUALIFYcondition, e.g.WHERE (SELECT count() > 0 FROM t AS i WHERE i.k = o.k), being rejected withILLEGAL_AGGREGATIONorNOT_AN_AGGREGATE, or failing withNOT_IMPLEMENTED(NOT_FOUND_COLUMN_IN_BLOCKon older versions) when the outer column it uses is not read elsewhere in the query. Closes #124499. #124594 (Groene AI). - Fixed
NOT_IMPLEMENTED(None of the algorithms enabled by the 'join_algorithm' setting ... can execute this SEMI/ANTI JOIN) for a correlatedEXISTS/NOT EXISTSsubquery, for anIN (subquery)underrewrite_in_to_join, or for anANY LEFT JOINof anENGINE = Jointable under an always-falseWHERE, whenjoin_algorithmis set tofull_sorting_mergeorpartial_merge. #118315 (Alexey Milovidov). - Comparing two deeply nested
Array,Tuple,Map, orObjectvalues doubled the work for every nesting level, because the ordering asked each equal element both whether it was less and whether it was greater. A single-value aggregate such asmin,max,argMin,groupArraySorted, or an-ArgMincombinator over a 30-level nested argument therefore ran for minutes on a few hundred rows, and could not be interrupted bymax_execution_time. Such a comparison now visits each element once. #116455 (Groene AI). - Fixed a server double free when finalizing an aggregate function with the
-Statecombinator nested under a combinator that transfers several substates in one call, such as-Resample,-ForEach,-Map, or-Tuple, if an exception is thrown part-way through the transfer. #111287 (Groene AI). - Fixed wrong results from
quantileExactWeightedInterpolated,quantileInterpolatedWeighted, and theirquantiles*forms over integer-backed types. #114571 (Groene AI). - Fixed
topK,topKWeighted,approx_top_k,approx_top_count,approx_top_sum,uniqUpTo,uniqCombined,uniqCombined64,exponentialMovingAverage,stochasticLinearRegression,stochasticLogisticRegression, andgroupNumericIndexedVectorstate columns with aDecimalor wide-integer parameter. The parameter was persisted as a quoted string that reparsed asString, so after a restart the table was unreadable, uninsertable, and undroppable. #121491 (Groene AI). - Fixed a server abort when the
flameGraphaggregate function was constructed on a thread without a query context, for example while attaching a stored table whose column type namesAggregateFunction(flameGraph, ...). #121894 (Groene AI). - Fixed
runningAccumulatereturning an accumulation computed over only part of the rows when it reads a state column underif,multiIf,and, ororat the defaultshort_circuit_function_evaluation = 'enable'. Inside a boolean predicate this also changed which rows passed the filter. An argument computed inline by another lazily evaluated function, whether it is the state or the grouping key, is still filtered. Closes #117121. #117126 (Groene AI). - Fixed
arrayIntersectreturning aNULLthat is present only in its first argument, which made the result depend on the order of the arguments.NULLis now in the result only when every argument array contains one. #118433 (Alexey Milovidov). arrayUniq,arrayEnumerateUniq,arrayEnumerateDense, andarrayJaccardIndexnow distinguishNULLfrom the nested type’s default value for nullable arrays that use generic hashing. #120676 (xiaohuanlin).- Fixed an out-of-bounds heap write in
stem. The output buffer now grows when the stemmed word is longer than the estimate from the input. #121402 (Jimmy Aguilar Mena). - Fix array and map search functions returning a match for a
NULLStringneedle when an empty string is present. #118741 (Minh Vu). - Fixed
leastandgreatestreturning wrapped-around values for aLowCardinalitynumeric argument of mixed signedness,intDiv/%/positiveModulothrowingDivision by zeroon NULL rows of aLowCardinality(Nullable(...))denominator, andfromModifiedJulianDay,runningConcurrency,hasPhrase,formatRow,now, andCASTrejecting validLowCardinalityarguments. #117450 (Alexey Milovidov). #122418 (Groene AI). - Fix
has,notHas,indexOf,countEqual, andmapContainssilently finding nothing in a constant array or map withEnumkeys searched for the name of an enum value, e.g.mapContains(map('a', 1)::Map(Enum8('a' = 1), UInt8), 'a')returned0. They now compare by the name of the enum value, consistently withequalsand with the same functions over a non-constant argument. Also fix indexing aMapwithEnumkeys by a numeric value that is not in theEnumthrowingUNKNOWN_ELEMENT_OF_ENUMduring query analysis instead of returning the default value, and an exception in the analysis of abloom_filterindex overmapKeysof aMapwithEnumkeys. Also fix abloom_filterindex over anArray(String)orArray(FixedString)column wrongly pruning the granules that matchhasAnyorhasAllwith a constantArray(Enum)argument. #116093 (Alexey Milovidov). - Fixed comparison of tuples with an untyped
NULLelement, such as(1, 2) != (3, NULL)or(1, 2) != toNullable((3, NULL)): the result wasNULL(or0for aNullabletuple) even when another element decides it. It is now the same as with a typedNULL:0or1when another element decides the comparison,NULLotherwise. A filter and its negation no longer both drop a row, e.g. withWHERE NOT (_partition_value > toNullable((..., NULL))). #123896 (Groene AI). - Fixed
pointInPolygonwith a constant polygon returning wrong results for some points of ordinary polygons, for example0for the point(0.76, 0.01)inside the polygon[(1, 0), (0, 1), (-1, 0), (0, -1)], or1for a point inside a small hole. The results now match those for a non-constant polygon. #123767 (Groene AI). - Arithmetic between a
Decimaland an integer that does not fit the native width of the decimal result now raisesDECIMAL_OVERFLOWinstead of silently wrapping the integer operand. #118721 (Alexey Milovidov). - Fixed wrong results of
pointInPolygonfor polygons with huge coordinates. With a constant array polygon, a filter on a table whose primary key covers the point columns could also return fewer rows than a full scan.pointInPolygonnow throwsBAD_ARGUMENTSwhere it would compute with a polygon coordinate larger than1e150in absolute value. #123740 (Groene AI). - Fixed
date_time_overflow_behaviorbeing ignored while parsingDateandDateTime. Closes #113151. #116099 (Yarik Briukhovetskyi). toStartOfIntervalno longer widensDateandDateTimeinputs toDate32andDateTime64whenenable_extended_results_for_datetime_functions = 1; onlyDate32andDateTime64inputs keep the extended result types, matching thetoStartOfXfunctions. This also removes the saturated result (2106-02-07 06:28:15) thattoStartOfInterval(<Date>, INTERVAL ... DAY)returned under that setting for dates after2106-02-07. #119806 (Groene AI). #121809 (Kirill Kopnev).- Fixed
age('week', ...)sometimes being off by one week when the dates fall on different weekdays. #122633 (Samuel Krempaský). - Fixed wrong results when an
Enum8orEnum16value is converted toDateTimeorDate. A negative member wrapped instead of saturating like theInt8orInt16it is stored as, sotoDateTimeof an enum returned a far-future timestamp and primary-key analysis discarded granules that did contain matching rows. #118039 (Groene AI). - Fixed
toDateTime64,toDateTimewith a scale andtoTime64throwingCANNOT_PARSE_DATETIMEfor aNullable(String)orNullable(FixedString)argument that containsNULL; such rows now returnNULL. FortoDateTime64this was a regression in 26.5, wherecast_string_to_date_time_modebecamebest_effortby default. #123311 (Groene AI). - Fixed
dateDiffandagewith unitdayreturning a result off by 65536 (for example-65535instead of1) when an argument is aDateTimeon the local day 1969-12-31 in a time zone west of UTC, such astoDateTime(0)inAmerica/New_York. If a table stores such a value in a sorting key, partition key, skip index, projection orMATERIALIZED/DEFAULTcolumn, rebuild it. #124555 (Groene AI). - Setting
date_time_overflow_behavioris now honored byCASTand the conversion functions for numeric conversions toDate,Date32,DateTime,Time,DateTime64, andTime64. ForDateTime64andTime64, the same now applies to theINSERT ... VALUESexpression fallback and thevaluestable function, and forDateTime64sort keys to numericWITH FILLbounds. Previously an out-of-range value was silently clamped even in thethrowmode.accurateCast,accurateCastOrNull, andaccurateCastOrDefaultno longer clamp an unrepresentable value intoDateTime64orTime64, and saturation now reaches the extreme representable tick of the target rather than the last whole second. #117667 (Alexey Milovidov). - Fixed a constant of
Varianttype reached through anArray,Tuple, orMapbeing mis-serialized to a secondary server, so a query that returned a result on a single node failed withCANNOT_CONVERT_TYPEthrough parallel replicas,remote, orDistributed. AStringmember of a multi-memberVariantconstant, scalar or nested, arrived there as whichever member its text parsed as, and an emptyMapwhose key or value is aVariantwas rejected outright. #117831 (Groene AI). - Fixed
LOGICAL_ERRORwhen reading asizeNsubcolumn of a shared-dataJSONpath, for example asize1subcolumn over data of typeArray(Array(Nullable(Int64))). It affected parts written with theadvancedshared data serialization version, which is the default for merged parts. #120039 (Pavel Kruglov). - Fixed wrong results when reading the
nullsubcolumn of aNullablefield of aVariant,Dynamic, orJSONelement, for examplevalue.`Tuple(a Nullable(UInt32), b String)`.a.null. On rows holding a different alternative the subcolumn returned0although the field itself wasNULL, sooptimize_functions_to_subcolumns(enabled by default) rewritingIS NULLto that subcolumn silently dropped matching rows. Closes #119935. #120099 (Groene AI). - Fix
JSONHasandJSONExtractRawreturning an absent result for a typedJSONpath whose literal value isNULLbut which contains a non-empty sub-object whentype_json_skip_null_typed_pathsis enabled. #120321 (JasonLi-cn). - Fixed
max_memory_usageandmax_server_memory_usagenot being respected when reading aJSONcolumn with theFLATTENEDserialization version from theNativeformat. #117730 (Pavel Kruglov). - Fixed reading flattened
Nestedmembers next to aJSONmember inWideparts. #122519 (Mohammed Sohail). - Allow the
JSONtype and theJSON*functions to parse documents whoseStringvalues hold bytes that are not valid UTF-8, which previously failed withINCORRECT_DATA. As a side effect,isValidJSONand theJSONExtract*family now accept such documents instead of reporting them invalid. #119122 (Groene AI). - Fix stack exhaustion when reading a deeply nested
DynamicorJSONvalue as aFieldor printing it in a text format. Both paths now raiseTOO_DEEP_RECURSIONinstead of terminating the server. #121441 (Groene AI). - Fix reading bucketed runtime
Mapvalues fromJSONcolumns usingadvancedshared-data serialization. #118577 (Rory Shanks). - Fixed a
Dynamicconstant losing the type of its value when a query is sent to other servers (Distributed,remote, parallel replicas): a constant holdingEnum8('7' = 3)arrived as the number3, soINandNOT INmatched the wrong rows and=failed withNO_COMMON_TYPE, and aUInt64,IPv4, orMapvalue arrived as a different type. Closes #119745. #118988 (Groene AI). - Fixed a crash on a query with a deeply nested
DynamicorJSONconstant. #120885 (Pavel Kruglov). - Fix inconsistent results and missing type errors when
optimize_functions_to_subcolumnsrewrites aJSONpath accessed withtupleElementorarrayElementusing an unsupported key type. Such expressions now behave the same with and without the optimization. #125471 (Groene AI). - Fixed
TYPE_MISMATCHwhen aLowCardinalityjoin key is also selected from the NULL-extended side of aLEFT,FULL, orASOF LEFTjoin withjoin_use_nulls = 1andjoin_algorithm = 'full_sorting_merge'or'parallel_full_sorting_merge'. Closes #120424. #120469 (Groene AI). - Fixed
ILLEGAL_PREWHEREon shardedGLOBAL RIGHT JOINqueries that usedPREWHEREon the left table. The filter is applied to the broadcast side before the join instead of being sent to aMemorytemporary table that does not supportPREWHERE.PREWHEREon a remote table in a join is also preserved when that table is read through a subquery wrap. #119780 (Anton Ivashkin). - Fixed a
Pipeline stuckexception when a query combined a merge join usingjoin_algorithm = 'parallel_full_sorting_merge'with a step that glues independent streams together, such as reading from aMergetable, or aUNION ALLnarrowed bymax_streams_for_union_step. Such a query now runs instead of failing. #121227 (Groene AI). - Fixed a query failing with an error such as
CANNOT_READ_ARRAY_FROM_TEXTwhen a subquery’sSELECTlist computes an expression that the same subquery’sWHEREguards against, and that subquery is the probe side of aJOINfor which a runtime join filter is built (enable_join_runtime_filters = 1, enabled by default). The guarded expression was evaluated on rows that theWHEREhad already removed. #122143 (Groene AI). - Fixed lost matches on a
Dynamicjoin key when outer joins are reordered with a join order conflict detector enabled (query_plan_optimize_join_order_conflict_detector) andjoin_use_nulls = 1. #123113 (Fisnik Kastrati). - Fix
NOT_IMPLEMENTEDerror for aLEFT JOINover a dictionary or other key-value storage underjoin_algorithm = 'direct'. #123491 (Hechem Selmi). - Fix exponential planning time in the transitive outer-to-inner JOIN conversion when the expression DAG has shared nodes, such as a column used twice (x + x) across nested subqueries. The analysis now visits each node once instead of every path. #123509 (Hechem Selmi).
- Fix a performance regression where the join runtime filter was skipped for joins that combine an
=key with a null-safe<=>(IS NOT DISTINCT FROM) key once hash table statistics were collected. #122618 (Manuel). - Fixed
indexHintover the non-preserved side of an OUTER join silently returning extra rows, andjoin_algorithm = 'direct'failing withNOT_IMPLEMENTEDwhen a column-free conjunct such asmaterialize(1)is added to theWHEREclause. #117569 (Alexey Milovidov). - Fix
NOT_IMPLEMENTEDfor an outerJOINwithjoin_algorithm = 'full_sorting_merge'whenoptimize_and_compare_chainderived a condition on the preserved side of the join from theONclause. #124233 (Yarik Briukhovetskyi). - Fix
UNKNOWN_IDENTIFIERerrors inINSERT ... SELECTfrom a parameterized view whenparallel_distributed_insert_selectis enabled. The view is now analyzed with the analyzer instead of the legacy interpreter. #119495 (Yarik Briukhovetskyi). - Fixed a query over a
Distributedtable (orcluster/remote/clusterAllReplicaswith an innerview) spanning more than one shard that references no column of the table anywhere in the query, such asSELECT count(*) OVER () FROM distributed_table. Such a query silently returned no rows, and returnedLOGICAL_ERRORInvalid number of columns in chunk pushed to OutputPortwhen the table produced a constant. The fix covers the analyzer;enable_analyzer = 0is fixed separately by #113955. #113469 (Groene AI). - Fixed a server crash when a scalar or
INsubquery inside a standalone expression, such as aCHECKconstraint, aTTLexpression, or a row policy, reads aDistributedtable or theremotetable function. #121418 (Groene AI). #121639 (Alexey Milovidov). - Fix
NOT_FOUND_COLUMN_IN_BLOCKforgroupingover aDistributedtable withoptimize_skip_unused_shards = 1: a constant that a query tree pass builds is now named on a shard exactly as the initiator names it. #119273 (Alexey Milovidov). - Refuse a query with
ORDER BYover aDistributedtable whose declared column type differs from the shard table’s type in a way that does not preserve the order, for exampleInt8declared over aStringcolumn. The shards sorted by their own type and the initiator merged the streams as if they were sorted by the declared type, which returned rows in the wrong order, cut the wrong rows withLIMIT, and duplicated values underDISTINCT. The check runs when a shard is the local server, where the shard table’s types are known, and only for the columns the query sorts by. Exact widenings (Float32toFloat64,DatetoDate32,DateTimetoDateTime64, aDecimalwith no smaller scale and no fewer integer digits,FixedStringtoString) are now recognized as order-preserving by both this check and the one of theMergeengine. #118445 (Alexey Milovidov). - Fixed queries over a
Distributedtable whenoptimize_skip_unused_shardsskips every shard and the query usesdistributed_group_by_no_mergeor reads the table through anotherDistributedtable. Such queries failed withNUMBER_OF_COLUMNS_DOESNT_MATCH,CANNOT_CONVERT_TYPE, orstd::out_of_range(withALIAScolumns) instead of returning an empty result or the aggregate of an empty set. #122982 (Groene AI). - Fixed queries that go through another server (
remote,Distributed, parallel replicas,GLOBAL IN, andQueryRunnerjobs sent to a cluster) failing withSYNTAX_ERROR,UNKNOWN_CODEC, orCORRUPTED_DATAwhenoutput_format_native_encode_types_in_binary_formatorinput_format_native_decode_types_in_binary_formatis enabled. The blocks of these queries now carry type names on the wire, and a shard with this change also works with an initiator without it.clickhouse-client --query_kind secondary_queryfollows the same rule. #123649 (Groene AI). #124716 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCK(orTHERE_IS_NO_COLUMN) when a query sent to other servers (aDistributedtable,remote, parallel replicas) has anINover a parameterized view called without its database name inside an expression the servers return, for examplecountIf(x IN (SELECT y FROM pv(p = 1))), aGROUP BYkey, or aSELECTitem. Also fixedNOT_AN_AGGREGATEwhen one query spells the same parameterized view call both with and without its database name. #123662 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen reading a subcolumn (Array.size0, aTupleelement,Map.keys/.values,Nullable.null, aJSONpath, or aDynamictyped subcolumn) through aVIEWover aDistributedtable. #119293 (Alexey Milovidov). - Fixed wrong results of aggregations,
LIMIT,DISTINCT,LIMIT BYand window functions over aBuffertable whose destination is aDistributedtable that a single shard finishes (one shard,distributed_group_by_no_merge, or aGROUP BYby the sharding key): the rows still in the buffer and the rows of the destination were processed separately and both results were returned. #124981 (Groene AI). - Fix wrong results when a condition outside a distributed subquery with
QUALIFYwas pushed into it and evaluated before the window functionsQUALIFYfilters by. #125491 (Nikita Taranov). - Fixed
THERE_IS_NO_COLUMNandNOT_FOUND_COLUMN_IN_BLOCKerrors in queries overremoteor with parallel replicas that compare tuples where one pair of elements is constant and false, such as(n, 1) = (n, 2), or whereNULLis compared with a column, such as(n, s) = (NULL, s). #125195 (Groene AI). - Fixed wrong results with
parallel_replicas_plan_based = 1when the plan fragment sent to the replicas has no output columns, for exampleSELECT count() FROM (SELECT 1 FROM t LIMIT 500). Such a query returned0, or an empty result set, instead of the correct value. #115871 (Groene AI). - Fixed wrong results and a
LOGICAL_ERRORwhen a query reads with parallel replicas inside a distributed sub-query whosecluster_for_parallel_replicasnumbers its shards differently from the cluster the query is distributed over: aVIEWcarrying its ownSETTINGS cluster_for_parallel_replicas, a read throughclusterAllReplicasof that same cluster, a cluster built by cluster discovery or by aReplicateddatabase when the two servers see a different set of shards under one name, or a plainremote_serverscluster whose per-server copies number the shards differently while a configuration change rolls out. The shard number shipped by the initiator was applied to the other numbering and selected the wrong shard. Parallel replicas are now declined for such a read. #113589 (Groene AI). #124724 (Igor Nikonov). - Fixed
SELECT count()returning a value multiplied by the number of replicas when executed inside a transaction with parallel replicas enabled. Trivial count optimization now is not rejected inside a transaction, so it is executed solely on the initiator. Followers no longer apply the trivial count optimization during query planning, which previously caused each of them to independently answer with the total row count read from the table’s metadata whenever the query reached them. #116365 (Kirill Shokhin). - Fixed
max_bytes_to_read,max_bytes_to_read_leaf, and read-speed and timeout limits being ignored for reads executed from a query plan shipped to another node, which happens withparallel_replicas_plan_basedandmake_distributed_plan. #119958 (Igor Nikonov). - Fixed
LOGICAL_ERRORCannot find a matching set in the map of sets from single-replica plan, and silently lost parallel replicas, when automatic parallel replicas were enabled and anINsubquery carried its ownSETTINGSclause namingforce_primary_keyorautomatic_parallel_replicas_mode. #120799 (Groene AI). - Fix
UNKNOWN_FUNCTIONon a shard or a replica for a higher-order function whose lambda body is anANDof comparisons whenserialize_query_plan = 1orparallel_replicas_plan_based = 1: a JIT-compiled lambda body was serialized into the plan. #119332 (Alexey Milovidov). - Fix missing total rows in progress (and therefore a non-working progress bar) for queries with parallel replicas when
parallel_replicas_local_planis enabled (the default). #123928 (Alexey Milovidov). - Fixed duplicate filter push-down in plan-based parallel replicas. #117731 (Nikita Taranov).
- Fixed wrong results and
UNKNOWN_IDENTIFIERerrors when a query reads aMergeTreetable after reading one of its projections with themergeTreeProjectiontable function, for example in aJOINorUNION ALLof the two. With parallel replicas such a query could also fail withGot read request from replica N for unknown stream. Closes #102182. #123915 (Groene AI). FINALon table functions now disables parallel replicas the same way asFINALon tables, so aTimeSeriestable function such astimeSeriesTagsno longer returns duplicate rows under parallel replicas. #122492 (Groene AI).- Fixed parallel replicas not being used when reading a
Distributedtable whose underlying table is anotherDistributedtable and every shard of the outer cluster has a single replica. #123566 (Igor Nikonov). - Fixed
TOO_MANY_ROWSbeing raised for a query that stays within itsmax_rows_to_readbudget whenparallel_replicas_min_number_of_rows_per_replicais set. The estimate sizing the replica set enforced the limit against whole granules at planning time. #121269 (Groene AI). - Fix a
NOT_IMPLEMENTEDexception forJOINqueries withINsubqueries when using plan-based parallel replicas. #121508 (Manuel). - Parallel replicas now honor a
SETTINGSclause that changes table eligibility when it is written inside a subquery or a view body. Such a clause was ignored, so a query over a view whose body setsparallel_replicas_for_non_replicated_merge_tree = 0, or setsparallel_replicas_allow_view_over_mergetree = 0and reads a further view, returnedmax_parallel_replicastimes too many rows, and aUNIONover a view overridingparallel_replicas_allow_view_over_mergetreeper subquery could throwCan't determine table for parallel replicas. #110020 (Groene AI). - A query that reads a
MATERIALIZEDCTE more than once, for example inside anINsubquery, now works with parallel replicas when the initiator also reads locally (parallel_replicas_local_plan = 1). The other replicas no longer fail withUNKNOWN_TABLEon the CTE’s temporary table. Closes #112642. #123121 (Groene AI). - Fixed a
LOGICAL_ERROR“Block structure mismatch in QueryPipeline stream” when selecting a computed column through themergetable function or theMergeengine. If constant folding folded that column for one matched table and not another, the query failed. #115971 (Groene AI). - Fix the exception
No set is registered for keyfor aSELECTthat reads aDistributedtable through aMergetable or themergetable function and whoseGROUP BY,DISTINCT, orLIMIT BYkey contains anIN-family function. #117817 (Groene AI). - Fix wrong results when reading a subcolumn of a
Mergetable column whose type differs between the source tables. Such a subcolumn exists only in the common typeMergederives, so it was filled with the default value for every row instead of being read. Most visibly,variantElementover aMergetable returnedNULLfor every row unless the call sat in the top-level projection next to another use of the whole column. #121462 (Alexey Milovidov). - Fixed a server crash when a
SELECTwithserialize_query_plan = 1read aMergetable through a table that forwards its reads, such asAlias,Bufferwith a destination, or aMATERIALIZED VIEWwith aTOtarget. Closes #119899. #119387 (Groene AI). - Fixed wrong results when a
Mergetable (or themergetable function) reads a subcolumn of a column that one of its child tables does not have: for that child,x.nullof a missingNullablecolumnxwas read as 0, sox IS NULLreturned no rows from it. Element subcolumns ofTuple,VariantandJSONcolumns and the sizes of a missing flattenedNestedmember were affected the same way. Closes #122523. #123633 (Groene AI). - Fixed a
Mergetable returning the value of another column, or failing with aCASTerror, for a column that one of its child tables does not have, when that child has a row policy or anALIAScolumn. Such a column is now filled with its default value. #124674 (Groene AI). - Fixed
mergeandMergetables with aDistributedtable among them returning the sameGROUP BYgroup several times, each copy with a part of its aggregates, when the aggregation is two-level and a table lacks a grouping column or has it under another type than the common one. #124720 (Groene AI). - Fixed a use-after-free when a query reads through an
Aliastable whose target is dropped concurrently. #120098 (Groene AI). - Fix
CREATE MATERIALIZED VIEW ... POPULATE AS SELECT count() FROM <MergeTree table>counting rows inserted during the population twice whenmaterialized_views_populate_atomicallyis enabled. #123182 (Murphy). - Fixed a materialized view over a system log table such as
system.query_logsilently stopping to receive rows after the server renamed the table to<name>_Nbecause its definition changed (a server upgrade, or a change of<engine>or<ttl>in the config). Closes #124177. #124217 (Groene AI). - Fixes wrong results when a materialized view reads an ordinary view over a table with a row policy that contains a subquery (
x IN (SELECT ...)or a scalar subquery). The policy’s subquery now reads the real source table instead of the block being inserted into the materialized view. #124875 (Aditya Kumar). SYSTEM WAIT VIEWon a refreshable materialized view in aReplicatedorShareddatabase no longer returnsOk.while a refresh requested on another replica has not run yet. Requested refreshes are now published inKeeper. #120623 (Samuel Krempaský).- Fixed a segmentation fault when a refreshable materialized view is started up and shut down at the same time, for example when a failed
ATTACH DATABASErolls the database back, or when the server shuts down while tables are still loading asynchronously. #121037 (Groene AI). - Fixed a refreshable materialized view with
REFRESH DEPENDS ON(orREFRESH AFTER ... DEPENDS ON) and noREFRESH EVERYre-running its refresh without limit after a failure used uprefresh_retries. It now waits for its dependencies’ next refresh. #123369 (Ashish Kumar Choubey). - Fixed
plain_rewritabledisks leaving object storage and the in-memory filesystem in disagreement when a failed metadata transaction could not be reversed completely. Transient failures during reversal are now retried until object storage accepts the operation, and rollback runs for all exception types. Missing blobs are reported asCORRUPTED_DATA, and replacing a file with a missing source no longer deletes the existing target. The disagreement previously surfaced only after a restart, when a directory could appear under a name the server never committed. #119235 (Sema Checherinda). #122696 (Sema Checherinda). - Fixed a query reading from
file,s3,url,azure, orhdfswithsession_timezoneset getting theDateTimeschema inferred by an earlier session with a differentsession_timezone, which formatted and computed the values in that other session’s time zone. #117811 (Alexey Milovidov). - Fixed unnecessary object-storage reads, and
<Error>-level exception messages such asCode: 499 ... The specified key does not exist ... (S3_ERROR), while destroying a data part on an object-storage disk when its skip indices are packed intoskp_idx.packed. Evicting the part’s index marks from the mark cache no longer inspects the part’s on-disk layout, so it performs no I/O. #113454 (Groene AI). - Fixed hive partition columns of glob-path object storage tables being permanently disabled when the first query over the table ran while the path matched no files. #120308 (Zach Rippas).
- Fixed unbounded memory and CPU usage when a path passed to
file,s3,azureBlobStorage, orhdfscontains many{a,b,c}glob groups or long{N..M}ranges. Such a path is now rejected with an error. #118467 (Alexey Milovidov). - Fix
copyObjectToAnotherObjectStoragecopying an object twice when the source and destination are the same object storage, which doubled the data transferred by a copy between two disks backed by that storage. #120953 (Alexey Milovidov). - Fixed
UNKNOWN_IDENTIFIERfor aDEFAULTcolumn that depends on a column used by a row policy, in tables with theFile,URL,S3, and other object-storage engines. #122714 (Nikolai Kochetov). - Fix object storage tables with
partition_strategy = 'hive'being silently empty for formats whose name is not the file extension real files carry. The read glob was built from the lowercased format name (**.jsoneachrow,**.csvwithnames), so pointing aJSONEachRowtable at a lake of.json/.jsonlfiles — or aCSVWithNamestable at.csvfiles — read zero rows with no error or warning. The glob is now built from every file extension registered for the format (and for itsWithNames/WithNamesAndTypesbase format), plus additionally registered read extensions:JSONEachRowmatches.json/.jsonl/.ndjsonfiles andTabSeparatedmatches.tsv. Files written by ClickHouse itself keep matching. #120319 (Zach Rippas). - Fixed reads of Hive-partitioned files (
.../key=9/...) that need no column of the data file, such ascount()withoptimize_count_from_files = 0orSELECT key, _row_number, returning no rows (Nativethrew an exception) when a partition column was smaller than the data columns. The wrong0was also cached and returned by latercount()queries. The same reads of a structure that lists only partition columns returned no rows or threw an exception for most formats. Affectsfile,url,s3and other object storages. #123381 (Groene AI). - A query over an object storage table (e.g.
S3) no longer waits for another query that is resolving the table’s hive partitioning on its first use, soKILL QUERYandmax_execution_timeapply to it while the endpoint is slow or unreachable. #123532 (Groene AI). - Fixed
BAD_ARGUMENTS(Expected positional arguments to go before key-value arguments) for a validS3argument list that combinesheaders(...)with a key-value argument, in either order, and for the engines and table functions sharing that parser (Iceberg,DeltaLake,Hudi,Paimon,GCS,S3Queue). Withfile_like_engine_default_partition_strategy = 'wildcard'the server persisted such a list itself, so a created table could no longer be attached and the server refused to start; affected tables load again. #119070 (Groene AI). - Fix the logical error
Attempt to read beyond right offsetwhen the right bound of a read from Azure Blob Storage is lowered below bytes the reader has already buffered. #120957 (Alexey Milovidov). - Fixed a
WHEREcondition or a row policy on a Hive partition column (use_hive_partitioning = 1) returning too few rows when theParquetdata file also has a column with that name and other values:Parquetrow-group, page, and dictionary pruning used the file’s values instead of the path’s. The same applied to a virtual column such as_filewhen the data file has a physical column with that name. Affectsfile,url,s3, and other object storages. #124991 (Alexey Milovidov). - Fixed an exception when a
WHEREcondition on the_file,_path, or_partvirtual column guards a branch withif,and,or, ormultiIf, for exampleWHERE _file LIKE 'events_%' AND toDate(substring(_file, 8, 10)) >= '2024-01-01'. Pruning files and parts by virtual columns now respectsshort_circuit_function_evaluationinstead of evaluating the excluded branch for every file or part name. The same path now also rebuilds copiedindexHintexpressions and reducedandexpressions with the right arguments, avoiding argument-count exceptions during lazy evaluation. #125033 (Groene AI). #125150 (Groene AI). #125126 (Groene AI). - Fixed loading, short
ATTACH, andUNDROP TABLEfor existing SQL-definedS3disks whose endpoints are absent fromremote_url_allow_hosts; new full-definitionCREATEandATTACHstill reject disallowed endpoints. #124930 (Alexey Bakharew). - Fixed filesystem cache accounting when the directory for a new cache key cannot be created, for example because the cache disk is out of space or inodes. The failed reservation stayed counted in the cache until the query released the file segment. #122211 (Sema Checherinda).
- Fixed
Parquetwriting size statistics twice for a column chunk that falls back from dictionary encoding, which madeunencoded_byte_array_data_bytesand the level histograms too large. TheParquetMetadataformat now also reportssize_statisticsfor each column chunk. #120027 (Erez Rokah). - Fix two
JSONobject-size-limit bugs: bytes before the opening bracket are now counted toward the limit, and valid data is no longer rejected just because earlier rows in the same block already used the shared buffer. #115795 (Pavel Kruglov). - Schema inference for the
Freeformformat no longer exhausts memory on a wide row of strings: the search for the row structure is bounded by the settinginput_format_freeform_max_search_steps(default4096,0means unlimited) and now also stops atmax_memory_usage,max_execution_time, andKILL QUERY. #122447 (Mohammed Sohail). #123238 (Groene AI). - Fix a crash when reading an ORC file whose root type is not a struct (for example, a file written with a
bigintorarray<bigint>root type). Such files are now rejected with anINCORRECT_DATAerror. Closes #123305. #123337 (Groene AI). - Fixed a possible out of bounds access when reading an ORC file. #123464 (Pedro Ferreira).
- Fix reading Avro files with a union whose named branches (records, enums, fixed) have the same structure. Before the fix, such files failed with
The number of (non-null) union types in Avro record (N) does not match the number of types in destination Variant type (M), even with the inferred schema. #123236 (Dmitry Kovalev). - Avro schema parsing no longer overflows the stack on a deep chain of named types. #124053 (Groene AI).
- Fixed a crash (stack overflow) on an Avro schema with a long chain of named type references, in schema inference (
DESC, orSELECTwithout an explicit structure, forAvroandAvroConfluent), in reads into aVariantcolumn and in Iceberg manifest reading. Such a schema now fails with an error instead. #124644 (Groene AI). - Fixes a crash when reading an ORC file whose metadata has fewer stripe statistics than the file has stripes (for example, after a corrupt
metadata_length) withinput_format_orc_filter_push_downenabled. TheORCinput format now reads such files without stripe-level filtering. #124315 (Groene AI). - Fixed a crash (stack overflow) when reading an Avro file with an explicit structure that does not read a field nested through a long chain of named types, or a field of a recursive type holding deeply nested data such as a long linked list. Such a file now fails with
TOO_DEEP_RECURSIONinstead. Closes #124925. #124964 (Groene AI). - Fixed a stack overflow crash on a deeply nested
CapnProtoschema that the nesting depth check missed: a comment or a byte order mark betweenimportand its path, an escape sequence in the import path, or a backtick text line. A backtick text line with many brackets is no longer rejected as nested too deeply. #125487 (Groene AI). - Fixed a crash (stack overflow) on a
CapnProtoschema with a long chain of type expression suffixes (Int32.a.a...,Int32()()...) or of declarations that refer to each other (constants, aliases, struct fields, annotations, imports). Such a schema is now rejected withThe CapnProto schema is nested too deeply. Closes #125782. #125900 (Groene AI). - Fixed a data race on the file list of a
Fileengine table. Two concurrentINSERTs withengine_file_allow_create_multiple_files = 1could pick the same file name, which madeSELECT count()over-report, rejected a validINSERTwithCANNOT_APPEND_TO_FILE, and could corrupt the heap. Closes #121517. #121598 (Groene AI). - Fixed
count()overfile('*.csv', 'CSVWithNames')withoptimize_count_from_files = 1over-counting a CSV file by one row in rare cases. #120552 (Knut-Aage-Hofseth). - Fixed concurrent
INSERTs andSELECTs on a table with theFileengine stalling forlock_acquire_timeout(120 seconds by default) and then failing withTIMEOUT_EXCEEDED. A singleSELECTcan open several readers on oneFiletable, and anINSERTarriving between two of them made the query wait for itself. Closes #115931. #121779 (Groene AI). - Fixed
TinyLogreturning fewer rows than the table contains when one of the data files being read ends before the others. AnArray,Map, orNestedcolumn contributes an elements file that holds one entry per element rather than per row, so it runs out early whenever the trailing rows hold empty containers, and a column holding only empty arrays contributes an elements file of zero bytes. The read stopped at the first data file by name to reach its end, cutting the result at a block boundary. #120307 (Groene AI). - Fixed
BACKUPandRESTOREqueries withSETTINGS <name> = DEFAULT: such a query either failed to parse or was formatted into text that could not be parsed back, and the other settings of the same clause were discarded. Repeatedasyncitems now use the last value,async = '1'no longer fails after the operation has started, andcompressionis rejected in theSETTINGSclause as in other queries. #112978 (Groene AI). - Fixed
BACKUPwriting a.backupmanifest that is not well-formed XML when a value in it contained&,<, or>, for exampleBACKUP ... SETTINGS id = 'a&b', or an incremental backup whosebase_backuppath contained one of those characters. The backup reportedBACKUP_CREATED, but every laterRESTOREfrom it failed withSAXParseException: Invalid token, leaving the data unreachable. Such values are now escaped. Backups already written with an unescaped value remain unreadable and have to be taken again. #118898 (Julia Kartseva). - Fixed
RESTOREofsystem.functionsfailing, and aborting the whole restore, when the backup holds a SQL user-defined function whose definition the version that created it accepted butCREATE FUNCTIONnow rejects, for exampleCREATE FUNCTION f AS lambda(identity(x), x)created on 25.5 or earlier. #122912 (Groene AI). - Fixes
BACKUP ... ON CLUSTERcreating a backup that cannot be restored when a host names its data files differently from the initiator: withdata_file_name_generator = 'checksum'and adata_file_name_prefix_lengthother than the hosts’backups.data_file_name_prefix_length(3 by default), or when a host’s config setsbackups.data_file_name_generator = checksumand the initiator uses the default generator. Backups already created this way still cannot be restored. #122624 (Groene AI). - Fixed
RESTOREof a lightweight snapshot fromAzure Blob Storagewhen the source disk endpoint includes a key prefix below the container name. #122697 (Garrett Thomas). - Fixed column comments of a
ReplicatedMergeTreetable being lost in a backup when they were changed after the last metadataALTER. #121309 (Nikolay Degterinsky). - Fixed
BACKUP/RESTORE ... ON CLUSTERhanging forever, unaffected byKILL QUERYand blocking server shutdown, whencompatibilityis set to24.10or older and a host fails on aKeepererror before it starts. Such acompatibilityvalue no longer setsbackup_restore_finish_timeout_after_error_sec,backup_restore_failure_after_host_disconnected_for_seconds,backup_restore_keeper_max_retries_while_initializing, andbackup_restore_keeper_max_retries_while_handling_errorto0, a combination no release ever used. #123752 (Groene AI). - Fixed
BACKUPfailing withA concurrent backup writing to the same destination ... detectedwhen nothing else was writing there. The lock file is claimed with a conditional write, and a retry of a request that had already been applied made the backup mistake its own lock for someone else’s. #116376 (Alexey Milovidov). BACKUPandRESTOREtoS3now retry requests that fail withExpiredTokenafter refreshing credentials. The retry time limit is 120 seconds by default and can be changed withbackup_s3_expired_token_retry_timeout_ms. #123195 (Nikolai Ovchinnikov).BACKUP ... TO File(...)/Disk(...)now fsyncs the backup data files, the.backupmanifest and the containing directories before reportingBACKUP_CREATED, so an acknowledged backup to local storage survives power loss. The guarantee coversbackups.allowed_pathand everything the backup writes below it. On aDisk(...)over object storage that keeps its metadata in local files, those metadata files are fsynced instead, since the backup is reached only through them. Controlled by the new backup settingfsync_backup_files(defaulttrue).S3(...)/AzureBlobStorage(...)destinations are unaffected. #111394 (Groene AI).Icebergtables whose manifest file headers carry a schema that conflicts with the schema registered for the sameschema-idinmetadata.jsonare now readable: themetadata.jsonschema is preferred and the divergent manifest header copy is ignored with a warning, no matter which of the two copies is read first, matching the behavior of other query engines such as Spark, Trino, PyIceberg, and DuckDB. Controlled by the new settingiceberg_tolerate_conflicting_manifest_schemas(defaulttrue);compatibilitybelow26.9restores the previous strict behavior, which failed such queries withICEBERG_SPECIFICATION_VIOLATION. #119743 (Melvyn Peignon).- Fixed
Icebergmanifest statistics recording the wrong file count for added files. #120858 (Konstantin Vedernikov). - Fixed
IcebergINSERTwriting nolower_boundsorupper_boundsat all into the manifest entry when the table has a column whose type cannot be serialized into a statistics bound, or a column that is entirelyNULL. Such a field is now omitted individually and the bounds of every other column are still written, so min/max file pruning keeps working. Closes #112706. #112934 (Groene AI). - Fixed
Icebergdate partition transforms being computed in the server time zone instead of UTC. #118583 (Konstantin Vedernikov). - Fixed
SHOW TABLESandsystem.tablesfailing on a database with theDataLakeCatalogengine over anIcebergREST catalog when an unrelated namespace was dropped by another client while the listing was in flight. #113740 (Groene AI). - Fixed validation of
Icebergmanifest-list entries during writes. #122829 (Arsen Muk). - Fixed metadata of empty
Icebergtables created by ClickHouse, so that Spark and otherIcebergJava-based tools can open them before the first insert and evolve their partition spec. #122077 (Asya Shneerson). - Prevent loss of newer committed
Icebergdata by rejectingOPTIMIZEwheniceberg_metadata_file_path,iceberg_snapshot_id, oriceberg_timestamp_msis explicitly set. #122683 (Arsen Muk). - Fixed reading an Iceberg table partitioned by
DateTime64when a data file does not store the partition column: the query failed withDECIMAL_OVERFLOW. Decimal partition values stored in a manifest in their raw form are decoded as well, andsystem.iceberg_files.partitionnow shows partition values in a readable form instead of raw bytes. #117090 (Alexey Milovidov). - Fix
CREATE TABLEandDROP TABLEin Iceberg REST catalog databases: the catalog now writes the initial metadata file,ORDER BYand table properties are sent to the catalog, multi-level namespaces are created correctly, andDROP TABLEuses the correct endpoint. #123631 (Asya Shneerson). - Fix
SELECT count()overIcebergtables returning too few rows after compaction leaves dangling position-delete files. Closes #123494. #123851 (Konstantin Vedernikov). - Fixed reading
Icebergtables through theDataLakeCatalogdatabase engine when the catalog reports a column type in a spelling the Iceberg type parser did not know:varbyte(Glue’s name for the Icebergbinarytype),list<...>(the Iceberg spelling ofarray<...>, also written by Glue), andtimestamp with local time zone(Hive 3’s name for the Icebergtimestamptztype). Such tables were rejected withUnknown Iceberg type. Closes #121850. Closes #87716. #121974 (Groene AI). - The
iceberg_metadata_staleness_mssetting is now respected when parsingIcebergmetadata, soIcebergtable functions andON CLUSTERworkers no longer list the wholemetadata/directory on every query. #124113 (Konstantin Vedernikov). - Fix a server abort when reading an
Icebergtable whose sort order names a transform ClickHouse cannot parse, e.g.bucket[xyz]; ClickHouse now ignores that sort-order hint and keeps the table readable. #121687 (Ilias). - Fixed
OPTIMIZE TABLEfor OSS Iceberg tables so compaction no longer removesversion-hint.textand breaks hint-based reads. #122833 (Arsen Muk). - Fixed a crash (SIGSEGV) when reading a malformed deletion vector with the
Puffininput format, for example one whose roaring run container has zero runs. Structurally invalid roaring bitmaps are now rejected with an error instead of crashing or returning wrong deleted-row positions. Closes #124688. #124735 (Groene AI). - Fixed an
INSERTinto aParquetIcebergtable failing withLogical error: 'Iceberg data file has 1 columns while its schema has 2 fields'whenALTER TABLE ... ADD COLUMNcommitted while theINSERTwas running. #121821 (Groene AI). - Fixed
Icebergv3 virtual columns_row_idand_last_updated_sequence_number: filters on them no longer return no rows for a data file rewritten by copy-on-write when the manifest has statistics for the table columns but not for the row-lineage columns, and rows of files written before the table was upgraded to format version 3 no longer returnNULLfor these columns. Closes #124271. #124591 (Groene AI). #124598 (Groene AI). - Fixed
OPTIMIZE TABLE ... MANIFESTfailing withBAD_ARGUMENTSon anIcebergtable whose current snapshot summary omits an optionaltotal-records,total-files-size, ortotal-data-filesmetric, which made manifest compaction permanently unavailable on tables written by engines that omit those metrics. Closes #117000. #117012 (Groene AI). - Fixed
Icebergmin/max pruning skipping a data file that holds matching rows when the file’suuidbound was written by an external engine such as Spark, Trino, or PyIceberg. Such a bound now prunes only when its lower and upper bounds are equal. This fixes theIcebergmanifest bounds only: theuuidstatistics of theParquetdata file itself are a separate defect, so a query at default settings can still miss rows. Closes #118366. #118380 (Groene AI). - Fixed
Icebergwrites storing ClickHouse unsigned integers in a narrowerIceberginteger type than the source. #118596 (Konstantin Vedernikov). ALTER TABLE ... EXECUTE remove_orphan_filesonIcebergtables now rejects anolder_thanthat is less thaniceberg_orphan_files_min_retention_seconds(default 1 day) before now, so it no longer deletes the files of a write that started within that window and has not committed yet. Settingiceberg_orphan_files_min_retention_secondsto0restores the previous behavior. Closes #125331. #125376 (Groene AI).- Fixed
DROP TABLEin aDataLakeCatalogdatabase with anIcebergREST catalog ignoringiceberg_delete_data_on_dropfrom the server’s default profile: ClickHouse always sentpurgeRequested=False, so the catalog never deleted the table’s data, and Microsoft OneLake rejected the drop with HTTP 405. ClickHouse now sendspurgeRequested=trueorpurgeRequested=false(lowercase, as theIcebergREST spec defines), chosen by that setting; a session-levelSETdoes not reach this drop. Closes #125410. #125469 (Groene AI). - Fixed
add.modificationTimein Delta Lake commit logs being written in seconds instead of the milliseconds the Delta protocol requires, so a data file written by ClickHouse appeared to Spark,delta-rs, anddelta-kernel-rsas last modified in 1970. Closes #120523. #120564 (Groene AI). - Fixed wrong values and a
LOGICAL_ERRORwhen reading a partitionedDeltaLaketable withallow_delta_kernel_rs = 0and column types that differ from the ones in_delta_log. #121544 (Raúl Marín). - Fix reading Delta Lake tables with column mapping where a field name with a dot, like
a.b, equals the path of a nested field (the fieldbof a structa). Such a field returned the other field’s values orNULL,SELECT *failed withCOLUMN_QUERIED_MORE_THAN_ONCE, and a partitioned table failed with aLOGICAL_ERROR. #123102 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen a query reads a struct column of aDeltaLaketable with column mapping together with one of its fields, such asSELECT s, s.x,SELECT *, s.x, orSELECT s ... WHERE s.x = 1. Closes #123811. #123852 (Groene AI). - Fixed
INSERTintoDeltaLaketables through a UnityDataLakeCatalog: the catalog now requests write credentials instead of reusing read-only ones. #123543 (Konstantin Vedernikov). - Fix DeltaLake statistics pruning for filters that compare a
Date32column throughCAST,toDate, ortoDate32, including a wrong-results case where1 >= dwas treated asd >= 1. #119184 (Arsen Muk). - Fixed
INSERTinto aDeltaLaketable with atimestamp_ntzcolumn writing theParquetdata file withisAdjustedToUTC=true, which made the committed table unreadable by Spark and other Delta engines. Such a column is now annotatedTIMESTAMP(isAdjustedToUTC=false), as the Delta protocol requires. Closes #120653. #120863 (Groene AI). - Fixed
SHOW TABLES,system.tablesscans, and table resolution hanging indefinitely against apaimon_restcatalog whose listings paginate. #115534 (JIaQi Tang). - Fixed data lake tables created on top of a server disk (
SETTINGS disk = '...'): they no longer overwrite the disk’s object storage settings with the table’s or the query’s settings, and they follow the disk’s configuration onSYSTEM RELOAD CONFIGinstead. #117398 (alesapin). - Reading an Apache Paimon primary-key table now throws
NOT_IMPLEMENTEDinstead of silently returning wrong results. Merge-on-read is not implemented, so the reader returned the raw union of the snapshot’s data files, including the row versions superseded by later upserts. Closes #113360. #113460 (Groene AI). - Fixed
SHOW CREATE DATABASEandBACKUPof aDataLakeCatalogdatabase omitting itsCOMMENT, andALTER DATABASE ... MODIFY SETTINGerasing that comment from the stored metadata, so that it was lost after a restart. #122942 (Groene AI). - Reject
Paimonmanifest and data paths that escape the table directory. A crafted table could previously read files outside its own directory through an absolute path or..components in metadata paths. #123099 (Konstantin Vedernikov). - Fixed a data race between concurrent queries on one
Huditable: the list of the table’s data files was filled on first use without synchronization. #119137 (Alexey Milovidov). - Fixed the Paimon incremental read silently duplicating and dropping data. Advancing the consumed-snapshot watermark in Keeper is now fenced by the
processing_lockand monotonic, so a read that lost the lock can no longer commit over another consumer’s progress. A cursor left ahead of the warehouse, and a snapshot that fails to load for any reason other than Paimon expiration, now raise an error instead of being silently skipped. #117630 (JIaQi Tang). - Fixed two ways a table with the
Redisengine mishandled anMGETreply. Reading the whole table stopped at the first key without a string value and silently dropped every key scanned after it, so one key of another Redis type was enough to truncate the result. A reply carrying a different number of elements than keys requested could terminate the server; such a reply is now rejected withINTERNAL_REDIS_ERROR. #120230 (Groene AI). - Fixed a broker-side queue leak when dropping a
RabbitMQtable.DROP TABLEasked the broker to delete the table’s queues without waiting for its own consumer channels to close, so the broker could still see a registered consumer and refuse the deletion withPRECONDITION_FAILED. #116050 (Groene AI). - Fixed spurious
NATSconnection failures when the vendorednats-ioclient getsEINTRwhile waiting for a socket, and picked up the upstream JetStream pull-subscription deadlock fix in the vendored client. #120202 (Alexey Milovidov). - Fixed
arrowFlightand theArrowFlighttable engine hanging forever when the remote Flight server accepts a request and never answers it. Requests are now bounded by the newarrow_flight_request_timeout_secsetting (300 seconds by default,0disables the bound), and a stalled read honorsKILL QUERYandmax_execution_time. #120231 (Groene AI). - Fixed
SELECTqueries on anEmbeddedRocksDBtable with a compositePRIMARY KEYreturning fewer rows than match the predicate when the predicate combinesINsets withORand one set’s element type cannot be converted to the key type. Such a set no longer narrows the candidate keys. #122261 (Groene AI). - Fixed a
FileLogtable that stopped reading all of its files forever after a single read error (such as a line that failed to parse or a partially written last line): every later poll reportedAnother select query is running on this tableand every directSELECTfailed withCANNOT_SELECTuntil the server was restarted. Related to #123368. #123395 (Groene AI). - Fixed a
NATSengine table reading from a JetStream stream (nats_stream) silently stopping to consume messages after the NATS server restarted or the connection was re-established. #115343 (Alexey Milovidov). #119301 (Alexey Milovidov). - Fix a rare server crash (
SIGSEGVinmongoc_log) when a MongoDB dictionary source orMongoDBtable was created while another thread created the first MongoDB connection in the process. Messages logged by the MongoDB driver now go to the server log. #124235 (Vladimir Cherkasov). RENAME DATABASEis now refused when the database holds a loadedS3QueueorAzureQueuetable whosekeeper_pathexpanded the{database}macro when the table was loaded. Previously the rename succeeded silently, the table bound to a differentKeeperpath at the next server start and reprocessed every file it had already consumed. Not checked: detached tables, tables not yet materialized underlazy_load_tables = 1, and akeeper_pathwhose macros a config reload redefined after the table was loaded. #120103 (Groene AI).SELECT count()andsystem.tables.total_rowsof aJointable that keeps every row of a key,ALL, orANY/SEMI/ANTIwithRIGHT, returned the number of distinct keys instead of the number of rows. #124099 (Groene AI).- Fixed reading
Enum8andEnum16columns ofPostgreSQLandMySQLtables,Nullable(Enum8)andNullable(Enum16)columns ofPostgreSQLtables, andEnumrange columns of aPostgreSQLdictionary source. Values are now returned as the declaredEnumtype, parsed by element name or by number, instead of the raw remote text typed asStringor anUnexpected value N in enumerror. A remote value that is not an element of the enum is now rejected with an error. #125198 (Groene AI). - Fixes
RabbitMQtables withrabbitmq_num_consumers > 1that insert into materialized views withparallel_view_processing = 0(the default) falling behind: the consumers were read one after another, all but the first inserted a single message per flush interval, and their messages waited many intervals (up to about 28 s at 100 msg/s with a 1 s interval). They are now read in parallel. #125106 (Sven Eliasson). - Fixed a server crash (segmentation fault) in a direct
SELECTfrom aNATStable while the table replaces a connection that the NATS client library closed for good, for example after the broker rejected rotated credentials. Closes #120199. #125494 (Groene AI). - Fixed a heap-use-after-free when an
EmbeddedRocksDBtable with a compositePRIMARY KEYwas filtered by a tuple equality whose tuple has aLowCardinalityelement, e.g.WHERE (k, id) = (SELECT (name, id) FROM t LIMIT 1). Closes #120527. #125509 (Groene AI). - Fixed the Arrow Flight interface returning garbage values for a
MergeTreecolumn stored in sparse serialization, which is the default for a column that holds mostly default values. AffectedDoGetwith a SQL ticket,GetFlightInfoandPollFlightInfo. #125553 (Groene AI). - Fixed a server crash when a
RabbitMQtable with theheadersexchange type had a routing key without=, or whenrabbitmq_routing_key_listwas empty. Routing keys without=for theheadersexchange type are now rejected with an exception. The problem was found and reported by @dstesk. #125661 (Alexey Milovidov). StorageKafka2now counts only live replicas when distributing partition locks, so a replica that lost itsKeepersession no longer leaves some partitions unconsumed. #120111 (johnjing).- Fixed memory growth in
Kafkatables with offsets stored inKeeperwhen partitions move between consumers: prefetched messages for released partitions are now freed rather than retained until restart. Closes #125077. #125076 (Aparajita Pandey). - Fixed spurious
TLS/SSL error: Interrupted system callfailures inmysql, theMySQLtable engine, theMySQLdatabase engine, andMySQLdictionaries by updatingmariadb-connector-cto v3.4.10, with a patch that clears the OpenSSL error queue before every TLS operation. #120526 (Groene AI). - Fixed a durability bug in the
MySQLandPostgreSQLdatabase engines. The marker file recording whether a table is detached or dropped was created and removed without fsyncing the metadata directory, so a power loss could silently revert an acknowledgedDETACH TABLE ... PERMANENTLY,DROP TABLE, orATTACH TABLEand change the table’s visibility on restart. It is now fsynced whenfsync_metadatais enabled (the default). A failedATTACH TABLEno longer leaves the table half-attached, which made a retry reportTABLE_ALREADY_EXISTS. #112170 (Groene AI). - Using the
PostgreSQLengine, inserts now quote table and column names so PostgreSQL does not fold them to lowercase. The destination table can therefore use any identifier casing. #120435 (Thomas Sileghem). - Fixed
KILL QUERYandmax_execution_timehaving no effect on a query reading fromPostgreSQLwhen the remote host stops sending data, andDROPof a refreshable materialized view whose refresh reads fromPostgreSQLhanging for the same reason. #118995 (Nikolay Degterinsky). - Fixed
PostgreSQLconnections losingsend_timeoutafter the handshake. #123094 (Sema Checherinda). - HTTP dictionary sources (
SOURCE(HTTP(...))) now respect themax_http_get_redirectssetting, so dictionaries can be created from URLs that redirect. Previously such dictionaries always failed withTOO_MANY_REDIRECTS. #101768 (Yash ). - Fix
optimize_inverse_dictionary_lookuprewritingdictGetcomparisons incorrectly: complex-key dictionaries with a single key column called with atuple-wrapped, possiblyNullable, key expression failed withILLEGAL_TYPE_OF_ARGUMENT; key expressions that rely ondictGet’s implicit key type conversion, e.g. aStringexpression for aUUIDkey, failed withNO_COMMON_TYPE, and lossy ones silently returned results wheredictGetthrows; a match on a dictionary key containingNULLproducedNULLinstead offalse; a single matching floating-pointNaNor zero key produced wrong results; and mismatched key shapes were folded to a result instead of thedictGeterror. Key expressions that would need a conversion are no longer rewritten and keep thedictGetlookup, except a signed integer probe of a simple-key dictionary, which is converted to theUInt64lookup type the waydictGetconverts it. #114865 (Artur Beglaryan). - Fixed a dictionary with a local
CLICKHOUSEsource that stopped updating withACCESS_DENIEDand kept serving stale data after a new role was granted to its source user and the old role was dropped. Every query of such a source now uses the current default roles of the user, like a new session of that user. Closes #122663. #124051 (Groene AI). - Fixed ClickHouse Keeper terminating when a client sent a
multirequest with no subrequests. Such a request was written to the Keeper changelog before it failed, so the termination repeated on every restart. #119847 (Alexey Milovidov). - Fixed ClickHouse Keeper discarding a
world:anyoneACL entry with all permissions when the request contained other entries. Such a node was stored more restrictively than requested and could end up repairable only with asupercredential; with<path_acls>configured and no<identity>, aReplicatedMergeTreeunder the configured path could not be created at all. These nodes now get the requested permissions, which grants every session full access to them, as ZooKeeper does. Closes #120177. #120265 (Groene AI). - Fixed
Keeperpersistent recursive watch events to report the path of the changed node, matching ZooKeeper behavior. Previously, they reported the path where the watch was registered. #121333 (Kirill). - Fix a segmentation fault in
ClickHouse Keeperwhen preallocating space for a changelog file fails because the disk is full. #122337 (Alexey Milovidov). - ClickHouse Keeper no longer sends the same watch event to one session several times when more than one of the session’s watches matches a change, for example persistent recursive watches on
/aand/a/bfor acreate /a/b/c, or a single persistent watch on a removed node. Like ZooKeeper, Keeper now sends each event to a session once. Closes #122291. #122706 (Groene AI). - Fixed a Keeper durability gap: with
force_syncenabled, the directory entry of a new changelog segment, or of a segment continued after a restart, was never fsynced, so acknowledged writes in that segment could be lost after a power loss on filesystems where a file fsync does not persist the file’s name. Keeper now fsyncs the log directory before the first entries of such a segment are reported durable, and stops if that fails. #122755 (Groene AI). - Fixed Keeper silently giving a new session to a ZooKeeper client, for example the Java client or
kazoo, that reconnects and asks to continue its session. Such a client now getsSessionExpired, ZooKeeper’s answer for a session that cannot be continued, instead of losing its ephemeral nodes later without notice. Keeper still does not restore sessions. Closes #116690. #122767 (Groene AI). - Fixed the Keeper HTTP storage API (
/api/v1/storage) storing a truncated value and reporting success when aPOSTorPUTbody was larger thanmax_request_size. Such requests are now rejected with413, and the node is left unchanged. Closes #122286. #122928 (Groene AI). - Fix Keeper recovery with
remove_orphaned_nodes_on_startupleaving an unrepaired snapshot on disk. Persist the repaired snapshot so followers can install it successfully and the recovered node can restart with orphan recovery disabled. #123206 (Seva Potapov). - Fixed a Keeper node that restarted after a crash sometimes giving a new client the session ID of a client that had connected to it before the restart, after which the new client received that client’s responses. #124307 (Groene AI).
- ClickHouse now rejects relative paths in
checksums.txt. #120356 (alesapin). - Encryption codecs (
AES_128_GCM_SIV,AES_256_GCM_SIV) now also cover the structural substreams of a column. #120636 (Raufs Dunamalijevs). - Rejected a compressed block whose codec stores data verbatim, such as
NONEorQuantized, when its declared uncompressed size does not match the body length. Previously that passthrough read path accepted such a block while every other decompression path rejected it. #114344 (Groene AI). - Reject invalid HTTP header names supplied to SQL-facing HTTP clients (the
urltable function and engine, HTTP dictionaries,S3/object storage, andDataLake/REST catalogs). A header name must be a valid RFC 9110 token (letters, digits and!#$%&'*+-.^_`|~); any other byte,:, whitespace, control characters, or separators such as/and=, is rejected. Such names could previously bypass the<http_forbid_headers>restriction. #118830 (Sergei Trifonov). - Fixed
ALTER QUOTAsilently not taking effect when a quota is changed toKEYED BY client_key: a user whose quota context was already cached kept the previous, more permissive limits, and the failed refresh also stopped every other cached context from picking up unrelated quota changes. #120240 (Groene AI). - Kafka producer and consumer trace logs now show secret
librdkafkaproperties, such assasl.password, as[HIDDEN]instead of their cleartext values. #119244 (János Benjamin Antal). EXPLAIN ASTno longer prints secret function arguments, such as the key ofencrypt, in cleartext, including withoptimize = 1for the body of a view the user may onlySELECTfrom. #120313 (Harikrishnan Prabakaran).- ClickHouse now masks credentials in
system.query_logeven for invalid URLs of external table engines. #122057 (alesapin). - The value of
role_session_nameis now hidden inquery_log. #122423 (Alexey Bakharew). BACKUP ... TO S3(...)andRESTORE ... FROM S3(...)now enforceremote_url_allow_hostson the initialS3URL, instead of checking only redirect targets. Endpoints that thes3table function would reject now fail withUNACCEPTABLE_URLhere as well. #123114 (Konstantin Vedernikov).- A password or presigned signature in a URL is no longer printed in clear by the
ConfluentSchemaRegistrytrace log, by theURL ... is not allowed in configuration file, see <remote_url_allow_hosts>error, or by theUnsupported scheme in URIerror. These now showscheme://[HIDDEN]@hostandX-Amz-Signature=[HIDDEN], assystem.query_logalready does forformat_avro_schema_registry_url. #123226 (Groene AI). - Fixed
SYSTEM SYNC TRANSACTION LOG(local, non-ON CLUSTERform) not checking theSYSTEM_SYNC_TRANSACTION_LOGprivilege. TheON CLUSTERform already required it, so a user without the grant could run the local form when experimental transactions were enabled. #112441 (Azhar Izzannada E). - The values of MongoDB connection options that carry a secret (
tlsCertificateKeyFilePassword,sslClientCertificateKeyPassword,AWS_SESSION_TOKENinauthMechanismProperties) are now hidden inSHOW CREATE,system.query_logandsystem.dictionaries.sourcefor theMongoDBtable engine, themongodbtable function and the MongoDB dictionary source,system.dictionaries.sourceno longer shows the MongoDB password, and a named-collectionurioverride after another override is no longer shown as written. #123240 (Groene AI). - A
SELECTrow policy on themergeTreeProjectiontable function (_table_function.mergeTreeProjection) is now also applied to a read shipped to another server as a serialized query plan (serialize_query_plan = 1, withprocess_query_plan_packetenabled there), as it already is for a local read or withserialize_query_plan = 0. #123609 (Groene AI). SYSTEM DROP DATABASE REPLICAwithout a database name is now denied for a user without theSYSTEM DROP REPLICAprivilege, instead of silently doing nothing and reporting success. This makes it consistent withSYSTEM DROP REPLICA. #117964 (Alexey Milovidov).ALTER TABLE ... MODIFY SETTING disk = disk(...)could register a disk defined in SQL whose local path is outsidecustom_local_disks_base_directory, and create its directory, bypassing the check thatCREATE TABLEapplies. Now it is rejected the same way, and a statement rejected this way leaves no disk and no directory behind. #119850 (Alexey Milovidov).- Fixed
ALTER TABLE ... ATTACH PARTITION ... FROM ...andCREATE TABLE ... CLONE AS ...requiring theALTER DELETEprivilege on the destination table. These statements only add data, soINSERTis now enough.REPLACE PARTITION, which does drop the destination data, still requiresALTER DELETE. A session temporary table used as the source ofATTACHorREPLACE PARTITION ... FROMalso no longer wrongly requiresSELECTon a same-named table of the current database. #117936 (Alexey Milovidov). - Fixed the server terminating when an argument of a
disk(...)setting value is a key without a value, such asdisk(equals(name)). A malformeddisk(...)argument no longer causes the whole query, including its other secrets, to be logged unmasked. #123847 (Groene AI). - Mask secrets in the queries that a cluster-mode
QueryRunnertable writes tosystem.query_logas well as in queries executed as startup scripts. #118978 (Miсhael Stetsyuk). - A
RESTORE TABLE ... AS <name>of a backup whose engine arguments were stripped now validates the Keeper path it derives fromdefault_replica_path. Previously the{database}and{table}substitutions were expanded against the restored name without being checked, so a name containing/resolved into another table’s Keeper subtree and left an inactive replica there. #121546 (Groene AI). - Hide secrets in the
system.mutationstable. #122717 (alesapin). - Creating a
FileLogtable now requires theREADandWRITEprivileges, as for aFiletable. #125701 (Robert Schulze). - Fixed an out-of-bounds read when reading a
Variantcolumn from a truncatedNativestream using compact discriminators serialization. #120252 (Raufs Dunamalijevs). - Reject malformed PostgreSQL startup messages whose parameter data exceeds the declared payload size. #112780 (Minh Vu).
- Reading settings from the Native protocol no longer sizes a string from the length a peer declares before the payload arrives, so a Query packet or a server hello can no longer turn a few bytes on the wire into a large memory allocation. This covers settings and query parameters, on the server and in the client. #118612 (Groene AI). #120931 (Alexey Milovidov).
- Fixed a crash when a client sends a block over the native TCP protocol that selects the internal
Detachedserialization kind for a column. #117699 (Pavel Kruglov). COPYoptions are no longer silently ignored on the PostgreSQL wire protocol:WITH (FORMAT csv)and the legacyWITH CSVare now applied, unsupported options are reported instead of skipped, and TSV header auto-detection no longer drops the first data row of aCOPY ... FROM STDIN. #119376 (Alexey Milovidov).- Bound the header column count in
RowBinaryformats to avoid excessive memory allocation from a crafted header. #120282 (George Larionov). - Reject malformed
Nativeblocks or corrupted parts that could make ClickHouse read past the end of aJSONorDynamiccolumn, for example because of duplicate types or paths, a truncated stream, or a part-only serialization version sent over the wire. #117765 (Pavel Kruglov). - Fixed
handshake_timeout_millisecondsnot bounding a connection that stops sending during the handshake, which held a thread forreceive_timeout(300 seconds by default) instead. The setting now also covers the MySQL and PostgreSQL handshake phases and the TLS negotiation; previously a peer that dribbled bytes during a TLS handshake, or stayed silent on the PostgreSQL port, could hold a thread indefinitely. HTTP header reading keeps its ownhttp_headers_read_timeoutbudget, now enforced by the same mechanism. Ontcp_port_secure, ClickHouse no longer writes an exception to a client whose TLS handshake has already timed out, so such a peer no longer holds a handler thread for twice the configured budget. #121547 (Sema Checherinda). #123101 (Sema Checherinda). - Reject malformed binary input with out-of-range VarInt, integer, or enum values, including settings, client info, query plans, distributed task descriptions, and text indexes, instead of silently truncating them. #113944 (sunliqiang). #123242 (Sergei Trifonov).
- The collections of the
Nativeprotocol, the settings and query parameters of a query, the client information, the granted roles, and the table-status lists, are now bounded, so a small packet can no longer make the server allocate memory for data that has not arrived. #117015 (Alexey Milovidov). - Fixed
Code: 102. UNEXPECTED_PACKET_FROM_SERVER (... got Progress)aborting anINSERTthat requests a table structure from the server, when a subquery is evaluated while the server analyses the query. TheProgressandProfileEventspackets sent in that window are now drained instead of rejected, both by the client and by the initiator of anINSERTinto aDistributedorremotetable, where rejecting them also hid the shard’s own error. AffectsINSERT ... SELECT,inputinserts, andINSERT ... VALUESwithasync_insert = 0. #118946 (Groene AI). - Fixed the PostgreSQL wire protocol rejecting a simple query that consists only of comments, such as the
-- pingthat the Go driverpgxv5 sends fromPing, withEmpty query. Such a query is now answered withEmptyQueryResponse, as in PostgreSQL. Closes #84085. #125161 (Groene AI). - Fixed
http_max_multipart_form_data_sizesilently truncating oversized multipart data instead of failing the query, and made it span a form’s external-table parts instead of resetting per part. #120036 (Sema Checherinda). KILL QUERY, query timeouts, and client disconnects now stop a query that reads over HTTP, for example over theurltable function, while it is retrying a request, instead of waiting until all retry attempts are exhausted. #112930 (Alexey Milovidov).- Fixed gRPC queries with transport compression (
gzip,deflate) crashing the server, as they could in official builds since 26.4. Closes #115121. #122668 (Groene AI). - Prevented asynchronous inserts that only need to buffer data from being blocked by another insert waiting for a flush worker while holding their shared queue lock.
SYSTEM FLUSH ASYNC INSERT QUEUEnow also waits for batches removed from the queue that are still waiting for a worker. #118352 (RJ). - Fixed asynchronous
INSERTunder a quotaKEYED BY client_key: the flush ran without the client’s quota key, so it failed withQUOTA_REQUIRES_CLIENT_KEY(or charged the wrong bucket). The quota key is now carried through the async batch and restored on flush, and background quota recomputes no longer log a spuriousQUOTA_REQUIRES_CLIENT_KEYerror. #122296 (Mikhail f. Shiryaev). - Fixed
max_memory_usage_for_userbeing exceeded by memory the user no longer holds. Memory that a query allocates but does not free itself, such as the data of in-memory table engines, cache entries and data waiting in the asynchronous insert queue, is now accounted to whoever owns it, and whatever a query leaves behind is settled when it ends.max_memory_usage_for_useris also applied when a query hands over memory it allocated before it had a user. #113647 (Raúl Marín). - Queries that send data over pooled connections, such as
INSERTinto aDistributedtable, are no longer charged for connection buffers that stay in the pool after they finish, which could count againstmax_memory_usage_for_userwhile another query of the same user was running. #125573 (Raúl Marín). - Fix a possible hang of a query under workload CPU scheduling with
cpu_slot_preemptionenabled: when all its threads were preempted, the query could keep CPU slots it had already used and wait forever for one of them. #123640 (Sergei Trifonov). - Fixed vector search returning too few rows for a query with
arrayJoinbelowORDER BY <distance> LIMIT. A row policy now counts as an additional filter for vector search, sovector_search_filter_strategy = 'prefilter'is honored and the index fetch multiplier is applied for a query filtered by a row policy. FixedNOT_FOUND_COLUMN_IN_BLOCKfor a non-rescoring vector search query when aWHEREfilter or a row policy reads the vector column. #114074 (Alexey Milovidov). - Fix a vector search returning fewer rows than its
LIMIT, and missing true nearest neighbors, after a lightweightDELETE(or with a delete mutation applied on the fly): the vector index is no longer used for a part while it still holds deleted rows. #119371 (Alexey Milovidov). CREATE TABLEnow rejects aSETTINGSname that is neither a setting of the table engine nor a query setting for theFile,URL,S3(withCOSN,OSS,GCS),AzureBlobStorage,HDFS,Log,TinyLog, andStripeLogengines, withUNKNOWN_SETTING, asMergeTreealready did. Thename = DEFAULTandparam_name = valuespellings are rejected too, except where the whole clause is dropped before any engine sees it. Such a name used to be accepted, stored in the table metadata, and never read, so a typo likeinput_format_csv_delimiterforformat_csv_delimitersilently did nothing. A table whose stored definition already names a non-setting still loads. Closes #120705. #120898 (Groene AI).arrayJoinin a projection or in aDistributedsharding key is now rejected atCREATE/ALTERtime. It changes the number of rows, which made every insert into a table with such a projection fail with an exception, and misrouted or failed inserts into such aDistributedtable. #117791 (Alexey Milovidov).- Fixed
ALTER TABLE ... MODIFY ORDER BYaccepting a key expression over a column that the sameALTERretypes through a subcolumn, for exampleMODIFY COLUMN x Tuple(a UInt32, b UInt32), MODIFY ORDER BY (k, x.a), or renames, for exampleRENAME COLUMN x TO y, MODIFY ORDER BY (k, y). Existing parts are not sorted by such a key, so queries that rely on the sort order could return wrong results. Such anALTERis now refused withBAD_ARGUMENTS. Closes #122685. #122765 (Groene AI). - Fixed
ALTER TABLE ... MODIFY QUERYdeleting the column comments of a materialized view with aTOtable. A column that the new query still produces now keeps its comment. #122775 (Groene AI). - Fixed
ALTER TABLE <mv> COMMENT COLUMN <col> '...'and comment-onlyALTER TABLE <mv> MODIFY COLUMN <col> COMMENT '...'returning success and storing nothing on a materialized view with an inner table, which left no supported way to change a column comment on such a view afterCREATE. #119469 (Groene AI). #123033 (Pedro Ferreira). - Fix
DROP NAMED COLLECTIONsucceeding while aMongoDBtable uses the collection, after which the server could not attach the table on restart. The drop is now refused withNAMED_COLLECTION_IS_USED, as for other table engines. #123636 (Groene AI). - A sharding key of a
Distributedtable, aRemotetable or theremote/clustertable functions that containsINwith a subquery or with a non-Settable is now rejected when the table is defined. The set of such anINwas never built, so everyINSERTfailed with aNot-ready Setlogical error andoptimize_skip_unused_shardscould prune to the wrong shard and return wrong results. A table defined earlier with such a key still loads, but anINSERTthat needs the key fails withBAD_ARGUMENTSand shard pruning does not use it. Pruning by a key withINover aSettable, which can change after rows are placed, now needsallow_nondeterministic_optimize_skip_unused_shards, as forjoinGet. #124646 (Groene AI). - Reject a
RENAME DATABASEthat would make the table dependency graph cyclic, for example one that leaves anAliastable referring to itself. Such a rename put a cycle into the server-wide table dependency graph, after which every unrelatedCREATEthat adds a dependency edge failed withINFINITE_LOOPand the renamed database stopped being listable after a restart. #117253 (Alexey Milovidov). - Fixed formatting of a function named
anywith a single subquery argument:SELECT 1 = `any`((SELECT 1))lost its backticks, and because bareANYbefore a subquery is the SQL quantifier, formatting the query changed its meaning toIN. This affected round-trips such as stored view definitions andSHOW CREATE. #120175 (Groene AI). - Fixed parsing of a column named
frominside parentheses, such asWHERE (from IN ('a')), which since 26.8 was read as a subquery starting with theFROMclause and failed withUnknown table function IN,Unknown table expression identifier, or a syntax error. #120950 (Alexey Milovidov). - Preserve quoting for identifiers named
cube,rollup, andrecursiveso formatted queries can be parsed back correctly. #121896 (Jaysurya Ray). - Fix
SET <setting> = DEFAULTignoring an activecompatibilitysetting: the setting now gets the value of that version, unless the settings constraints forbid it, andSET compatibility = DEFAULTreverts the settings it changed. Closes #116883. #116933 (Groene AI). - Fixed direct config substitutions via
from_envfailing when XML-1.0-legal values contain XML special characters like&,<,>, or the]]>sequence; existing<include from_env="..."/>XML-subtree substitutions are unchanged. An explicit<include from_zk="..." yaml="true"/>substitution can read a YAML subtree wherever the generic<include>form is used, including inside a leaf element, so it must not be used for a literal secret or setting. Without the explicityaml="true"attribute, a non-<value is literal text, but direct non-<leaffrom_zksubstitutions are recommended for exact-byte secrets or settings, because surrounding whitespace of an<include>becomes part of a leaf value. Values beginning with<continue to be interpreted as XML fragments for backward compatibility. Upgrade note: a directfrom_envvalue or a non-<leaffrom_zkvalue that was previously XML-entity-encoded, for examplea&b, now resolves to its exact literal bytes and must be stored raw asa&binstead. #101773 (Yash ). - Fixed the server refusing to start with
UNKNOWN_ELEMENT_IN_CONFIGwhen the definition files of executable user-defined functions or of their drivers are placed inconfig.d(for example with<user_defined_executable_functions_config>config.d/*_function.xml</user_defined_executable_functions_config>), which also merges their<function>or<driver>elements into the server config. Closes #123308. #123586 (Groene AI). - Queries over
system.parts,system.parts_columns,system.projection_parts,system.projection_parts_columns, andsystem.dropped_tables_partsnow respect cancellation andmax_execution_timewhile the result is being built. #113909 (Alexey Milovidov). - Fixed a data race on the exception message for a cancelled query: threads no longer append context concurrently to one shared exception object. #119077 (Groene AI).
- Fixed unbounded memory growth from time zone names that were not names of the time zone database. A time zone name now has to be one that
system.time_zoneslists, or a fixed UTC offset spelledFixed/UTC±HH:MM:SS. #120288 (Alexey Milovidov). - Fixed a server abort during transaction rollback: internal exception-reporting helpers could call
std::terminatewhile no exception was being handled. #122891 (Murphy). - Fixed a crash when synchronous logging (
logger.async = 0) had no log sink that accepted a message. #123336 (Groene AI). - Fixed a permanent hang of the server on macOS, where threads that format a time (for example while signing
S3requests, reporting an exceeded quota or reloading a dictionary) could wait forever on the C library’s internal time zone lock while the query profiler was enabled. #125369 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKon a table that has a physical column named_partshadowing the virtual column, for queries such asSELECT count() FROM t WHERE isNull(_part > 0)andSELECT count() FROM t WHERE _partition_id = 'all'. #117539 (Alexey Milovidov). - The statistics cache is now refreshed for read-only
MergeTreetables. #119559 (Rory Shanks). - A
MergeTreetable withtable_disk = 1mounts the parts already present at the disk root. If it declares a sorting key those parts were not written with, reading it raisedLOGICAL_ERRORand aborted the server in builds with assertions enabled. It now reportsINCORRECT_DATAand names the offending part. #119295 (Groene AI). - Fix a refresh of a table whose disks are all read-only (
SYSTEM RESTART DISK, or the backgroundrefresh_parts_intervaltask) failing with aLOGICAL_ERRORand hiding committed parts when a rolled-back part covers them. Follow-up to #100992, which fixed the same case on the startup part-loading path. #111167 (Groene AI). SYSTEM SYNC MERGESno longer returns while the part covering the scheduled merges is still uncommitted: it now waits until a new transaction can see that part. #123396 (Murphy).- Reject empty part names in
CHECK TABLE. #123625 (Minh Vu). - Partition commands on a
DateTime64key accept a literal with.as the date separator again, such as'2024.02.19 00:00:00.500'. #122995 (DeviousCardi). - A
CHECK TABLErunning while a part writestxn_version.txtno longer fails withUnexpected file txn_version.txt.tmp in data part. #124158 (Murphy). - Fixed
ALTER TABLE ... MATERIALIZE TTLfailing withUNKNOWN_IDENTIFIERand being retried forever on a table withttl_only_drop_parts = 1when a part still holds a column that the table dropped while that part’s partition was detached. Mutating such a partition after cloning it into another table withATTACH PARTITION FROMno longer fails with a logical error either. #115962 (Groene AI). - Fixed a member of a
Nestedadded byALTER TABLE ... ADD COLUMNto aMemorytable being read as empty arrays for the rows inserted before theALTER, unless another member of the sameNestedwas read at the same time. It now gets the array sizes of the other members, like inMergeTree. This fixes wrong results ofSELECT,WHERE,PREWHERE,ARRAY JOIN, and row policies over such a column, andSIZES_OF_ARRAYS_DONT_MATCHerrors. #122991 (Groene AI). - Fixed
SELECTfromsystem.part_moves_between_shardsandKILL PART_MOVE_TO_SHARDfailing withCode: 999 ... No node, path .../part_moves_shardwhen any replicated table on the server is attached without its Keeper tree. #122132 (Groene AI). - Fixed an exception (
BAD_GETorNOT_IMPLEMENTED) when a filter on a table with a_part_offsetprojection had aFloatorNullable(Nothing)condition over a column the projection does not store. #124568 (Groene AI). - Fixed a skip index recording the wrong expression type when
ALTER TABLEran in a session whose settings change how that expression resolves.toString(v)over aDynamiccolumn isNullable(String)undercast_keep_nullableandStringat the server baseline, so such anALTERstoredNullable(String)while the writers resolvedString, and the next index rebuild failed an internal type assertion. #119799 (Groene AI). - Fixed
hasPhraserejectingFixedStringinput for some tokenizers, such asicuandsplitByRegexp('\W+'). Closes #123426. #123585 (Elmi Ahmadov). - Fixed statistics about the number of selected rows in trivial
countqueries answered from a text index. #125380 (Anton Popov). ALTER TABLE ... RESET SETTING auto_statistics_typesnow rebuilds the automatic column statistics from the default types immediately. Previously the table kept the statistics of the old setting value until the server was restarted, sosystem.columnsand the statistics written into new parts disagreed with the table definition. #123599 (Rion Bora).- Fix
basicstatistics of parts written by 26.6 or 26.7: afterALTER TABLE ... UPDATEor a lightweightDELETE, non-Nullablecolumns reported a default-value count of 0, which made selectivity estimates wrong. Query results were not affected. To repair parts that are already affected, runALTER TABLE ... MATERIALIZE STATISTICS ALL. #123536 (Samuel Krempaský). - Fixed
indexHintwith aNothing-typed argument, such asindexHint(assumeNotNull(materialize(NULL))), which threwCannot create non-empty column with type Nothinginstead of only narrowing the read. #117635 (Alexey Milovidov). - Fixed
arrayReduceover a non-deterministic aggregate such as an unseededgroupArraySamplebeing treated as deterministic, which pushed aHAVINGpredicate below the aggregation and collapsed per-row draws into a single one. #118971 (Alexey Milovidov). - Fixed an internal error when two
*matchers whose column transformers differ in kind at the same position are compared, for example two lambdas sharing an alias with bodies* EXCEPT (a)and* REPLACE (1 AS a). Such a query now reportsMULTIPLE_EXPRESSIONS_FOR_ALIAS. #120234 (Groene AI). - Fixed a
LOGICAL_ERROR(Can't set alias of ... of QualifiedAsterisk) when a column transformer that assigns a name, such asAPPLYwith a name prefix orREPLACE, is applied to an expression that expands to an asterisk or aCOLUMNSmatcher. Such queries now return a clearBAD_ARGUMENTSexception. #109223 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKforLIMIT BYon an injective function of aGROUP BYkey, such asGROUP BY toString(c0) LIMIT 1 BY toString(c0). #120070 (Alexey Milovidov). - Fixed
LOGICAL_ERROR: Incorrect table expressionwhenEXPLAIN AST optimize = 1orEXPLAIN SYNTAXreads from the experimental table functioneval. #121272 (Groene AI). - A non-finite
FROM,TO,STEP, orSTALENESSvalue inORDER BY ... WITH FILL(nan,inf, or-inf) is now rejected withINVALID_WITH_FILL_EXPRESSION. Previously such a value either made the query generate fill rows endlessly (TO nan,TO infascending,TO -infdescending, and the same values forSTALENESS) or produced a wrong result: a non-finiteFROMemitted the bound itself as a row and dropped the fill rows thatTOasked for, while a non-finiteSTEP, or aTObound the fill runs away from, returned the rows unfilled. Pass a finite value instead, or omit it. #118434 (Alexey Milovidov). - Fixed exception
Trying to compare constants of incompatible typesfor a query with anINlist over a column of a table that has aCONSTRAINT ... ASSUME, when bothconvert_query_to_cnfandoptimize_using_constraintsare enabled. #118278 (Alexey Milovidov). EXPLAIN ASTno longer throws when aBackuplocator name looks like aCOLUMNSmatcher. #122870 (Groene AI).ORDER BY ... WITH FILL ... INTERPOLATEof the fill column itself is now rejected over aDistributedtable as well, with the same exception a local table already reported, instead of returning rows whose fill column was overwritten by the interpolated expression. #118304 (Alexey Milovidov).- Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen a query over thefilesystemtable function combinesindexHintwith an ordinary condition on the same column. #118671 (Alexey Milovidov). - Fixed wrong results from
optimize_using_constraintswith aCONSTRAINT ... ASSUME NOT (...): a negated comparison could be added to the constraints graph as if it were positive, making predicates such asa < bappear always true anda >= balways false. #121255 (Alexey Milovidov). - A
HAVINGclause referencing aSELECTalias whose quoted name contains a dot, as inSELECT sum(t1.c1) AS `t1.c1` FROM t1 AS t1 HAVING `t1.c1` > 0, is no longer rejected withNOT_AN_AGGREGATE. The identifier resolution cache conflated that quoted one-part name with the qualifiedt1.c1, which could also return a wrong result instead of an error when both spellings met in one query. Default settings were affected from 26.6, whereenable_identifier_resolve_cachebecame enabled by default. #122017 (Groene AI). - The analyzer now rejects
arrayJoininINTERPOLATEand inHAVINGwithWITH TOTALS. Before,INTERPOLATEused only the first array element, andHAVINGfailed only during execution. #123538 (Yarik Briukhovetskyi). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen a comparison of single-element tuples whose elements are tuples, such astuple((a, b)) = tuple((c, d)), is part of an alias used inGROUP BYand also inORDER BY,HAVING, orWHERE. Such comparisons are now rewritten completely, soWHERE tuple(tuple(x)) = tuple(tuple(y))over aJOINno longer returns rows wherexandyare bothNULL, the same asWHERE tuple(x) = tuple(y). #124546 (Groene AI). - Fixed the exception
Not-ready Set is passed as the second argument for function 'in'when theadditional_result_filtersetting contains anINsubquery. Such a query now applies the filter instead of failing. #117719 (Groene AI). - A nested correlated subquery that cannot be decorrelated now reports
NOT_IMPLEMENTEDinstead of the internal errorCannot find column ... in actions DAG input. #118317 (Alexey Milovidov). - Fixed
NOT_IMPLEMENTEDfor a correlated subquery in theSELECTlist of a query that has aWHERE, when the correlated column is not also selected, andNOT_FOUND_COLUMN_IN_BLOCKfor a correlated subquery inHAVINGof a query withWITH TOTALS. #118402 (Alexey Milovidov). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKfor a correlated subquery that reads a tuple element of an outer column by position (o.p.1), and for the same shape on the left ofIN (subquery)underrewrite_in_to_join. #118287 (Alexey Milovidov). - Fixed
Cannot evaluate correlated scalar subqueryfor a query that uses one correlated scalar subquery twice in the same expression, for example in both branches ofif(1 = 1, ..., ...). #118321 (Alexey Milovidov). - Fixed an out-of-bounds read when finalizing a crafted
analysisOfVarianceaggregate state whose internal arrays have mismatched lengths. #107860 (uwezkhan). - Fixed an out-of-bounds read of the parsed pattern in
sequenceMatch,sequenceCount, andsequenceMatchEvents. When the trailing part of a pattern consisted only of actions that a zero-length match satisfies (.*and(?t...)conditions), the matcher read one element past the end of its action list, sosequenceMatchandsequenceCountcould return0for a pattern that does match. #119871 (Groene AI). - Fix an out-of-bounds read when deserializing a
uniqThetastate shorter than 24 bytes, for instance fromCAST(<string> AS AggregateFunction(uniqTheta, ...)). #119598 (Alexey Milovidov). - Fixed
regr_r2returning1instead ofnanwhen the data contains a NaN or an infinity.regr_sxxandregr_syyreturned0in the same case. #123249 (mosya415). - Reject malformed serialized
groupBitmapstates withINCORRECT_DATAinstead of failing later during bitmap operations. #124049 (Elmi Ahmadov). - Fixed wrong results in the
largestTriangleThreeBucketsaggregate function forDateTime64arguments close to the type’s upper bound: the maximumDateTime64(9)value was returned as1677-09-21 00:12:43.145224192. Such values are now saturated instead of wrapping, and a deserialized state whoseDate,Date32,DateTimeorDateTime64coordinates are out of range or fractional is rejected with an error. #120284 (Groene AI). - Fix a wrong result, or an exception in debug builds, when
optimize_aggregators_of_group_by_keyseliminatedany,minormaxof aGROUPING SETSkey withgroup_by_use_nulls. #125575 (Alexey Milovidov). - Fixed several URL-parsing bugs in
domainRFCandportRFCfor bracketed IPv6 hosts: an embedded IPv4 tail (for example[::ffff:192.168.0.1]) was rejected, non-IPv6 bracket contents and garbage following the closing bracket were silently accepted, and userinfo state could leak into host validation. Also fixeddomainRFCandportRFCresolving the wrong host when a URL’s userinfo contains more than one@, rejected a host starting with a literal dot indomainanddomainRFC, and fixedfirstSignificantSubdomainRFCandcutToFirstSignificantSubdomainRFCreturning a bogus subdomain for a bracketed IPv6 host instead of an empty result. #118979 (Luís Lizardo). - Fixed
IPv4StringToNum,IPv6StringToNum,isIPAddressInRange,parseDateTime,parseDateTime64,parseDateTimeInJodaSyntax,parseTimeDelta,parseReadableSize,toModifiedJulianDay,JSONMergePatch,stringToH3, and the H3 index functions throwing an exception on entirely validLowCardinalitydata. #117359 (Alexey Milovidov). - Fixed the exception
Cannot convert out of range floating point value to integer typewhen a logical function (and,or,xor) receives a constant floating point argument outside{0, 1}, such asSELECT 1 OR 2.0. #117965 (Alexey Milovidov). timeSeriesRangeandtimeSeriesFromGridnow throwARGUMENT_OUT_OF_BOUNDwhen the requested number of points would exceedfunction_range_max_elements_in_block, matching the behavior ofrange. Previously an unbounded request would run for tens of seconds and allocate hundreds of gigabytes before hitting the memory limit. #121056 (Ilya Yatsishin).bitShiftLeft,bitShiftRight,bitRotateLeft, andbitRotateRightno longer answer, once the expression is compiled, for the arguments their interpreted implementation rejects: a big-integer or negative shift amount. #118716 (Alexey Milovidov).- Fix
mapPopulateSerieskeeping the wrong value when duplicate keys are present. #119832 (Minh Vu). - Fix
formathandling of escaped braces around replacement fields. #120704 (Minh Vu). jaroSimilarityandjaroWinklerSimilaritynow return0when one input is empty. #119710 (Minh Vu).- Fixed
plusandminusover an array of dates and an array of tuples holdingNULL, for exampletoString([toDateTime64(1, 3)] + [(2, NULL)]), and the exceptionColumnTuple cannot have ColumnConst as its elementwhen adding a constant interval to a non-constant interval of another unit, for exampletoIntervalDay(number) + INTERVAL 1 HOUR. #122451 (Groene AI). - Fixed
timeSeriesCopyTagsandtimeSeriesCopyTagwhen both group arguments are constant. They returned a single row regardless of the number of input rows, so such a call over several rows failed withInvalid number of rows in Chunk(LOGICAL_ERROR), and a single-row query printed an extra row inclickhouse-client. #122990 (Groene AI). - Fixed
ifandCASEover tuples failing withColumnTuple cannot have ColumnConst as its elementwhen an element isNULLin both branches, for exampleif(number = 0, (1, NULL), (number, NULL)). #123268 (Groene AI). - Fixed
geometryIntersectCartesianandgeometryIntersectSphericalreturning an arbitrary result (usually1) for an emptyLineString, or aMultiLineStringwith an empty element, against aRing,Polygon, orMultiPolygon. For such aMultiLineString,polygonsDistanceCartesianandpolygonsDistanceSphericalcould return0. #124101 (Groene AI). - Fixed an infinite, uncancellable loop in functions
hop,hopStartandhopEndwhen subtracting the hop interval does not move the window end, for examplehopEnd(toDateTime(0, 'UTC'), toIntervalQuarter(413844), toIntervalQuarter(413844)), where the date saturates at the calendar limit. Such arguments now throw theTime overflowerror. #124570 (Groene AI). - Fixed the result type of
randConstant,rand,rand32,rand64,randCanonical,generateUUIDv4,generateUUIDv7andgenerateULIDwhen their optional ignored argument has typeNothing: they declaredNothingrather than their documented type.randConstantwith more than one argument also raisedLOGICAL_ERRORduring query analysis instead of reporting the wrong argument count. #116072 (Groene AI). KILL QUERYandmax_execution_time(includingtimeout_overflow_mode = 'break') now stop AI functions in the middle of a block, instead of only after all requests for the block have finished. #125698 (George Larionov).- Fixed the exception
Provided time zone must be non-emptywhen the time zone argument offormatDateTime,formatDateTimeInJodaSyntax,fromUnixTimestamp, orfromUnixTimestampInJodaSyntaxis aLowCardinalitycolumn. #117006 (Alexey Milovidov). - Fixed
toWeekandtoYearWeekwith mode8returning week135forDate32andDateTime64values in the year 1900 and earlier. The wrong values also made the primary key analysis drop matching rows for predicates ontoYearWeek(key, 8). #117694 (Alexey Milovidov). - An out-of-range integer constant in an
INset for aDateTime64orTime64column no longer wraps to a negative timestamp and matches an unrelated row. #118656 (Alexey Milovidov). - Fixed
makeDateandmakeDate32with two arguments to accept day 366 in leap years. #119363 (Minh Vu). - Fixed
CASTof an empty container to a container ofVariantorDynamic, which was rejected withCannot convert type Nothing to Variant(...)orVariant type should have at least one nested type. This also fixes a query returning an emptyArray(Variant(...))failing once part of it runs on a secondary server, where the folded constant is re-rendered as a_CASTof an empty container. #118038 (Groene AI). - Fixed
TYPE_MISMATCH(CAST AS Array can only be performed between same-dimensional array types) when casting anArray(Map(...))to an array whose element type contains theMapinside aVariant, or toArray(Dynamic),Array(JSON), orArray(String). #120948 (Alexey Milovidov). - Fixed
arraySliceandarrayElementon aQBitcolumn replicated byARRAY JOINor aJOIN: debug builds raisedLOGICAL_ERROR, while release builds could return wrong results. #120224 (Groene AI). - Fixed a function over a
Dynamiccolumn reportingLOGICAL_ERRORwhen an unrelated exception, such asMEMORY_LIMIT_EXCEEDED, was raised while converting the nested result to the declared result type. Such exceptions now keep their own error code, message, and stack instead of being reported as an internal error. #121280 (Groene AI). - The
JSONtype and theJSON*functions now also acceptStringvalues holding bytes that are not valid UTF-8 on builds where simdjson uses its scalarfallbackbackend (s390x,riscv64andloongarch64without RVV / LSX,amd64compaton CPUs without SSE4.2 or PCLMULQDQ), which previously failed withINCORRECT_DATA. #123945 (Groene AI). - Fixed an exception when a function applied to a
Dynamiccolumn returns a result of theNothingtype, for examplearrayElementon an empty array literal. Such queries now returnNULLfor every row instead of failing withstd::out_of_rangeorVariant type should have at least one nested type. #115982 (Groene AI). - Fixed
CAST AS QBit can only be performed from String, Array or another QBit(andUnsupported types for IN) errors when a query with aQBitconstant, such asWHERE q = CAST([1, 2], 'QBit(Float32, 2)')orq IN (...), runs overremote, aDistributedtable, or parallel replicas. #125038 (Groene AI). - Fix
LOGICAL_ERROR: Column identifier ... is already registeredwhenanalyzer_compatibility_join_using_top_level_identifier = 1and aJOIN ... USINGkey resolves to anALIAScolumn of a table function such asmergeorremote.NATURAL JOINnow also matchesALIAScolumns of a table function, as it already did for a table, and no longer takes a non-selectableEPHEMERALcolumn as a join key on either side; with no other shared name it behaves as aCROSS JOINrather than failing withCode: 16. #118734 (Groene AI). - With
analyzer_compatibility_join_using_top_level_identifier = 1, aJOIN USINGidentifier of the outermostJOINis now also resolved from an alias defined in theWITHclause or in another clause of the query, not only from theSELECTlist, and duplicated aliases with identical definitions no longer prevent the resolution; an innerJOINof a query with several joins resolves it from its left table, as the old analyzer did. This fixesUNKNOWN_IDENTIFIERfor such queries and aUSING clause expected identifiererror when an innerUSINGjoin is placed below an aliased outermostUSINGkey. Closes #121401. #121975 (Vladimir Cherkasov). #123103 (Vladimir Cherkasov). - Fixed a null dereference while formatting the
LOGICAL_ERRORfor aUSINGcolumn with no expression; the query now reports the column name instead. Closes #123292. #123296 (Raúl Marín). - Fix the AST predicate push-down into distributed subqueries treating non-deterministic
EXECUTABLEandWASMuser-defined functions as deterministic. It pushed a predicate over such a function’s result to the shard, which evaluated the function again. #119865 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR(Initiator received more initial requests than there are replicas, orDuplicate announcement received for replica number N) when amergeTreeAnalyzeIndexespredicate contained a correlated subquery and parallel replicas were enabled. #119860 (Groene AI). - Parallel replicas are kept enabled for cluster engines when
automatic_parallel_replicas_modeis set. Also, from now on, withenable_parallel_replicas = 2parallel replicas are forced and the automatic mode is not applied. #122306 (Nikita Taranov). - Fixed
NO_SUCH_DATA_PARTin amake_distributed_planbucketed read when a worker’s own index analysis prunes a part that the coordinator selected, for example withuse_index_for_in_with_subqueries = 0and anIN (subquery)predicate. Such parts are now skipped instead of producing a false “part … selected by the coordinator is not available on this replica” error. AddedDistributedPlanWorkerPartsReceived,DistributedPlanWorkerPartsScanned, andDistributedPlanWorkerPartsPrunedprofile events. #115514 (Groene AI). - A serialized query plan carrying
max_block_size = 0is now rejected when it is read, instead of constructing steps with a zero block size that could make the receiving server hang. #120606 (Nihal Z. Miaji). - Fixed a case where
make_distributed_planfell back to local execution for the outer query but still built innerINsubquery sets as distributed plans inside views, scalar subqueries,GLOBAL INsubqueries,Distributedshard plans, materialized CTEs, andTimeSeriesreads. #119986 (Antonio Filipovic). make_distributed_planqueries that resolve dictionary functions,joinGet, orMergeTreecolumn defaults only on the initiator now fall back to local execution, avoiding worker-sideDictionary (...) not foundfailures and similar unresolved-reference errors. #121198 (Antonio Filipovic). #121567 (Antonio Filipovic).- A cancelled or failed distributed query with
make_distributed_plan = 1no longer waits for the handshake timeout of a streaming exchange whose producer does not answer. Closes #122395. #122422 (Groene AI). - Fixed distributed query plans losing a
LIMITearly-stop signal on an in-memory exchange when a port closed concurrently. Such queries could keep reading whole inputs or wait for exchange streams after theLIMITwas already satisfied. #122453 (Groene AI). - Fixed the
LOGICAL_ERRORReading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query planon a table read with more than one stream, raised by a lightweightUPDATEorDELETEwhose predicate passes anINsubquery that defines aMATERIALIZEDCTE to a function such asignore, and by a lightweightUPDATE/DELETEor aSELECTwhen anINor other set subquery defines aMATERIALIZEDCTE that two otherMATERIALIZEDCTEs of that subquery read. #119715 (Alexey Milovidov). #121010 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen a predicate on aMergetable’s_tableor_databasevirtual column is wrapped inindexHint. #117612 (Alexey Milovidov). - Fix
Column `__array_join_exp_1` not found in tableforARRAY JOINwith a filter on the array-joined column over aMergetable whose child is aDistributedtable. #119307 (Alexey Milovidov). - Fixed a
LOGICAL_ERRORUnexpected return typewhen reading aMergetable whose underlying table is anotherMergetable with different column types, withoptimize_prewhere_after_pushdown = 1andmove_all_conditions_to_prewhere = 0. #124037 (Groene AI). - Fixed
TRUNCATE TABLEfailing withDEADLOCK_AVOIDED, leaving the data in place, while the table is being read concurrently, for aMergeTreetable in a database withlazy_load_tables = 1and for anAliastable whose target is aMergeTreetable. #119105 (Groene AI). #121703 (Groene AI). #113634 (Groene AI). TRUNCATE ALL TABLES FROMandTRUNCATE TABLES FROM ... LIKE ...now skipAliastables, which hold no data of their own. Previously such a statement could fail withLOGICAL_ERROR, truncate a target in another database, or fail when the alias target was missing. #121134 (Groene AI).- Fix
SHOW CREATE TABLE,system.tables.create_table_query, and metadata files ofAliastables including a column list, which is invalid forENGINE = Aliasand goes stale when the target table changes. #115141 (Enric Calabuig). - Fixed a logical error when a non-
APPENDrefreshable materialized view was created in a non-Atomic/Replicateddatabase via a full-definitionATTACH, or via aRESTOREof a view that had a UUID into such a database.CREATEalready rejected this combination;ATTACHandRESTOREbypassed the check and produced a broken view with no UUID. Backups of views that never had a UUID stay restorable, and refresh now fails cleanly instead of aborting in debug and sanitizer builds. #111928 (Groene AI). - Fixed
SELECT count()never terminating, or returning an invented row count, on anAvrofile with a corrupted block header. The bundledClickHouse/avronow rejects a block row count larger than its payload can hold wherever it can derive a lower bound for the schema, soSELECT count()oversnappy-compressedAvrofiles still uses the block header row count instead of decoding every row. #116156 (Groene AI). #121211 (Groene AI). - Fix
rows_readandrows_before_limit_at_leastin the statistics of theJSONandXMLoutput formats being reported as 0 or too small when a query withLIMITreads from remote servers (parallel replicas or theremotetable function), because the output format could be finalized before the remaining progress was drained from the connections. Also fix a query broken off bytimeout_overflow_mode = 'break'answering with a truncated response - or with no response body at all - instead of a complete document with the statistics, and, over the native protocol, dropping the rows that had already been produced when the time limit was checked. #118000 (Alexey Milovidov). - Fix
CANNOT_SEEK_THROUGH_FILEwhen reading a subset of columns from anArrowStreamthrough a pipe, for example withclickhouse localreading stdin. #125689 (Mishalski). - Fixed
FileLogon macOS re-reading a file from offset0when it is renamed during a directory rescan. #122448 (Groene AI). - Fixed
FileLogsilently skipping the first rows of a file moved into the watched directory from elsewhere (for example a staging file renamed into place) when that file got the inode of a file just deleted from the directory. Such a file is now read from the beginning. #123593 (Groene AI). - A
FileLogfile that cannot be opened (removed, a symlink whose target was removed, not readable by the server) no longer stops the table: the other files keep being consumed, and it is skipped, logged once and retried until it can be opened while the table is loaded, unless the directory reports that it was removed, renamed or replaced. With the defaulthandle_error_mode, a record that cannot be parsed is now logged and skipped while the table streams into materialized views, instead of failing the whole insert together with the rows read from the other files; a directSELECTstill throws. #123595 (Groene AI). - Fixed the warning about a setting duplicated in the definition of an
S3QueueorAzureQueuetable, which said that the first value is used while the table uses the last one. #124916 (Vadim Lopatin). - Fix the
KafkaConsumersWithAssignmentmetric drifting negative: it was decremented twice for every consumer-group rebalance. #113919 (kalavt). - Fixed the histogram metric
keeper_read_wait_for_write_time_millisecondsand the OpenTelemetry spankeeper.read.wait_for_writealways reading zero and never being emitted whenuse_new_dispatcheris enabled, which is the default. #115252 (Groene AI). TestKeeperno longer treats nodes that only share a name prefix as descendants:removeRecursiveof/qkeeps/q2, andlistRecursiveandlistWithOptionsof/qreturn its children when a sibling such as/q-xexists. #122769 (Groene AI).- Fixed Keeper
ProfileEventsKeeperPacketsSent,KeeperPacketsReceived,KeeperRequestTotal,KeeperRequestTotalWithSubrequests, andKeeperLatencybeing counted twice. After upgrading, these counters grow at half the previous rate. #122811 (myeongjun). - Fix unbounded recursion when decoding a deeply nested value inside a binary-encoded type, for example an
AggregateFunctionparameter in aDynamicvalue read fromRowBinaryorNative. #122667 (Pavel Kruglov). - Fixed
SHOW COLUMNSfailing withCannot parse string 'Decimal' as Int8(CANNOT_PARSE_TEXT) forNullable(Decimal(P, S))columns when the connection is made through the MySQL wire protocol. #75694 (ultrabig). - Fix a logical error
Cannot write to canceled bufferin the PostgreSQL wire protocol handler when a client disconnects while the server is still sending the result of a query. #118369 (Alexey Milovidov). - Fixed a signed overflow in the workload throttler that made
system.scheduler.throttling_usreport a negative value for a workload whosemax_bytes_per_second,max_queries_per_second, ormax_cpusis small enough to postpone a request for longer than a year. Such a postponement is now saturated at one year. #113697 (Groene AI). - Fixed the
throughputcolumn ofsystem.schedulerreporting a small fraction of the real value (about 0.05x initially and 0.3x after 4 seconds) for about 20 seconds after a scheduling node is created, for example right after server start orCREATE WORKLOAD. The client’s CPU usage indicator, which uses the sameEventRateMeter, was affected the same way on its first samples. Closes #121962. #122006 (Groene AI). - Fix a logical error
Cannot add step Limit to QueryPlan because it has incompatible header with root step Sortingwhen a vector search query withvector_search_with_rescoring = 0was executed with the experimentalmake_distributed_plansetting. #114457 (Alexey Milovidov). - Fix
assignCentroid(vec, 'dict')with an unqualified dictionary name over aDistributedtable,cluster/remote, or parallel replicas. Remote shards and replicas resolved the name in their owndefaultdatabase, so the query failed withDictionary (dict) not foundor silently used a dictionary with the same name fromdefault. The name is now resolved in the current database of the initiator, as fordictGet. #123711 (Groene AI). - Fixed
UNDROP TABLEfailing withLOGICAL_ERROR(Failed to get metadata path from database) instead ofUNKNOWN_TABLEwhen the target database engine stores no table metadata on disk, for example aMemorydatabase that reused the name of a droppedAtomicone, or the default database ofclickhouse-local. #120945 (Groene AI). - Fixed
ALTER TABLE ... MODIFY SETTING name = DEFAULTskipping the checks an engine makes on a setting reset. #119475 (Raúl Marín). - Fixed
TRUNCATE ALL TABLES FROM <db>failing withNOT_IMPLEMENTEDfor the whole database when it held a table whose engine stores no rows of its own, such asMerge,Null,GenerateRandom,Executable,ExecutablePool,FuzzQuery,FuzzJSON, orURL. Such tables are now skipped, as views and dictionaries already were. #121248 (Groene AI). - A table created without a column list over a source that carries a per-column
TTLno longer inherits thatTTLwhen its own engine does not support one, such asMerge,Buffer,Distributed, orRemote. #121335 (Groene AI). - Fixed the logical error
Cannot find column <name> in ColumnsDescriptionwhen a singleALTERstatement on a materialized view appliesCOMMENT COLUMNorMODIFY COLUMN ... COMMENTafter aMODIFY QUERYwhose new query no longer produces that column. Such a statement now reports the missing column instead of aborting in debug and sanitizer builds. #121469 (Groene AI). - Fix
LOGICAL_ERRORCannot capture column N because it has incompatible typewhen a materialized view with a lambda over anArray(Tuple(...))column receives a block while the source table’s column type is being changed byALTER TABLE ... MODIFY COLUMN. #122345 (Jimmy Aguilar Mena). #123514 (Jimmy Aguilar Mena). #124740 (Groene AI). - In a
Memorydatabase, the name of a detached table, view or dictionary is now reserved, as inAtomicdatabases. A statement that would create a new object under it (CREATE,CREATE OR REPLACE [MATERIALIZED] VIEW, orATTACHwith a full definition) fails withTABLE_ALREADY_EXISTS,IF NOT EXISTSmakes it a no-op, and a shortATTACHrestores the detached object. Previously these statements were accepted, butSHOW CREATE TABLEand the table dependencies kept describing the detached object, and a laterALTERof such a view failed with aLOGICAL_ERRORexception. #122670 (Groene AI). - Fixed a window definition that places a frame before the parent window name, as in
WINDOW x AS (ROWS UNBOUNDED PRECEDING w). That order is now a syntax error, while a parent window named after a frame keyword, as inWINDOW x AS (rows), now parses. #120156 (Groene AI). - Formatting
EXPLAIN AST (<query>) FORMAT ...or... SETTINGS ...now keeps the parentheses forINSERT,DELETE,CREATE, a nested non-SELECTEXPLAIN, other non-SELECTqueries, and aSELECTorEXPLAINwith output options of its own, andEXPLAIN SYNTAX SYSTEM ... FORMAT ...is no longer formatted with parentheses that do not parse, so the formatted query parses back with the same output options. #123189 (Groene AI). - Fixed formatting of PostgreSQL
COPYqueries so table names, columns, direction, format, and header options are preserved. #123601 (Minh Vu). - Keep empty
LIKEandILIKEpatterns inSHOWstatements, includingSHOW FUNCTIONS. #123624 (Minh Vu). #123626 (Minh Vu). - A one-argument
tuplein theORDER BYof a projection, such asORDER BY tuple(c0), is now kept when the definition is formatted, so the formatted query parses back to the same definition. #123162 (Alexey Milovidov). - Fixed formatting of the tuple element access operator when its index carries an alias.
SELECT ((1,2) AS t).(1 AS a)was formatted asSELECT ((1, 2) AS t).(1) AS a, which re-parses with the alias attached to the wholetupleElementinstead of to the index. This changed the column names of a query passed throughformatQueryor sent to a remote shard, and raisedInconsistent AST formattingon builds with assertions enabled. #120217 (Groene AI). - Fixed
formatQueryandformatQueryFromJSONdroppingFULLfromSHOW FULL DATABASESand the other supportedSHOW FULLforms.SHOW FULL DICTIONARIESno longer selects a non-existentenginecolumn, and builds with assertions enabled no longer fail withInconsistent AST formatting. Closes #123967. #124036 (Groene AI). - Fixed a crash and a
LOGICAL_ERRORwhen alambdafunction reached query analysis without thelambda(tuple(...), body)shape the SQL parser always produces. An AST deserialized from JSON (dialect = clickhouse_json) can no longer mark an arbitrary function as a lambda, andCREATE FUNCTION f AS g(tuple(x), x)is now rejected withBAD_ARGUMENTSinstead of failing whenfis called. Closes #120380. #120483 (Groene AI). - Fixed server termination on
CREATE TABLE/ALTER TABLEwhen a constraint expression restored through theclickhouse_jsondialect held a function without anargumentslist. Such a payload now fails withBAD_ARGUMENTSwhile the AST is deserialized, so shapes that used to be accepted and fail later atINSERT(for examplenotEqualswith no argument list) are rejected at parse time inside that dialect. #120507 (Groene AI). - Fixed
formatQueryFromJSONaccepting enumerator names that name no value (an enumeration bound, or an unset default), such as{"type":"SystemQuery","query_type":"UNKNOWN"}, which raisedLOGICAL_ERROR: Unknown SYSTEM commandinstead of reporting bad input. Such names are now rejected withBAD_ARGUMENTS. Closes #120741. #120886 (Groene AI). - Fixed two segfaults in
formatQueryFromJSONwhen a node omits a child that formatting dereferences unconditionally. Closes #120739. #120876 (Groene AI). - Fixed a server crash when a
clickhouse_jsonpayload restores an expression holding a function with noargumentslist, a shape the SQL parser cannot produce. Such a payload is now rejected withBAD_ARGUMENTS, as is an emptyTTLlist, which was persisted as metadata that no longer loaded. #120882 (Groene AI). - Fixed
formatQueryFromJSONraisingLOGICAL_ERROR: Unknown element in AST: Foreign Keyfor a payload of typeForeignKeyDeclaration. That node type has no formatter and no query can produce one, so it is now rejected withBAD_ARGUMENTS. Closes #120738. #120915 (Groene AI). - Fixed stack exhaustion when deserializing an AST from JSON through
formatQueryFromJSONor theclickhouse_jsondialect. Such payloads now fail withTOO_DEEP_RECURSION. #121693 (Groene AI). - Fixed a silently corrupted query when a node restored from the AST JSON format (
formatQueryFromJSON,dialect = 'clickhouse_json') carried a shape the parser cannot produce, such as a bare select query argument or an expression list where an argument was expected. Such a node is now rejected withBAD_ARGUMENTSinstead of formatting into SQL that parses back as a different query. #120725 (Groene AI). - Fixed stack exhaustion in
parseQueryToJSONwhen serializing a query nested deeper than the serializer could follow, reachable by raisingmax_parser_depthabove its default. Such a query now fails withTOO_DEEP_RECURSIONinstead of terminating the server. #121856 (Groene AI). - A
CREATE DICTIONARYsent in the AST JSON format (dialect = 'clickhouse_json') is now rejected withBAD_ARGUMENTSwhen the brackets of a key-value argument do not match its value, a bracketed list holds something other than key-value pairs, theSOURCEhas no brackets, the primary key is empty or not a list of identifiers, aDEFAULTis not a literal, or the attributes or the definition are missing or empty, and so is any other query that carries them. Such queries could crash the server or prevent it from starting. #122981 (Groene AI). - Fix a server crash (SIGSEGV) when a
CREATE TABLE ... PROJECTION/ALTER TABLE ... ADD PROJECTIONstatement is restored from aclickhouse_jsonAST whose projectionquerysubtree contains a function node without anargumentslist. The malformed payload is now rejected withBAD_ARGUMENTSduring AST JSON deserialization. #121113 (Ilias). - A
clickhouse_jsonpayload that restores a function without anargumentslist into an expression slot read by the pre-analyzer stack is now rejected withBAD_ARGUMENTSwhile it is being deserialized. Previously such a payload was accepted and could reach a visitor that dereferences the missing list, terminating the server. #121119 (Groene AI). - Fixed
parseSizeandparseTimelogic to correctly distinguish between size thresholds and time-based rotation schedules such as12:00. Fixes #103108 and #100910. #103127 (Jianmei Zhang). - A configuration file can be written in XML or in YAML, but only
config.xmlwas looked up as the default configuration file. Nowclickhouse-server,clickhouse-keeper,clickhouse-local,clickhouse-keeper-clientandclickhouse-disksalso findconfig.yamlandconfig.yml(keeper_config.yamlandkeeper_config.ymlfor Keeper). Previously,clickhouse-serversilently started with the configuration embedded into the binary when only aconfig.yamlwas present. #118422 (Alexey Milovidov). clickhouse install(and thereforeapt/dpkgpackage upgrades) no longer prompts interactively to set up a password for thedefaultuser when that user has been explicitly removed from configuration via<default remove="1" />inusers.d. Previously the installer only checked whether thedefaultuser already had a password configured, missing the case where the user itself does not exist in the merged configuration at all, so it kept asking for a password on every upgrade even though there was no user to set it for. #110438 (Eduardo Gómez).- Fixed the per-query
MemoryAllocatedWithoutCheckandMemoryAllocatedWithoutCheckBytesvalues insystem.query_log. A thread’s untracked memory balance is flushed when the thread is attached to a query, and that flush was reported as the query’s, so memory allocated before the query existed was charged to it. #116505 (Groene AI). - Fixed
AsynchronousInsertQueueSizeandAsynchronousInsertQueueBytesinsystem.metricsgrowing permanently afterSYSTEM FLUSH ASYNC INSERT QUEUE. #120215 (Sema Checherinda). - Fixed a trailing NUL byte in the
notationcolumn ofsystem.unicode, which madelengthreturn a wrong value and comparisons such asnotation = 'U+0041'never match. #122119 (David Meng). - Fixed
CGroup*asynchronous metrics being silently missing on cgroup v2 systems that run ClickHouse in a nested cgroup, such as a typicalsystemdservice. Closes #103968. #122918 (Raúl Marín). - Fixed
NO_COMMON_TYPEforuse_variant_as_common_type = 0in the jemalloc fragmentation dashboard. #121621 (Azat Khuzhin). - Fixed
TYPE_MISMATCHbeing counted insystem.errorson every execution of aSELECTcomparing aDateTime64column against aDateTime,DateorDate32constant insideAND. A date or time constant with a part the column type cannot hold is no longer pushed down to MongoDB as a truncated bound. #121078 (Navneet Kumar). - Fixed reading
system.parts,system.parts_columnsandsystem.projection_partsfor a table whosePARTITION BYcontains amodulowith an unsigned left and a signed right operand: the query aborted withBad get: has Int128, requested UInt128 (BAD_GET)when the partition value was wider than 8 bytes, and otherwise showed a reinterpreted value thatALTER TABLE ... DROP PARTITIONrejects. The same value is rendered while a merge or mutation is scheduled, while asystem.part_logrow is written, and while a partition is pruned, so on such a table merges failed to start,part_logrows were lost, and a filtered read could abort during planning. #119333 (Groene AI). - Fix
system.server_settingsreporting the async logger queue size under the misspelled keylogger.async_queye_max_sizeinstead oflogger.async_queue_max_size. #123578 (Raúl Marín). - Fix
SELECTfromsystem.stack_tracefailing withCannot read from file /proc/<tid>/status ... No such processwhen a thread exits while the table is being scanned. #123805 (Groene AI). - Fix
system.jemalloc_sampled_allocationsand the collapsed output ofsystem.jemalloc_profile_texton sampled allocations whose backtrace jemalloc could not unwind: the allocation is now reported withtrace = []or under[unknown]instead of failing withCANNOT_PARSE_TEXTor being omitted. #123818 (Groene AI). - Fix per-protocol asynchronous metrics such as
TCPThreadsandHTTPThreadsnot being reported for listeners configured through the<protocols>section. Such a listener is now reported under the same metric as the equivalent built-in port. Metrics are also now reported for thetcp_with_proxyandtcp_sshlisteners, which previously had none. #112977 (Chester). - Fix a deadlock when an obsolete union system log table is replaced with synchronous drops. #124610 (Azat Khuzhin).
- Fixed the
max_local_read_bandwidth_for_server,max_local_write_bandwidth_for_server,max_remote_read_network_bandwidth_for_serverandmax_remote_write_network_bandwidth_for_serverrows ofsystem.server_settingsreporting the reading session’s own bandwidth limit instead of the server-wide one.getServerSettingon those names is fixed the same way. #119556 (Groene AI). - Fix tables of the
clickhouse-localdefault database becoming invisible (UNKNOWN_TABLE) when the same--pathis later used with anotherdefault_database. #123124 (Nikolay Degterinsky). - Fixed missing crash reports of
clickhouse-localwhen neitherstdinnorstderris a terminal: a fatal signal printed nothing, and--client_logs_filewas not written. #115102 (Groene AI). - Fixed
clickhouse-localhanging forever onDROP TABLE|VIEW|DATABASE ... SYNCwhen--pathis set and no metadata is loaded from it, for example a new directory on released versions or--only-system-tables. #123862 (Groene AI). - The wasm64
clickhouse localnow starts with 2 GiB of linear memory, so it no longer fails at startup withmemory access out of boundswhen Node.js races amemory.growacross worker threads. Closes #124067. #123944 (Groene AI). - Fixed
SET profilehaving no effect on subsequent queries inclickhouse-local. Profile settings such asreadonlyandjoin_use_nullsnow apply to subsequent queries again. Closes #123916. #125171 (Alexey Milovidov). - Fixed
promql_evaluation_timesilently rounding the requested instant, which could make an instant query return a different sample. The setting also now accepts an integer Unix timestamp over the native protocol, which it previously refused. #120942 (Valery Petrov). - PromQL queries with regex label matchers (
=~,!~) again work under--dialect promql. #115073 (Valery Petrov). - Allow PromQL
#and#!line comments to end at EOF without a trailing newline. #113201 (Minh Vu). - Fix PromQL duplicate-series detection to check one step at a time, so series that share tags but have values at different steps are now merged instead of failing with
Multiple series have the same tags. Binary operators check for duplicates after matching series, so unmatched series no longer cause this exception. #124086 (Vitaly Baranov). #124879 (Vitaly Baranov). - PromQL: fixed expressions over an instant vector that is known to be empty, such as
(0 < clamp(up, 1, -1)) or vector(7), which failed in range queries withNumber of values doesn't match number of stepsor returned samples at1970-01-01. #123879 (Valery Petrov). - Fixed
SELECT count()returning the whole-table row count for a streaming read (FROM ... STREAM), ignoring theCURSORbound. The implicit min-max/count projection answered the query from part metadata instead of the streaming reader. #117188 (Groene AI). - Fixed a server crash (
std::terminatewithwrite failed) in the embedded SSH client when the client’s terminal was closed before the line reader was destroyed. #120764 (Alexey Milovidov). - Fixed
Code: 1001 STD_EXCEPTION(filesystem error: ... File name too long) when a query names a table or dictionary longer than the filesystem’sNAME_MAXinclickhouse local, or in a server holding aFilesystemorURLdatabase. Such a name is now reported as missing rather than as a filesystem error. Closes #121304. #121471 (Groene AI). - A malformed argument list of an optimization of the
mergeTreeAnalyzeIndexestable function is now reported asBAD_ARGUMENTSinstead of a logical error or a rawstd::exception. #118644 (Alexey Milovidov). - Fixed
max_execution_timenot being enforced inclickhouse-localfor a query blocked inside a non-interruptible read.clickhouse-localdid not start the watchdog that turns a time limit expiry into a query cancellation, so a query reading from an unresponsives3endpoint ran to the end of the S3 retry budget (s3_retry_attemptsdefaults to 500, which takes minutes) instead of failing withTIMEOUT_EXCEEDEDat its limit. #120933 (Groene AI). - Fixed distributed queries hanging at 100% CPU on macOS when
max_threads = 1. #122905 (Raúl Marín). - Fixed a server abort on macOS when an HTTP client resets the connection during header reading. #123074 (Groene AI).
- Fixed a
LOGICAL_ERROR(Unexpected return type from materialize, a server abort in debug and sanitizer builds) when reading aBuffertable whose destination declares a column with a different but convertible type and a forwarded filter references that column: with a row policy and the implicitWHEREtoPREWHEREmove, and underquery_plan_optimize_lazy_final. The same cause made such a read fail withNOT_FOUND_COLUMN_IN_BLOCKwhen a text index on that column was read directly and the predicate appeared in bothPREWHEREandWHERE, fail withTYPE_MISMATCHover aURL(Parquet)destination, abort withBad cast from ColumnMap to ColumnArraywhen a row policy and an explicitPREWHEREboth referenced it, or fail withAMBIGUOUS_COLUMN_NAMEwhen severalPREWHEREconditions referenced the converted column. #113900 (Groene AI). #124632 (Groene AI). - Fixed
SYSTEM DROP DNS CACHEleaving entries in the DNS cache when it ran at the same time as the periodic DNS cache update. #123699 (Groene AI). - Fix
UNSUPPORTED_METHODerror for queries usingIN/NOT IN/GLOBAL INwith a subquery insideAND/ORwhenenable_function_early_short_circuitis enabled. #116037 (fhw12345). - Fixed a crash caused by a stack overflow when a deeply nested JSON document was parsed into a
JSONcolumn or passed to theJSONExtractfamily of functions. Such documents are now rejected with theTOO_DEEP_RECURSIONerror. #120887 (Pavel Kruglov). - Fixed the
LOGICAL_ERRORNot-ready Set is passed as the second argument for function 'in'for a query withORDER BY ... WITH FILL ... INTERPOLATEwhoseINTERPOLATEexpression containsINwith a subquery or a table that is not used anywhere else in the query. #124518 (Groene AI). - Fixed wrong results of a
WHEREequality betweenTuplevalues withNullableelements, or betweenVariantvalues, over a comma,CROSSorINNERjoin: the pair whose equality isNULL, such astuple(NULL) = tuple(NULL), was returned. Withallow_dynamic_type_in_join_keys = 0, a comma orCROSSjoin with aWHEREequality on aDynamicvalue no longer returns no rows or fails withILLEGAL_COLUMN. #124854 (Groene AI). - Fixed secret arguments being exposed in
system.query_logand the server log when a table function or function was called with the wrong letter case, such asS3instead ofs3,MySQLinstead ofmysql, orENCRYPTinstead ofencrypt. Such calls are still rejected. #124862 (Groene AI). - Fixed tables of a
MySQLdatabase ignoring the database’sconnection_auto_closesetting: withconnection_auto_close = 0, every read still closed its connection and the next read reconnected. A table attached again withATTACH TABLEalso lost the database’s settings.INSERTinto anyMySQLtable ignored the setting and always kept its connection; with the defaultconnection_auto_close = 1it now closes it after the query, as reads do. Closes #124749. #124884 (Groene AI). - Hide the password of a URL in
SHOW CREATE TABLE,system.tablesandsystem.query_logonly within the URL’s authority: a@in the query string no longer rewrites the shown host, and a password containing@is hidden whole. #124885 (Raúl Marín). - Fixed
mergeandMergetables over aDistributedorremotetable rejecting valid queries on a column that some of the tables lack: aggregates overDecimalandMapcolumns failed with errors such asTHERE_IS_NO_COLUMN, and an integer column of this kind inGROUP BY,ORDER BYorLIMIT BYfailed withPositional argument number 0 is out of bounds. #124976 (Groene AI). - Fixed trace samples in
system.trace_loglosing theirquery_idwhile a thread attaches to or detaches from a query, so memory profiling samples remain attributable to the query. #125176 (Groene AI). - Fixed wrong window function results in the totals row of a
WITH TOTALSquery when anarrayJoinexpands the totals into several rows: those rows were not sorted by the window’sPARTITION BY/ORDER BYkeys. #125324 (Groene AI). - Fixed primary key and skip index analysis that could skip or over-count rows for conditions on date and time functions such as
toHour,toDayOfMonth,timezoneOffsetortoTimeWithFixedDateover aNullable(DateTime)orLowCardinality(Nullable(DateTime))key whose time zone differs from the session time zone. #125327 (Groene AI). - Fixed wrong results of
ORDER BY,DISTINCT,LIMIT BYand aggregation in order over aMergetable or themergetable function when it reads anIcebergtable with a sort order: the rows came back unsorted or duplicated. #125383 (Groene AI). - Fixed
count()with aWHEREcondition on the sorting key returning too many rows on aMergeTreetable with a normal projection: rows counted from the primary key by the exact count optimization were counted again when the projection was read. Closes #125183. #125412 (Groene AI). - Fixed a possible segmentation fault when reading an
Avromapinto aMapcolumn (for exampleMap(DateTime, String)) with theAvroConfluentformat, includingKafkatables. Closes #125457. #125505 (Groene AI). - Fix a server crash on
CREATE DICTIONARYwithout aSOURCEclause whenrestore_replace_external_dictionary_source_to_nullis enabled. Such a query now fails withINCORRECT_DICTIONARY_DEFINITION, as it does with the setting disabled. With the same setting, a localCLICKHOUSEsource that uses a constant function such asDB currentDatabase()is no longer rejected. #125659 (Groene AI). - Fixed the
ArrowandArrowStreaminput formats rejecting valid dictionary-encoded columns whose dictionary contains repeated values. Closes #125139. #125677 (Jay Pokale). - Fixed the Arrow Flight interface writing the text of each query, including secrets such as
IDENTIFIED BYpasswords and storage keys, to the server log andsystem.text_log. The gRPC interface did the same for the first 64 characters of each query. Now queries from these interfaces are logged only with their secrets hidden. #125716 (Groene AI). - Fix a server crash on macOS where an idle thread pool worker aborted with
condition_variable wait failed: Invalid argument. TheEINVALthat Darwin’spthread_cond_waitreturns when the kernel fails the wait is now treated as a spurious wakeup. Closes #84761. #125721 (Groene AI).
Build/Testing/Packaging Improvement
- Harden official builds by compiling with
-fstack-protector-strongand-fstack-clash-protection, and by linking with-Wl,-z,separate-code. #119039 (Raúl Marín). #123073 (Raúl Marín). - The musl build of ClickHouse is now a static position-independent executable, so it gets address space layout randomization like the glibc build. #125669 (Raúl Marín).
- Added an optional packaging mode
SYMBOL_SECTIONS=gnu_debugdatathat replaces.symtaband.strtabin release binaries with compressed.gnu_debugdata(MiniDebugInfo), reducing symbol data from about 148 MiB to about 10 MiB in the official build. Stack traces and symbol access from gdb, lldb, elfutils, and perf remain available. #115322 (Andrew Grigorev). - Update
cctzto 2026d. Time zone names with thefile:prefix are now rejected. #121325 (Actuele AI). Updatecctzto 2026e:America/Winnipeg,America/Rainy_River, andCanada/Centralnow stay at UTC−5 from 2026-11-01, reflecting Manitoba’s removal of the DST fall-back. #124249 (Actuele AI). - Update
OpenSSLto 3.5.9. #124278 (Actuele AI). - Update
aws-sdk-cppto 1.11.907, the AWS CRT libraries to 0.43.8, andaws-c-commonto 1.0.2. #125080 (Groene AI). - The
delta-kernel-rslibrary no longer carries its own copy of OpenSSL, so the binary always links the OpenSSL built fromcontrib/opensslwith the current build flags instead of an older copy kept by the Rust build cache. #123889 (Groene AI). - Rust crates are now built in parallel with each other and with the C++ code, which reduces the build time. #124645 (Antonio Andelic).
- Builds of the experimental GPU engine are faster:
nvcccompilations are now cached withccache, and unused PTX plus CUDA line info are no longer generated. #120421 (Konstantin Vedernikov). - Fixed building with
-DNO_ARMV81_OR_HIGHER=1on AArch64: the compatibility profile no longer disablesNEONfor Rust, soring-based components (chdig,delta-kernel-rs) compile and stay enabled. This unblocks building for ARMv8.2-A CPUs that lackrcpc, such as HiSilicon Kunpeng 920. #107440 (Tiaonmmn). - Compile code linked into the position-independent
clickhouseexecutable with-fPIEinstead of-fPIC, avoiding unnecessary symbol indirection. Apply the flag to the C++ runtime libraries fromcontribtoo, so builds with compilers that do not default to PIE link successfully, including Fedora’sclangonaarch64andx86_64. #125094 (oleg-milanov). #125488 (Groene AI). - Allow building with XRay instrumentation under musl. #118914 (Konstantin Bogdanov).
- Fixed a missing CMake link dependency that could make
src/Functions/array/distanceTransposed.cppfail withsimsimd/simsimd.h file not foundon a from-scratch build. #120504 (Craig Ringer). - Reduce linker warnings in Rust/wasm builds: remove
--icf=safewarnings aboutSHT_LLVM_ADDRSIGin the stripped Rust libraries, and apply the__jit_debug_register_codeworkaround only to theclickhousebinary and only whenwasmtimeis linked. #122904 (Raúl Marín). #123287 (Azat Khuzhin). - Update
google-protobufto v36.1.google-cloud-cppprotobuf sources are now regenerated whenprotocchanges, so incremental builds do not fail after such an update. #118926 (Actuele AI). #123603 (Alexey Milovidov). - Update
rocksdbto v11.8.1. #118929 (Actuele AI). - Update
abseil-cppto 20260817.0. #118897 (Actuele AI). - Update
PostgreSQLto 18.6. #124281 (Actuele AI). - Update
thriftto v0.25.0. #124280 (Actuele AI). - Update
cppkafkato v0.4.1. #119468 (Actuele AI). - Update
h3to v4.5.0. #119328 (Actuele AI). - Update
flatbuffersto v25.12.19. #119100 (Actuele AI). - Update
croaringto v5.2.2. #119464 (Actuele AI). - Update
simdutfto v9.1.1. #119324 (Actuele AI). - Update
double-conversionto v3.4.0. #119095 (Actuele AI). - Update
libcpuidto v0.8.2. #121382 (Actuele AI). - Update
liburingto 2.15. #118895 (Actuele AI). - Update
libuvto v1.52.1. #119099 (Actuele AI). - Update
libcotpto v4.2.2. #122000 (Actuele AI). - Update
vectorscanto 5.4.13. #125774 (Actuele AI). - Update
snappyto 1.2.2. #119325 (Actuele AI). - Update
brotlito v1.2.0. #119096 (Actuele AI). - Update
libdeflateto v1.26. #119349 (Actuele AI). - Update
xxHashto v0.8.4. #124231 (Actuele AI). - Update
google-benchmarkto v1.9.5. #118893 (Actuele AI). MemoryWorkernow correctsMemoryTrackerusing allocated memory from ASan, TSan, and MSan instead of resident memory in sanitizer builds when cgroups are available. #119956 (Konstantin Morozov).- Add support for cross-compiling ClickHouse for illumos. Closes #23777. #125073 (Alexey Milovidov).
ClickHouse release 26.9, 2026-09-21. Presentation, Video
Backward Incompatible Change
- The analyzer can no longer be disabled: the
enable_analyzersetting (and its old nameallow_experimental_analyzer) is obsolete, an attempt to set it to0is rejected, and thecompatibilitysetting no longer reverts it. The analyzer has been the default since 24.3, and the query analysis used before it is no longer supported. To compare the behaviour or the performance of a query with the old query analysis, use a ClickHouse version older than 26.9. #118629 (Alexey Milovidov). - The default compression method is changed from
LZ4toZSTD(3). Client/server and server/server network communication switches toZSTD(3)uniformly. ForMergeTreecolumn data the built-in default is now size-aware:LZ4for parts below 100 MB andZSTD(3)at or above it, judged by the part size known at write time (the size of the source parts for a merge or a mutation). TheStripeLogdata stream, the persistent files of theSetandJoinengines, andMergeTreeauxiliary files such aschecksums.txtswitch toZSTD(3)uniformly. HTTPcompress=1now uses thenetwork_compression_methodsetting too; the default is stillZSTD(3), andcompatibilityset to26.8or earlier restoresLZ4over HTTP as well. This improves compression ratios and reduces storage and network usage out of the box, at a modest increase in CPU usage. To restore the previous behavior: for network compression, use thecompatibilitysetting or setnetwork_compression_method = 'LZ4'; forMergeTreecolumn data, setCODEC(LZ4)on the column or table, or set the server<compression>default toLZ4; for theLogandTinyLogengines, set a columnCODEC(LZ4). The remaining streams always use the built-in default and have no runtime rollback; reading stays correct because every compressed frame is self-describing. #108786 (Alexey Milovidov). #119825 (Alexey Milovidov). This change is backward compatible, it is listed here for your convenience. - Removed the CatBoost integration. The
catboostEvaluatefunction, thesystem.modelstable and theSYSTEM RELOAD MODEL(S)queries are no longer available. Queries, views and grants referring to them have to be migrated before the upgrade: in particular, revokeSYSTEM RELOAD MODELfrom all users and roles beforehand, because an access entity whose grants still mention the removed privilege cannot be parsed on startup. Also let any in-flightSYSTEM RELOAD MODEL(S) ON CLUSTERentries drain from the distributed DDL queue before the upgrade: upgraded hosts can no longer parse such entries and will finish them with an error status instead of executing them. The same applies to persisted table metadata: a table whose columnDEFAULT/MATERIALIZED/ALIASexpressions, secondary indices, constraints, projections, partition/order/sample keys, or TTL expressions still referencecatboostEvaluatecannot be loaded after the upgrade (UNKNOWN_FUNCTION), so drop or rewrite such definitions beforehand. The revoke also has to cover every other carrier of serialized grants: aGRANT SYSTEM RELOAD MODELline in thegrantssection ofusers.xmlmust be removed as well, because it can no longer be parsed and the server then refuses to load the users configuration at startup; on clusters with replicated (Keeper-backed) access storage, revoke the privilege before upgrading any replica, because with the defaultaccess_control_improvements.throw_on_invalid_replicated_access_entities = 0an upgraded replica that reads a user or role still carryingSYSTEM RELOAD MODELfrom ZooKeeper cannot parse it and silently drops that entity from its in-memory copy (setthrow_on_invalid_replicated_access_entities = 1to fail loudly instead); and access backups (BACKUP ... ACCESS) taken while the grant was still present cannot be restored withRESTORE ... ACCESSon the new version, so re-create such backups after the revoke. #109710 (Robert Schulze). #116586 (Alexey Milovidov). - Removed the deprecated
read_resourceandwrite_resourcedisk options fromstorage_configuration. Attach a scheduler resource to a disk withCREATE RESOURCE name (READ DISK disk, WRITE DISK disk)instead. #115286 (Sergei Trifonov). - Removed the
WasmEdgeengine for WebAssembly UDFs.wasmtime, which has always been the default, is now the only supported value of thewebassembly_udf_engineserver setting. A server configured withwebassembly_udf_engine = 'wasmedge'will not start; remove that setting or set it towasmtime. On binaries wherewasmtimeis unavailable, including MemorySanitizer,arm_v80compat, andriscv64, WebAssembly UDFs are not available at all: the server still starts, butsystem.webassembly_modulesis absent and any attempt to create or use a WebAssembly UDF fails withSUPPORT_IS_DISABLED. #115316 (Alexey Milovidov). - The experimental
WINDOW VIEWfeature is removed, together with theWATCHstatement and thewindowIDfunction. It has been non-functional since version 24.12 (inserts into the source table were silently not delivered to window views) and was never supported by the analyzer, which is enabled by default since 24.3. The settingsallow_experimental_window_view,window_view_clean_interval,window_view_heartbeat_interval, andwait_for_window_view_fire_signal_timeoutare kept as obsolete no-ops. The time-window functionstumble,tumbleStart,tumbleEnd,hop,hopStart, andhopEndare kept. If you still have window views defined, drop them before upgrading: a server that finds a window view in its metadata fails to start (Cannot parse definition from metadata file ... (SYNTAX_ERROR)), the same way the removal of theLazydatabase engine behaves. Similar functionality will be reimplemented on top of streaming queries (issue #114738). #114747 (Alexey Milovidov). - Removed the sharded
GROUP BYaggregation (enable_sharding_aggregator, disabled by default) in favor of the adaptive aggregation (enable_adaptive_aggregator, enabled by default), which targets the same high-cardinality workloads without the weaknesses on skewed or low-cardinality keys and with support for external aggregation. Theenable_sharding_aggregatorsetting is kept as obsolete: setting it is still accepted and has no effect. #116532 (Nihal Z. Miaji). - Fixed wrong results from
runningConcurrencyunderLEFT JOINandANY JOIN, and under lazy evaluation inif,multiIf,and, andor, by treating it as non-deterministic. Queries using it may be slower. A sorting key, partition key, or text indexpreprocessor/postprocessorcontainingrunningConcurrencyis now rejected, and a table created earlier with one will not load after upgrading: remove or replace it before the upgrade. #114403 (Groene AI). BACKUP ... TO Disk(...),RESTORE ... FROM Disk(...), andCREATE DATABASE ... ENGINE = Backup(..., Disk(...))now requireSOURCESgrants for the targetDisk(...)location:WRITE ON DISKto write andREAD ON DISKto read. Previously a user withBACKUPbut withoutSOURCEScould still use any disk listed inbackups.allowed_disk; such users now need the correspondingDISKgrant, while users already grantedSOURCESare unaffected. #117406 (Groene AI).- Compression codecs are now gated by dedicated per-codec settings whose declared tier defines the codec maturity. The
ALPcodec is promoted to beta throughenable_alp_codec, andallow_experimental_codecsis now obsolete: it no longer enables any codec, so use the per-codecenable_<codec_name>_codecsettings instead. #116337 (Raufs Dunamalijevs). #117545 (Raufs Dunamalijevs). - Reading a
Filesource withrename_files_after_processingset now requires theWRITE ON FILEgrant on top ofREAD ON FILE(on the initiator forfileCluster): the setting renames the files aSELECThas read, which is a write to the source, and it used to happen for anyone who could read them. A query relying on it now needsGRANT WRITE ON FILE. A per-query renaming rule is also no longer cached by aFilesystemdatabase, where it could make an unrelated later query rename files, or be dropped silently. #117895 (Groene AI). - The
interfaceandhttp_methodcolumns ofsystem.query_log,system.query_thread_logandsystem.processesare nowEnum8instead ofUInt8, over the value setsystem.session_log.interfacealready uses, plusUnknownfor an unrecognized interface. Comparing to a number keeps working (WHERE interface = 1) and comparing to a name now works too (WHERE interface = 'TCP'), but a plainSELECTrenders the name, and arithmetic on the column (interface + 0) is no longer accepted. The default-enabledsystem.user_query_logand the opt-inall_union tables copy these types. As with any system log schema change, the existing log tables are renamed with the first free suffix (query_log_0,query_log_1, …) on upgrade; their rows read as names afterALTER TABLE system.query_log_0 MODIFY COLUMN interface Enum8(...), and the same forhttp_method, preceded byMODIFY SETTING table_readonly = 0if that table was frozen. #118136 (Groene AI). CREATE TABLE ... AS mergeTreeIndex(...)is no longer accepted, nor the same form overmergeTreeProjection,mergeTreeAnalyzeIndexes,mergeTreeAnalyzeIndexesUUID,mergeTreeTextIndexandmergeTreeCodecBlockCounts. The storage these functions return holds its source table’s storage object, so once such a persisted table had been read,DROP TABLE <source> SYNCnever returned, the source stayed insystem.dropped_tablesforever and its data was never reclaimed from disk. Reading these functions directly, as inSELECT ... FROM mergeTreeIndex(...), is unaffected. An existing table of this shape keeps loading at server startup, butATTACH TABLE,RESTOREandReplicateddatabase replica recovery now refuse it: list them withSELECT database, name FROM system.tables WHERE engine = 'Proxy', drop the ones over these six functions, and read the functions directly instead. #118969 (Groene AI).CREATE TABLE ... AS timeSeriesSamples(...)is no longer accepted, nor the same form overtimeSeriesData,timeSeriesTags, ortimeSeriesMetrics. Reading those functions directly is unaffected. Existing tables of this shape still load at server startup, butATTACH TABLE,RESTORE, andReplicatedreplica recovery now refuse them, because once such a persisted proxy table had been read,DROP TABLE <ts>dropped its live target and destroyed its rows, and later reads could fail withQueryPlan was not initialized. Find candidates withSELECT database, name, create_table_query FROM system.tables WHERE engine = 'Proxy'and keep only the ones whose outer call is one of these four functions; aview(...)wrapper is still allowed. Drop such a table on a freshly started server, before anything reads it, so the drop removes only the proxy and leaves theTimeSeriesdata intact. Do not useDETACH TABLEinstead, because a detached definition can no longer beATTACHed. If metadata loading of such a table already fails after a restart, move the metadata file out ofstore/and restart: until then, unfiltered reads ofsystem.tablescan fail withASYNC_LOAD_WAIT_FAILED. #119786 (Groene AI).- Removed the
s3_disable_checksumsetting. It existed to skip a second read of the source data for the checksum of an S3 upload; the checksum is now computed during the single read, so there is nothing left to disable. #119496 (Azat Khuzhin). Nullable(Tuple(...))is now generally available and enabled by default.Nullable(Tuple(...))columns can be created without any setting, schema inference of nullable structs in theParquet,Arrow,ORC,AvroandJSONformats returnsNullable(Tuple(...)), and aTuplesubcolumn extracted from aVariant,Dynamic,JSONorNullable(Tuple)column isNullable(Tuple(...))andNULLwhere the value is missing, instead of a tuple of default values. The previous behavior is available withenable_nullable_tuple_type = 0andallow_nullable_tuple_in_extracted_subcolumns = 0; the subcolumn setting is read at server startup, so it has to be set in the default profile. Upgrading existing tables whose partition keys, sorting keys, TTL expressions, or skip indexes depend on a tuple subcolumn extracted from aDynamic,VariantorNullable(Tuple)column or from aJSONpath not declared asTuple(...)is unsafe with the new default: tables may fail to attach, queries may fail, or data parts may be detached during startup. Before the first startup after upgrading, setallow_nullable_tuple_in_extracted_subcolumns = 0in the default profile, or preserve the previous behavior throughcompatibilityin that profile. Changing the setting after parts have been detached does not restore them automatically; those parts must also be reattached. #119222 (Nihal Z. Miaji).- New setting
validate_group_by_all_key_types(defaulttrue) gates the key-type validation thatGROUP BY ALLapplies to the grouping keys it expands theSELECTexpressions into. Since 26.7 it rejects aVariantorDynamicgrouping key, for example an untyped JSON subpath, that earlier versions accepted with the analyzer enabled (the default), with no way to keep such a query running across an upgrade. Settingcompatibilityto a version before 26.7, orvalidate_group_by_all_key_types = 0, restores the earlier behavior. An explicitGROUP BYis unaffected and still rejects such a key, as it did before 26.7. Closes #119852. #119868 (Groene AI).
New Feature
DISTINCTcan now spill data to disk, like external aggregation and external sort: the new settingsmax_bytes_before_external_distinctandmax_bytes_ratio_before_external_distinctset the threshold; by default, spilling starts once query memory usage exceeds half the available memory under the applicable server or user memory limits, or as soon as the next hash table allocation would exceed it. #116569 (Nihal Z. Miaji).- Refreshable materialized views can now refresh incrementally with
REFRESH ... APPEND INCREMENTAL, appending only the rows committed to the source table since the previous refresh instead of re-reading the whole source. #114152 (Smita Kulkarni). An incremental refresh into anIcebergtarget is now exactly-once: the refresh cursor is committed atomically inside theIcebergsnapshot summary. #114823 (Smita Kulkarni). - New
LIMITforms that select rows by boundary conditions instead of by position, following the stream order (useORDER BYto define it):LIMIT n AFTER condreturns up tonrows starting at the first row wherecondis true (SELECT number FROM numbers(10) ORDER BY number LIMIT 3 AFTER number >= 5returns5, 6, 7);LIMIT UNTIL condreturns the rows before the first row wherecondis true (LIMIT UNTIL number >= 3returns0, 1, 2);LIMIT AFTER cond1 UNTIL cond2returns the rows between the two (LIMIT AFTER number >= 2 UNTIL number >= 6returns2, 3, 4, 5);LIMIT n AFTER cond ALLopens a range ofnrows at every matching row and returns their union without duplicates (LIMIT 2 AFTER number IN (2, 6) ALLreturns2, 3, 6, 7). #99508 (Zakhar Kravchuk). - Added the
CREATE TOKENstatement, which generates a random secret, adds it to the current user as an additional authentication method and returns it together with its expiration deadline:CREATE TOKEN VALID FOR INTERVAL 30 DAY GRANTS (SELECT ON db.table). It is a convenient way to create tokens for applications: a token is tied to the user, can be limited in time and in privileges, and stops working when the user is deleted. Without an explicitVALID UNTILorVALID FORclause a token lives forcreate_token_default_ttl_seconds, 30 minutes by default. The statement requires the newCREATE TOKENprivilege, which also authorizes the equivalentALTER USER <current user> ADD IDENTIFIED ...statement. #116957 (Alexey Milovidov). - Authentication methods in
CREATE USERandALTER USER ... ADD IDENTIFIEDsupport aGRANTS (SELECT ON db.table, ...)clause which limits the access rights of sessions authenticated with that method to the intersection with the listed grants. This allows using additional credentials as tokens for applications:ALTER USER vasya ADD IDENTIFIED WITH password BY '...' VALID UNTIL '2026-12-31' GRANTS (SELECT ON db.table). Closes #109117. #110144 (Alexey Milovidov). - Added the SQL standard linear regression aggregate functions
regr_slope,regr_intercept,regr_r2,regr_count,regr_avgx,regr_avgy,regr_sxx,regr_syyandregr_sxy. #119347 (mosya415). - Added
MergeTreesettingsmax_table_size_rows,max_table_size_bytes_compressed, andmax_table_size_bytes_uncompressed, which limit the total size of a table. The limits are checked at the start ofINSERTand when new parts are committed, including the results of background merges and mutations, but not on replicated fetches. Closes #115063. #115069 (Alexey Milovidov). - Added the
max_tablesdatabase setting to limit the number of tables inAtomicandOrdinarydatabases. Every table-like object counts toward the limit, including tables, views, and dictionaries. #115202 (Alexey Milovidov). - Added bracket syntax for
JSONsubcolumns, such asjson['key1']['key2']; the parser translates it to nestedarrayElementcalls. #107039 (Pavel Kruglov). - Added the
system.statementssystem table, which exposes the documentation of SQL statements such as their name, syntax, description, and examples. #115341 (Robert Schulze). - Added virtual columns for the
Icebergv3 manifest fieldsfirst_row_idandlast_seq_num. #115603 (Konstantin Vedernikov). The same fields are now also written when inserting into anIcebergv3 table. #116171 (Konstantin Vedernikov). - Added the opt-in
MergeTreesettingskip_empty_columns_on_insert, which avoids storing columns that contain only their type-default value. It requiresserialization_info_version = 'with_missing_columns'; during rolling upgrades with servers that cannot read the new part metadata, keep the older serialization version. #98472 (Amos Bird). - Added support for
+and-betweenDateTimeandTimedata types. #82980 (Yarik Briukhovetskyi). - Added the
parseISO8601Durationfunction, which parses ISO 8601 duration strings such asPT1H30Minto seconds. #116993 (Navneet Kumar). - Added the
type_json_skip_null_typed_pathssetting forJSON. When it is enabled, typed paths inJSONcolumns that haveNULLvalues are treated as absent, matching the behavior of dynamic paths. Closes #99191. #106959 (Pavel Kruglov). - Added the
arrayFlattenedLengthfunction, which returns the total number of elements in a multidimensional array as if it was flattened witharrayFlatten. Unlikecardinalityandlength, which count only the elements of the outermost array, it counts elements at every nesting level, matching PostgreSQL’scardinality. #113696 (David Meng). clickhouse-clientnow accepts--ssh-key-filewithout a value: the key is looked up the same way assshdoes it, from~/.ssh/config, the default identity files such as~/.ssh/id_ed25519, and the keys held byssh-agent. Authentication with a key held byssh-agentis now supported without passing its path or passphrase explicitly. #115072 (Alexey Milovidov).- The
splitByRegexptokenizer, used in text indexes and thetokensfunction, now accepts an optionalextractargument. WithsplitByRegexp(re, 1),reno longer acts as a separator: each match contributes at most one token, the first capture group of the match or the whole match ifrehas no capture group. #116127 (Jimmy Aguilar Mena). - Added the
system.session_query_idssystem table, which contains the query ids of the queries executed in the current session, in execution order. It makes it easy to find “the queries I just ran” insystem.query_logwithout assigningquery_idclient-side or tagging queries withlog_comment, which is especially useful for testing and benchmarking. The history size is bounded per session by the newsession_query_ids_history_sizesetting (default1000,0disables recording), andTRUNCATE TABLE system.session_query_idsclears the current session’s history. #110536 (Vladimir Cherkasov). - Added a zero-argument form of
yearthat returns the current year, mirroringnowandtoday:year()is equivalent totoYear(today()).yearis now a function in its own right rather than a case-insensitive alias oftoYear, and is reported non-deterministic, soyear(<date>)is excluded from features that require a deterministic function: the query result cache, mutations ofReplicated*tables, on-the-fly mutation application (apply_mutations_on_fly), mutation partition pruning, and the trivial-view pushdown toDistributedtables; usetoYear(<date>)where determinism is required. Results, result types, index analysis and projection selection foryear(<date>)are unchanged. #109097 (Groene AI). - Added a memory fragmentation profiler for jemalloc. The new
system.jemalloc_sampled_allocationstable lists the sampled allocations that are currently alive, with their backtrace, age and size class; together withsystem.jemalloc_arena_binsit shows which code holds the allocations that keep fragmented slabs alive, and the same data is shown in a new “Fragmentation” tab of the jemalloc page of the server’s web UI. #115456 (Azat Khuzhin). - Support
BACKUPandRESTOREforWORKLOADandRESOURCEentities. SQL-definedCREATE WORKLOADandCREATE RESOURCEdefinitions are now included when backing upsystem.workloadsandsystem.resourcesand are recreated on restore, includingON CLUSTER. #108431 (Sergei Trifonov). - Added the
workload_admission_timeout_msquery setting that bounds how long a query waits to acquire its workload query slot and memory reservation before failing.0(the default) keeps the previous unbounded wait. #118852 (Sergei Trifonov). - Added
mode = 'exclusive'to theS3Queueengine: file processing is tracked only in the memory of the server, with no coordination through Keeper, for high-throughput ingestion on a single server, such as from a localminioinstance. #110552 (Ivan Tkatchev). - Added the
nats_ca_file,nats_client_cert_fileandnats_client_key_filesettings to theNATSengine, for verifying a broker certificate signed by a private CA and for client-certificate authentication. The feature was first proposed in #69396 by sidhmads. #116117 (Nikolay Degterinsky). - Added a four-letter-word command to
clickhouse-keeperfor the backpressure that the leader applies to slow Raft members. #117728 (Kseniia Sumarokova). - Added the
keyValuePairstext index tokenizer, which indexes aMap(String, String)column directly and answersmap['key'] = 'value'from the index without reading the map column. #115579 (Jimmy Aguilar Mena).
Experimental Feature
- Added Prometheus HTTP API support for the
/api/v1/metadata,/api/v1/labels, and/api/v1/label/<name>/valuesendpoints onTimeSeriestables. The/api/v1/labelsendpoint returns the sorted unique label names of the matched time series, and/api/v1/label/<name>/valuesreturns the sorted unique values of one label; both support the optionalmatch[],start,end, andlimitparameters. #116518 (Nikita Mikhaylov). #116731 (Nikita Mikhaylov). #117160 (Nikita Mikhaylov). - Added the
/api/v1/format_queryendpoint of the Prometheus HTTP API. It parses a PromQL expression and returns its canonical form. #117159 (Nikita Mikhaylov). - Added an embedded SQL Console UI at
/uion the HTTP server. This is the same console that is available in ClickHouse Cloud - not to be confused with the Web UI. #100406 (Luis Neves). - Reimplemented the experimental
KQL(Kusto) dialect with a dedicated lexer and parser instead of translating it to SQL text and reparsing it. This fixes expression-injection in string operators such ascontainsandhas, several results that disagreed with Kusto such as7 / 2,substringwith a negative start, andbin, and functions that were registered but did nothing. Unsupported syntax is now rejected instead of being mistranslated. #112932 (Alexey Milovidov). - Added an experimental
trinovalue of thedialectsetting (gated byenable_trino_dialect): queries written in Trino SQL are translated to ClickHouse SQL, including Trino-specific syntax (ARRAY[...]literals,TRY_CAST,UNNEST,ROWconstructors and types,VALUEStables,OFFSETbeforeLIMIT,FETCH) and a mapping of several hundred Trino function names and argument conventions to their ClickHouse equivalents. Bitwise shifts over untyped integer literals now match Trino semantics. #115383 (Alexey Milovidov). #119430 (Ethan Lin). - Added the
hierarchicalKMeansandassignCentroidfunctions, building blocks for IVF-style vector search. #112309 (Shankar Iyer). - Added
SELECTsupport forTimeSeriestables. #115622 (Vitaly Baranov). TimeSeriestables now derive their inner engine family fromdefault_table_engine, require all inner tables to use the same replication family, and always pinrecent_samples_ttl_secondsintoSETTINGSforRECENT SAMPLEStargets. #115922 (Vitaly Baranov).- Added PromQL support for
absentandcount_values, including range queries andby/withoutaggregation modifiers. #112795 (Valery Petrov). - PromQL now supports the range functions
sum_over_time,avg_over_time,count_over_time,present_over_time,absent_over_time,quantile_over_time, andpredict_linear. #112353 (Valery Petrov). #112842 (Valery Petrov). - The
TimeSeriestable engine now supports dictionary-encoded series identifiers: theidcolumn can be declared with aLowCardinalitytype, and new tables useTuple(UInt64, LowCardinality(UUID))by default while existing tables keep their declaredidtype. The previous layout remains available throughTAGS INNER COLUMNS (id Tuple(UInt64, UUID)), and the new layout gives a 1.16x geometric-mean PromQL speedup in the benchmark. #117033 (Nikita Mikhaylov). timeSeriesGroupArrayis now supported inSimpleAggregateFunction, and thetimeSeries*ToGridfunctions now also accept the samples as a singleArray(Tuple(timestamp, value))argument. #117340 (Vitaly Baranov). #117341 (Vitaly Baranov).TimeSeriestables now expose the outer samples column assamplesinstead oftime_series.INSERT INTO ts_new SELECT * FROM ts_oldstill works because the column order is unchanged. #119225 (Vitaly Baranov). TheMETRICStarget is renamed toMETRIC FAMILIES, which is what that inner table actually holds;METRICSkeeps working as an alias. #119227 (Vitaly Baranov).- Distributed query plans (
make_distributed_plan) now stop idle upstream stages promptly after a satisfiedLIMIT, instead of continuing to read and compute data that nobody consumes. They also no longer stall when the initiator pipeline has only one execution thread, because waiting for distributed plan stages no longer occupies that thread. Plans with many nodes now honor the query’smax_threadsin worker fragments, so they no longer exhaust the server thread pool or outlivemax_execution_time;use_concurrency_controlis disabled automatically for these queries because it can starve worker tasks while they wait on exchange sockets. Plans with many finished stages also no longer pay up to 100 ms of idle waiting per stage while draining completed stages, which speeds up multi-join queries several times in some cases. The data sent between nodes is now also serialized on all threads of a task instead of one thread per destination, removing a bottleneck when a query runs on a small number of workers. #115690 (Alexander Gololobov). #116017 (Alexey Milovidov). #116300 (Groene AI). #116878 (Alexander Gololobov). #117328 (Alexander Gololobov). #119067 (Alexander Gololobov). parallel_replicas_plan_basedcan now collect runtime statistics and automatically enable parallel replicas for supported queries. #115788 (Igor Nikonov).- A
Mergetable can now be read with parallel replicas: reads from the underlyingMergeTreetables are coordinated across replicas, and aggregations and joins above them are distributed too. Enabled by theparallel_replicas_allow_merge_tablessetting together withparallel_replicas_plan_based. #115001 (Igor Nikonov). - Added experimental support for the
silkfiber runtime, enabled with theenable_silk_runtimeserver setting. When it is enabled, subsystems that support it can run jobs on fibers instead of occupying an operating-system thread while waiting for I/O. #112667 (Miсhael Stetsyuk). - Adaptive codec selection (
enable_adaptive_codec_selection) forMergeTreenow also applies to columns without a specialized candidate codec: when no type-specific codec candidate exists, each block is written with whichever of the table’s default codec andNONEcompresses it smaller, so incompressible data is no longer stored larger than raw. ForFloat32andFloat64columns it now also considers theALPcodec. #115639 (Raufs Dunamalijevs). #117553 (Raufs Dunamalijevs). - Added aggregation pushdown below
JOIN(eager aggregation) to the experimental Cascades optimizer as a cost-based alternative: a partial aggregation is performed on one join input before the join and merged above it, or, when the join provably neither duplicates nor null-extends the aggregated side and the join keys are a subset of theGROUP BYkeys, the aggregation is pushed below the join entirely. Controlled by the new settingcascades_aggregation_pushdown(enabled by default; takes effect only withenable_cascades_optimizer = 1andmake_distributed_plan = 1). #115354 (Dmitry Novik). - Queries with
INTERSECTandEXCEPTnow work under the experimentalmake_distributed_plansetting. #116563 (Alexander Gololobov). Whenmake_distributed_planis enabled and no distributed plan can be built, the query falls back to local execution. #116487 (Antonio Filipovic). A failingmake_distributed_plan = 1query reports the error of the task that failed, not the closed exchange connection that failure caused; worker task failures reach the client with the worker’s error code. #118390 (Groene AI). - Fixed
Column '__text_index_...' not found in tableandQuery builder not found for text search querywhen a query using a text index read withparallel_replicas_plan_basedenabled. #116363 (Igor Nikonov). parallel_replicas_plan_basednow supportsRIGHT JOINandORDER BY ... WITH FILL; when the analyzer is disabled, the query runs locally instead of falling back to query-based parallel replicas, because plan-based parallel replicas are not supported there. #113515 (Groene AI). #116135 (Igor Nikonov). #118781 (Igor Nikonov).- Adaptive codec selection (
enable_adaptive_codec_selection) now applies to every substream of a column, such asArrayandStringsizes and null maps, instead of the main data stream only. #117348 (Raufs Dunamalijevs). - WebAssembly UDFs now split an input block that would not fit into the guest’s linear memory into smaller batches, sized by the input’s measured serialized size. The new setting
webassembly_udf_input_split_memory_ratiocontrols how much of the linear memory one call’s input may occupy. #116552 (Vasily Chekalkin). A UDF using theBUFFERED_V1ABI that returns a result buffer with a non-zero size but a data pointer at linear-memory offset0is now rejected instead of unrelated memory being read. #116548 (Vasily Chekalkin). - The experimental
ReaderExecutornow shrinks its read window and block size under memory pressure, configured viareader_executor_memory_pressure_{elevated,high,critical}_level_pct; its default read window is now 8 MiB. #115635 (Sema Checherinda). - PromQL: implemented the
max_over_timeandmin_over_timefunctions. #112354 (Valery Petrov). PromQL now also parses legacy octal numeric literals with Prometheus-compatible semantics. #113586 (Minh Vu).sgnnow preservesNaNand negative zero. #113747 (Minh Vu).stddevandstdvarno longer returnNaNfor large finite values whose variance is representable. #114250 (Minh Vu). - PromQL no longer counts consecutive
NaNsamples as changes. #113744 (Minh Vu). CREATE TABLE ... ENGINE = DeltaLake(...)can now create a newDeltaLaketable, writing the initial commit throughdelta-kernel-rs, attach to an existing_delta_log, or register an existing table into a Unity catalog. It is gated behind the newallow_delta_lake_create_tablesetting; creating a partitioned table (PARTITION BY) is not supported yet. Writes to aDeltaLaketable now cast values to the Delta write-schema type with an accurate cast that throws when a value does not fit the target type, for example300written into a Deltabyte, instead of silently truncating; the newdelta_lake_accurate_write_castsetting, enabled by default, controls this, andcompatibilitybelow26.9restores the previous truncating behavior. #106011 (Smita Kulkarni).
Performance Improvement
- Reduced memory usage and query-plan optimization time for keyed aggregations over large constant-folded literals by hashing the aggregation hash-table-statistics cache key while it is serialized instead of accumulating a full copy in memory first. For an 80 MB literal, peak memory drops by about 250 MB and optimization time by about 2.5x. #115847 (Groene AI).
- Added the
query_plan_aggregation_bucket_top_ksetting (enabled by default) to control the optimization that keeps only each two-level aggregation bucket’s bestngroups when a final aggregation feedsORDER BY ... LIMIT n. The optimization is now visible inEXPLAINoutput. #116124 (Nihal Z. Miaji). - A
WHEREequality is now merged into theJOINcondition even when its operands have different types but a common supertype, such asInt32andNullable(Int32). This lets moreCROSS JOINs be rewritten toINNER JOINs. #112630 (Hechem Selmi). - Improved performance of merges of text indexes. #114525 (Anton Popov).
- Reduce CPU usage of the post-filter used by
INandNOT INpredicates. #111690 (Elmi Ahmadov). - The
arrayJoinfunction syntax is now planned as theARRAY JOINoperator internally, so it can use the sameARRAY JOINoptimizations. A filter on a column produced byARRAY JOINis pushed into the array before it is expanded, so elements that do not match are never turned into rows and other columns are not replicated for them, which speeds up selectiveARRAY JOIN ... WHEREqueries over wide rows. A follow-up reduces the fused path’s per-block overhead by avoiding per-window filter copies and computing survivor offsets only when eager replication needs them. Controlled by thequery_plan_fuse_filter_into_array_joinsetting. #115474 (Yarik Briukhovetskyi). #116910 (Yarik Briukhovetskyi). #117660 (Yarik Briukhovetskyi). - Fixed a performance regression where a query combining a text index filter with
ORDER BY ... LIMITstopped answering the filter from the index and read the whole text column instead. #115586 (Jimmy Aguilar Mena). - Speed up query pipeline construction for queries with large expressions or many streams by computing each plan step’s output header once instead of once per stream. For a ClickBench Q29-like query on a 96-core machine, this removes about a third of the hot query time. #115677 (Alexey Milovidov).
- Speed up building the hash table of an
ANY,SEMI, orANTI JOINwhen the right side repeats the same join keys many times. #115820 (Nikita Taranov). - Speed up random data generation.
rand,rand64,randConstant,randomString,randomFixedString,generateUUIDv4,generateUUIDv7, anddateTimeToUUIDv7now generate bytes with ARS (reduced-round AES in counter mode) wherever the CPU has AES instructions: on AArch64 chosen at build time, on x86-64 chosen at run time when VAES is present. Targets and CPUs without those instructions keep the previous generator unchanged. A follow-up reduced the fixed setup cost on x86-64, which is noticeable when blocks are small. #116133 (Groene AI). #116158 (Raúl Marín). - Fix a CPU regression for queries that issue many independent small reads against the same
MergeTreepart when the table hasLowCardinalitycolumns. Such queries on tables with a smallindex_granularitywere up to several times slower since 26.6. #116134 (Groene AI). - Speed up
GROUP BYwithout aggregates by inlining some functions and by starting prefetching at the same cardinality asGROUP BYwith aggregates, which helps when the hash table stops fitting in the L2 cache. #115840 (Nikita Taranov). #116267 (Nikita Taranov). - Use the
bloom_filterskip index forINpredicates on a directly indexed column whentransform_null_in = 1and theINset contains noNULLvalues. Previously the index was skipped for such queries, forcing a full scan. #111329 (Groene AI). - The adaptive
GROUP BYaggregation (enable_adaptive_aggregator) now falls back to the ordinary algorithm when rare keys or aggregate arguments are too wide to copy profitably, so aggregations over heavy string columns run at the ordinary algorithm’s speed and memory usage. Addsadaptive_aggregator_freeze_threshold_bytesto bound each thread’s frozen table in bytes. #115755 (Nihal Z. Miaji). - Lightweight
UPDATEqueries now write patch parts that carry the table’s sort-key columns, so applying a patch no longer has to hold the whole patch part in memory. #116007 (Alexey Milovidov). - Added an alternative row-major payload layout for hash joins to speed up join output reconstruction. Controlled by
enable_hash_join_row_store(defaulttrue) andmin_rows_ratio_for_hash_join_row_store(default5). A probe that emits no right-side columns, such asSELECT count(), no longer publishes a fake zero match count into the row-store cache, so a later full-output run can still use the row-store optimization. Closes #117260. #104884 (Hechem Selmi). #117410 (Groene AI). - The
IEJoinalgorithm now chooses which twoJOIN ONinequality conditions to use as its key conditions by their estimated selectivity from the column min/max statistics, instead of taking the first two in syntax order. The remaining conditions are evaluated per candidate pair, so picking the most selective pair can speed up such joins by orders of magnitude. #115790 (Vladimir Cherkasov). - A
bloom_filterskip index on anArraycolumn is now used forarrayJoin(column) IN (set),arrayJoin(column) GLOBAL IN (set), andarrayJoin(column) = const, the same way it was already used forhasAny(column, set)andhas(column, const). Previously thesearrayJoinforms fell back to a full scan. #109536 (Groene AI). - Reduce cancellation latency for distributed queries that use parallel replicas by not waiting for a replica’s initial announcement after the query is already cancelled. #114862 (Nikita Taranov).
- Speed up reading
system.tablesby not copying the query context for every row. #115867 (Nikolay Degterinsky). - Speed up
Array(LowCardinality(T))aggregations by preserving dictionary identity. #115961 (Ivan Babrou). - Improved the performance of the
roundDurationandroundAgefunctions on AArch64 by rewriting their comparison cascades into a branchless form that the compiler can auto-vectorize. Results are unchanged. #116164 (Groene AI). - Avoid extremely slow
BACKUPof aMemoryorKeeperMaptable whenmax_compress_block_sizeis set to a small value by sizing the temporary file stream withtemporary_files_buffer_size. #116233 (Groene AI). - Speed up server shutdown for databases with many tables by shutting tables down in parallel. Controlled by the new
database_catalog_shutdown_table_concurrencysetting;0means the number of CPU cores. #104969 (Jayme Bird). arrayElementandarraySlicenow read lazily replicated arrays (produced byARRAY JOINandJOINwhenenable_lazy_columns_replicationis enabled) directly, without materializing them. This reduces memory usage and speeds up queries that index or slice a large array. #112304 (Diego Gomes Tomé).A UNION DISTINCT Bnow deduplicates each branch in parallel before merging them, the same way itsSELECT DISTINCT * FROM (A UNION ALL B)rewrite already did. Previously the query funneled every row through a single thread, so it did not scale withmax_threads. #115173 (Groene AI).- Speed up regular-expression searches for simple anchored literals, including prefix, suffix, exact-literal, and escaped-literal matches. #116554 (Elmi Ahmadov). #117331 (Elmi Ahmadov).
- Reduce CPU and memory overhead of
TTLdeletions during merges: blocks are now filtered in one vectorized pass instead of being rebuilt column by column, and a block with nothing to delete is passed through untouched instead of being copied. #116623 (Shaohua Wang). - Optimize one-argument date conversions on
DateandDateTimecolumns. #114267 (Ivan Babrou). clickhouse-localnow attaches thesystemandinformation_schematables on first access instead of at startup. #115489 (Konstantin Bogdanov).- Speed up
GRANT,REVOKE, andSHOW GRANTSfor users with many grants by avoiding a deep copy of the access-rights tree when it is only read. #115696 (miao tang). - Reduce memory usage when inserting into a wide
MergeTreepart that writes many more streams than it has columns, for example a table with a few bucketedMapcolumns. Themin_columns_to_activate_adaptive_write_buffersetting is now compared against the number of streams the part writes, since one write buffer is allocated per stream. #115759 (Groene AI). - Fixed a performance regression since 26.6: a query filtering a
Nullablecolumn withIN (subquery)read the whole table instead of skipping the read when the subquery returned no rows. Closes #116450. #116538 (Yarik Briukhovetskyi). - Fixed quadratic complexity of
groupConcatover aFixedStringargument. The whole argument column was converted toStringonce per row, so a query over 400,000 rows took 45 seconds instead of 0.1 seconds and could overrun itsmax_execution_time, which is only checked between blocks. #116795 (Groene AI). - Push a
WHEREcondition on aUSINGcolumn through aRIGHT JOINso the leftMergeTreeinput can use it as a primary-key index condition, even when the join keys have different types. Applies withenable_analyzer = 1. #103478 (Manuel). - Reduce memory usage of Parquet dictionary-based row-group pruning (
input_format_parquet_dictionary_filter_push_down) several times by hashing integer dictionaries directly and keeping the value set as a sorted vector instead of a hash table. #115744 (Alexey Milovidov). - Reading dictionary-encoded
Parquetdata is now faster: dictionary indexes are decoded and resolved to values in one fused pass, turning runs of a repeated value into bulk fills instead of per-row gathers, for about 20% faster scans of dictionary-encoded numeric columns. #115819 (Alexey Milovidov). - Speed up some
PREWHEREqueries with text indexes by placing text-index lookups and other zero-size-column predicates before expensive predicates on the indexed column. #116546 (Jimmy Aguilar Mena). - Speed up the
numberstable function, sorting, and other bulk index fills on AArch64 by improving code generation of their sequential-fill loops. Results and x86-64/macOS code generation are unchanged. #116616 (Groene AI). - Speed up
groupUniqArrayfor 8-bit types (UInt8,Int8,Enum8,Bool) by using a 256-bit bitmap instead of a hash set. #116880 (Manuel). - Writing rows in JSON output formats that emit object keys, including
JSONEachRowand its aliases,PrettyJSONEachRow,JSON,JSONStrings,JSONStringsEachRow,JSONObjectEachRow, andGeoJSON, is now faster because each field name is no longer copied into a temporary string and re-measured for every row. Compact formats that emit no keys are unchanged. #117082 (Groene AI). - Fixed a performance regression introduced in 26.4 when writing
JSONandDynamiccolumns in text formats, includingDynamic(JSON)text output. #115852 (Pavel Kruglov). #117655 (Nikita Fomichev). - Speed up repeated insertion of the same
LowCardinalityvalue into an in-memory column, for example during joins. #115020 (Minh Vu). - Correlated subqueries with equality on columns that differ only in nullability, or on native-number columns with a least common type, are now decorrelated via equivalent-expression substitution instead of falling back to a
CROSS JOINwith a post-join filter. This avoids severe memory growth on such queries. Closes #113407. #115493 (Dmitry Novik). - Speed up division and modulo of
Int128,UInt128, andDecimal128values that fit in 64 bits.Decimal128rounding withround,floor,ceil,trunc, androundBankersis 1.5x faster on x86-64, and gains more on architectures that have no 128-bit divide instruction. Results are unchanged. #116199 (Groene AI). - Functions with several SIMD implementations, including
MD5,SHA1, hashing functions,greatCircleDistance, andgeoDistance, now choose one from the CPU’s capabilities instead of benchmarking them at runtime.MD5becomes 2-3.7x faster. Thefunction_implementationsetting is obsolete and has no effect. #116501 (Raúl Marín). - Speed up
dotProductTransposedonQBitcolumns with floating-point element types on hosts where SimSIMD has no vectorized dot kernel, which forFloat64means AArch64 and x86 without AVX-512. The reduction now uses independent partial sums instead of a single accumulator, so its summation order changes. Closes #116784. #116816 (Groene AI). - Reduce jemalloc fragmentation by lowering
lg_extent_max_active_fitto its default value6. #116836 (Azat Khuzhin). - Speed up
formatDateTimewith non-constant time zone arguments by caching resolved time zones locally. #116851 (Robert Schulze). - PromQL selector scans over
TimeSeriestables are now parallelized, which speeds up reads of the narrow, decode-heavy samples table columns. #116932 (Nikita Mikhaylov). - Speed up conversion of
TimeSeriestag arrays by reserving the final output size up front and by building extracted tag values andNULLmaps in one pass. #115620 (Minh Vu). #115687 (Minh Vu). - Speed up
timeSeriesGroupArraywhen the input samples are already sorted by timestamp. #117703 (Vitaly Baranov). - The
Nativeprotocol now batches end-of-query control messages into a single socket write by default, andsyncnow flushes them immediately. This removes one round trip of latency per query for clients on high-latency connections that idle between queries. #111034 (Kaviraj Kanagaraj). - Phrase search in text indexes now stores positions in packed blocks and reads only the blocks that cover candidate rows, reducing position-data reads and memory usage. #111550 (Elmi Ahmadov).
- Appending many default values to
ArrayandStringcolumns now pre-sizes the offsets array, reducing reallocations and peak memory usage. #113577 (Groene AI). - The preliminary per-stream
DISTINCTnow abandons deduplication when the input is almost entirely unique, freeing its hash tables because the finalDISTINCTstill deduplicates the output. This roughly halves memory usage and speeds upSELECT DISTINCTon unique data. Controlled byallow_preliminary_distinct_abandoningand observable viaDistinctTransformsAbandonedDeduplication. #116508 (Nihal Z. Miaji). - PromQL instant-vector responses now reuse the formatted evaluation timestamp within each result block. #115567 (Minh Vu).
- Speed up
TimeSeriesreads by writing sampling keys directly into the result column. #115683 (Minh Vu). - Reduce lock contention and per-lookup allocations during serialization by sharding the object pool. #116869 (Manuel).
LIKE ... ESCAPE 'c'andILIKE ... ESCAPE 'c'can now use skip indexes instead of falling back to a full scan.TYPE textindexes prune granules for both;LIKE ... ESCAPE 'c'can also use thengrambf_v1,tokenbf_v1, andsparse_gramsindexes, andNOT LIKE ... ESCAPE 'c'can usebloom_filterskip indexes and the primary key when applicable, matching plainNOT LIKE.TYPE textindexes still do not supportNOT LIKE. #105848 (Groene AI).- Distributed
ORDER BYquery plans can now useread in orderwhen the query order matches the table’s sorting key, and projections can reuse that base-table in-order read too. #115244 (Shankar Iyer). #116854 (Mikhail Artemenko). - Slightly speed up
INSERTintoJSONcolumns by making typed-path default insertion cheaper. #107359 (Pavel Kruglov). - Added the
query_plan_lift_predicate_across_joinoptimization, which copies equi-join filter conjuncts acrossMergeTreejoin inputs for better primary-key pruning. It speeds up some queries by 70-80x. #108377 (Yarik Briukhovetskyi). - Automatic parallel replicas now share prepared sets with the probe plan instead of executing them twice. #114231 (Nikita Taranov).
- Supported
LIKEandILIKEpatterns can now use text indexes. #114728 (Elmi Ahmadov). - Improve generic
arrayReverseperformance by reserving space for all nested elements. #115011 (Minh Vu). LEFT ANTI JOINandLEFT SEMI JOIN, when no column of the right table is selected, now build a hash table that stores the keys alone and release the right-hand blocks as they are built. This makes them up to 1.5x faster and can halve memory usage. Controlled by the new settingenable_join_key_only_hash_tables, which is enabled by default. #115301 (Nikita Taranov).- Speed up
timeSeriesFromGridfor dense rows by bulk-copying values. #115518 (Minh Vu). - Answer
min,max, andcountaggregations withoutGROUP BYand filters directly from per-part column statistics, collected automatically for suitable columns by theauto_statistics_typesMergeTreesetting, reading no data for the parts that have statistics materialized. This speeds up ClickBench Q6 (SELECT MIN(EventDate), MAX(EventDate) FROM hits) from tens of milliseconds to a few milliseconds. Controlled by the new settinguse_statistics_for_min_max_aggregation, which is enabled by default. #115738 (Alexey Milovidov). - On AArch64, short runtime-sized copies in hot string, join, and part-reading paths now stay inline instead of being rewritten to a
memcpycall. #117353 (Groene AI). - Improve performance of
bitmapAndCardinality,bitmapOrCardinality,bitmapXorCardinality,bitmapAndnotCardinality, andbitmapHasAnyby computing the result directly instead of first materializing the intersection bitmap. #117478 (Anand Kr Shaw). - Reduce memory usage of reading a
TimeSeriestable directly with SQL (SELECT ... FROM ts_table). The samples are now aggregated in sorting-key order instead of being buffered in a hash table, so peak memory no longer grows with the size of the scanned window, andLIMITis pushed into the read. #117726 (Nikita Mikhaylov). - Queries with join-side disjunction predicates can now push the per-side filters down to
PREWHEREonMergeTreereads, reducing unnecessary column reads. #117760 (Nikita Taranov). - Reduce
clickhouse-keeperrequest latency for concurrentRemoveRecursiverequests when many uncommitted nodes exist. #117778 (Alexander Gololobov). - Improve performance of
hasToken,hasAnyTokens, andhasAllTokensqueries with text indexes in lazy posting-list apply mode. #117905 (Anton Popov). - Speed up k-way merges: merging sorted streams with multi-column or collated sorting keys uses a sorted array of cursors instead of a heap (7-8% faster), merges of non-intersecting parts detect the whole cursor as one batch in O(1) comparisons, and runs of duplicate keys inside a part are skipped, which makes
SELECT ... FINALfromReplacingMergeTreeuse up to 40% less CPU and the insert-time deduplication ofoptimize_on_insertabout three times faster when there are many duplicates. #115869 (Alexey Milovidov). - Reading columns with many substreams, such as
JSON, from object storage is much faster and makes far fewer requests: the marks of all streams of aMergeTreepart are now loaded asynchronously and in parallel by default (settingload_marks_asynchronously). #118477 (Alexey Milovidov). Marks of streams with an empty data file, such as theSharedVariantsubstreams ofJSONpaths with values of a single type, are not loaded at all, which removes about a third of the requests. #118478 (Alexey Milovidov). The metadata streams ofJSONandDynamiccolumns are no longer read twice when prefetching. #118479 (Alexey Milovidov). A read of a file inside a packed part is bounded to the file’s slice, so it does not transfer the rest of the archive and reuses HTTP connections. #118483 (Alexey Milovidov). - Improved performance of reading individual paths and subcolumns from
JSONcolumns that use theadvancedshared data serialization. Each path and substream now starts in its own compressed block, so a selective read no longer decompresses data belonging to other paths. #118154 (Pavel Kruglov). - The join reordering optimizer uses the CD-C and CD-A conflict detectors from the SIGMOD’13 paper “On the Correct and Complete Enumeration of the Core Search Space”, so joins of any kind can be reordered, including
ANTIandSEMIjoins, not onlyINNERjoins. For seven relations, CD-C explores about 12 times more valid plans than before. #117677 (Fisnik Kastrati). - Decode
Icebergdata manifest files concurrently while the list of data files for a query is produced. The settingiceberg_manifest_decode_concurrency(default4) bounds how many manifests, delete and data alike, are decoded at a time; it replacesiceberg_delete_manifest_decode_concurrency, which is kept as an alias. #116723 (Aaron Harlap). - Use the
lower_boundandupper_boundstatistics of theIcebergmanifest list to prune data files. Closes #104567. #115817 (Konstantin Vedernikov). - Reduce peak memory of the
JSONExtract*functions on the rapidjson code path (allow_simdjson = 0): the parser’s DOM allocator is rewound between rows, so the DOM is bounded by one document instead of growing withmax_block_size. A 100-level nested document uses 84% less memory and is 30% faster, a 200-key object 61% less and 21% faster. #117618 (Groene AI). - Faster writing of
Stringvalues in the JSON output formats (JSONEachRowand its variants,JSON,JSONObjectEachRow,PrettyJSONEachRowandGeoJSON) and inJSONExtractRaw: a run of bytes that needs no escaping is copied in one block instead of one byte at a time. Values in which most bytes need escaping become slower. The output is unchanged. #117755 (Groene AI). addDays,addWeeks,subtractDaysandsubtractWeeksover aDateTimecolumn are up to 12% faster in time zones with UTC-offset changes: a per-row range check that the argument type makes impossible to fail is no longer executed. #118219 (Groene AI).toHourandtoMinuteno longer walk the calendar lookup table in time zones where the result is pure arithmetic:toHourin every zone whose UTC offset does not change after 1970 (includingUTCandAsia/Kolkata), andtoMinutein zones that keep a constant minute-of-hour, such asAsia/Kolkata,Pacific/ChathamandAmerica/St_Johns. Results are unchanged. #117562 (Groene AI).- Reduce the per-query cost of applying the
compatibilitysetting and of logging changed settings intosystem.query_log. A query on a service that sets an oldcompatibilityvalue can run more than twice as fast. #118114 (Raúl Marín). - The bound on the cost of estimating the selectivity of
col IN (...)from column statistics, controlled bystatistics_max_set_size_for_exact_selectivity_estimation, is now also applied whencompatibilityis set to 26.6 or an earlier version. #118095 (Nikita Fomichev). - Automatic parallel replicas now skip their planning overhead entirely when no read step of the query is estimated to read at least
automatic_parallel_replicas_min_bytes_per_replicatimes the number of replicas. #116521 (Nikita Taranov). - Join runtime filters now reach the local probe-side plan under parallel replicas when
parallel_replicas_filter_pushdownis enabled, so grouped probe-side queries filter rows before local aggregation instead of after it. #118650 (Nikita Taranov). The join runtime filter no longer builds a Bloom filter that the build-side key count predicts to be too dense to be useful. #118336 (Manuel). - The bucket-local top-K optimization (
query_plan_aggregation_bucket_top_k) no longer materializes every group’s key for a statistic that only automatic parallel replicas consume, soGROUP BY ... ORDER BY count() DESC LIMIT nover high-cardinality keys spends less CPU in the final aggregation. #118374 (Groene AI). - Skip analyzing the implicit
minmax_countprojection during query planning when the query aggregates with a function that projection cannot provide. Previously every aggregating query over aMergeTreetable interpreted the projection’s definition while optimizing the plan, even forsum,avg,uniqand every other aggregate it can never serve. #118723 (Groene AI). - A condition on an
ARRAY JOINelement, such asARRAY JOIN tags AS t WHERE t IN (...), is now used for skip index analysis the same wayarrayJoin(tags) IN (...)already is. #118582 (Yarik Briukhovetskyi). AWHEREcondition that compares anARRAY JOINelement with other columns of the row is applied before the expansion, so filtered-out elements are never expanded. #118904 (Yarik Briukhovetskyi). ARRAY JOINof aNestedcolumn inside a subquery, CTE,UNIONbranch or view now reads only the referenced subcolumns, like a top-levelARRAY JOINdoes. Fixed an exceptionTuple doesn't have element with namewhen a secondARRAY JOINreferenced a subcolumn of aNestedcolumn joined by the first one. #119055 (Vladimir Cherkasov).- A
bloom_filterskip index is no longer selected for a condition built only from!=orNOT IN. A bloom filter can only prove that a value is absent from a granule, so such a condition never skipped a granule while the whole index was still read.force_data_skipping_indicesnow reportsINDEX_NOT_USEDfor it. #116544 (Groene AI). - Text indexes on
mapKeysandJSONAllPathscan now pruneINpredicates even when the right-hand-side set exceededuse_index_for_in_with_subqueries_max_valuesand was built without stored elements. #118128 (Nikita Taranov). A text index built with thearraytokenizer can now serve arbitraryLIKEandILIKEpatterns by scanning its dictionary. #115649 (Elmi Ahmadov). - Speed up primary key index analysis for conditions with a large
INset by reusing per-thread buffers instead of allocating on every call. #110937 (Manuel). Avoid a redundantLowCardinalitytype unwrap per mark when evaluatingINconditions on the primary key. #117054 (Manuel). - Improved performance of aggregate functions that combine a null map with an
-Ifcondition (sum,avg,min/max/argMin/argMaxwith-If, functions with two or moreNullablearguments such ascorrandquantileExactWeighted, and thetimeSeries*functions with-If) when a block is consumed in increasing sub-ranges, asoptimize_aggregation_in_orderand window frames do. #118025 (Groene AI). - Hashing a value that has no contiguous in-memory representation (
JSON,Variant,AggregateFunction) no longer allocates and copies a buffer per row.xxHash64over aVariantcolumn is about 40% faster,sipHash64over aJSONcolumn about 5%. Counting distinct aggregate states withuniqExactis about 33% faster for 200-byte states;uniq,DISTINCTandarrayDistincthash states through the same path. #119322 (Groene AI). - Speed up compression and decompression with the
T64codec on AArch64 and on x86-64 hosts without AVX-512. The byte and bit transposes now use portable vector shuffles instead of a per-byte scalar loop. Compressed output is unchanged. #116206 (Groene AI). FasterDoubleDeltadecompression. #118787 (Nikita Mikhaylov). - Improve
LIMIT BYperformance by stopping input reads after a constant grouping key reaches its limit. #118770 (Minh Vu). - Squash small chunks before writing the intermediate table during recursive CTE evaluation. Deep recursions no longer accumulate one tiny
Memoryblock per produced chunk, which degraded per-step reads of the working table. #107068 (Zach Naimon). - Speed up
jaroSimilarityandjaroWinklerSimilarityusing AVX2. #104457 (Manuel). Speed upisValidASCIIby using SIMD kernels from simdutf. #119062 (Konstantin Bogdanov). Fasterbase58Encodeandbase58Decode. #117619 (Groene AI). Improve the performance of string functions in byte mode by avoiding unnecessary ASCII scans. #115003 (Minh Vu). - Speed up
mortonEncodeandmortonDecodeby resolving each input column and the constant range mask once per call instead of once per row. Results are unchanged. #117727 (Groene AI). - Speed up the fast Walsh-Hadamard transform used by
randomHadamardTransformand by vector quantization with AVX2 (about 28% higher throughput). #119064 (Jingxin (Philip) Li). - Faster
cbrt,fmod,fmaandhypot: in release builds the slower implementations from Rust’scompiler_builtinswere shadowing the optimizedllvm-libcones, andhypotnow uses the libc implementation. #118910 (Konstantin Bogdanov). - Reduced the time and peak memory of
s2GetNeighborsover many rows by reserving its result array once per block instead of once per row. Peak memory at four million rows in a single block drops by about 44%, and the gain grows withmax_block_size. #115919 (Groene AI). - Avoid materializing constant arguments in generic
leastandgreatestevaluation. #119108 (Minh Vu). - Faster materialization of lazily replicated sparse columns when consecutive output rows refer to the same source row. #118237 (Minh Vu).
- Skip rebuilding column TTL blocks when no row in the block is expired. #119109 (Minh Vu).
- Faster
LEFT ANTIjoins with theie_joinalgorithm when there is no residual condition: empty bitmap scans are skipped. #118584 (Minh Vu). - PromQL: a math binary operator applied to two aggregations of the same expression with the same grouping, such as
sum(x) - max(x)orsum by (job) (rate(x[5m])) / count by (job) (rate(x[5m])), now evaluates the argument once and computes both aggregations in a singleGROUP BY, instead of scanning the argument twice and joining the two results by group. #118307 (Nikita Mikhaylov). Use the constant empty group for aggregations with an emptyby()modifier. #118132 (Minh Vu). Improved the performance of thederivfunction. #118987 (Vitaly Baranov). - A PromQL selector matching a whole metric on a
TimeSeriestable no longer re-evaluates its primary-key range onidfor every row it reads; measured 23.7% faster on a 105M-row whole-metric query. #119092 (Groene AI). - Faster
timeSeries*ToGridaggregate functions: per-sample timestamp validation is skipped when the sorted bucket endpoints already prove the range. #118189 (Minh Vu). - Reduced contention on the global logger mutex in the
MergeTreeread path, which was noticeable on servers with many cores and queries touching many parts. #117498 (Manuel). Partition values are no longer formatted for a trace-level log message when trace logging is disabled. #119605 (Rory Shanks). - Push the
disk_namefilter ofsystem.remote_data_pathsinto the disk traversal, so a query that names the disks it needs no longer walks every object storage disk on the server. #118400 (Alexey Milovidov). - Speed up
clickhouse-clientstartup with many options. #118386 (Ivan Babrou). - Fewer allocations when reporting
ProfileEventssnapshots. #118305 (Ilya Yatsishin). - Speed up reading subcolumns from wide parts and from compact parts with substream marks by avoiding unnecessary full-column serializations. #111020 (Rory Shanks).
- Speed up aggregation batches with non-null states. #117009 (Ivan Babrou).
- Speed up flushing
system.opentelemetry_span_logby writing spans directly into its columns instead of boxing each value into aField. A burst of spans no longer makesSYSTEM FLUSH LOGS opentelemetry_span_loghit its timeout. #117481 (Alexey Milovidov). - Avoid join-order regressions when the selectivity estimator cannot evaluate every predicate in a
WHEREcondition: unaffected predicates are still used to estimate cardinality instead of falling back to full-table estimates. #118137 (Nikita Taranov). - Improved performance of some array functions: generic
arrayFirstandarrayLastreserve result rows,arrayExceptno longer copies the input when the exclusion array is empty, single-argumentarrayConcatno longer rebuilds the result, andarraySlice(arr, 1)no longer rebuilds the result array. #118188 (Minh Vu). #119665 (Minh Vu). #119697 (Minh Vu). #119817 (Minh Vu). - Reuse HTTP connections to object storage when a read range ends at the end of the object. Streams reading the same
MergeTreepart no longer open a new connection for each range. #118480 (Alexey Milovidov). SELECT count()can use the trivial count optimization on tables with lightweight-update patches that only change values, avoiding unnecessary table and patch reads. #118882 (Anton Popov).- Improve
Mapsubcolumn pruning:mapContainsValuecan read only the values subcolumn,mapKeys/mapValuesfilters can read only the matching keys or values subcolumn even when the fullMapis also selected, andhas/notHasover aMapcan read only the keys subcolumn when it is safe to do so. #119172 (Minh Vu). #119261 (Minh Vu). #119190 (Minh Vu). - The
advancedshared-data serialization forJSONnow sizes compressed blocks bymin_compress_block_sizeinstead of flushing per path and substream, avoiding large part-size regressions on tables with many shared-data paths. #119285 (Pavel Kruglov). - Reduce decompression overhead for chained compression codecs by constructing codec-description ASTs only when requested. #119490 (Raufs Dunamalijevs).
- Accelerate
countBytesInFilterandcountBytesInFilterWithNullon AArch64 using direct NEON vector register accumulation, improving filter counting throughput by up to 15x. #119555 (Joshua Dorst). - Partition pruning now runs before loading column statistics and before calculating skip-index ordering costs for
PREWHEREoptimization. Query-planPREWHEREcolumn sizes and statistics are now also estimated from the parts left after pruning, retaining the existing byte-cost estimate when those parts have no per-column measurements. #119558 (Rory Shanks). #119606 (Rory Shanks). #119607 (Rory Shanks). - Speed up single-argument
uniq,uniqCombined, anduniqCombined64on common scalar types when aggregating many interleaved groups. #119594 (Manuel). - UTF-8 validation is now vectorized across ClickHouse, not only inside the
isValidUTF8SQL function on x86. Text index conditions, Prometheus query parsing, format escaping and output,detectLanguage, andisValidUTF8itself now validate long strings much faster, including on AArch64. Closes #116074. #116204 (Groene AI). - Improved the performance of the
splitByNonAlphaandsplitByStringtokenizers. #119434 (Anton Popov). - Speed up
lowerUTF8andupperUTF8for mixed columns with mostly ASCII rows. #119790 (Minh Vu). - Speed up sorting of wide tables (
ORDER BYover many columns) by skipping an unnecessary per-row check in the merge step when no column can be replicated. This removes overhead that was noticeable on ARM. #110627 (Groene AI). - Speed up query analysis for large parameterized views by avoiding repeated hashing of the substituted view query during query-tree comparisons. Closes #118736. #119517 (Alexey Milovidov).
Improvement
- AI functions (
aiGenerate,aiClassify,aiFilter,aiExtract,aiTranslate,aiRedact,aiEmbed,aiSimilarity) are now beta and no longer require theallow_experimental_ai_functionssetting, which is now obsolete. Theai_function_*settings moved to the beta tier, andai_function_max_retriesnow defaults to1so that a single transient provider error does not fail the query. #116227 (George Larionov). - Added dimensional metrics for
S3Queue. #115422 (Bharat Nallan). - Very large
max_streams_to_max_threads_ratiovalues onMergetable reads are now validated correctly: stream-count calculations that overflowsize_tor exceed the maximum source count are rejected withPARAMETER_OUT_OF_BOUNDinstead of hitting undefined behavior. #113382 (Alexey Milovidov). - The Web UI no longer shows sort and filter controls in column headers when the first page of a result contains only a single row and those controls would only re-run the same query. Results that are already sorted or filtered, or truncated at the display limit, still show them. #116181 (Alexey Milovidov).
- A trace started by sampling (
opentelemetry_start_trace_probability) is now written back into the query’s client info, so remote and distributed secondary queries and DDL entries join the same trace instead of starting disjoint ones. #115619 (Diego Gomes Tomé). - The
Empty querysyntax error now says which text was empty when the text is not the query itself but a fragment parsed on its own, such as the value of theparallel_replicas_custom_keyoradditional_result_filtersetting:Empty query (parallel replicas custom key). The error for custom-key filtering requested withoutparallel_replicas_custom_keynow names the settings involved. #115959 (Alexey Milovidov). - Using
join_algorithm = 'direct'against aBuffertable now returns the ordinary unsupported-storage error instead ofCannot clone ReadFromPreparedSource plan step(NOT_IMPLEMENTED). #115309 (Groene AI). INSERT INTO ... SELECTfrom a cluster table function such ass3Clusterwithparallel_distributed_insert_selectnow expands aliases in theWHEREcondition before pruning files to read, so alias-based filters participate in pruning and no longer write a stack trace to the server log. #115932 (Alexey Milovidov).- Wrapped object-storage disks now account reads and writes to the workload of the underlying object storage, so workload scheduling uses the intended limits and priorities. #116288 (Mikhail Artemenko).
- A server started without a config file now declares the same single-node
defaultcluster as the packaged config, socluster('default', ...)andclusterAllReplicas('default', ...)work instead of failing withCLUSTER_DOESNT_EXIST. #116382 (Alexey Milovidov). - The
/commands of the client (/help,/man,/clear) are now offered by the line editor: typing/at the beginning of the input lists them as hints, andTabcompletes the command being typed. A mistake in a command name is now reported with similar commands suggested, instead of being parsed as SQL. #115039 (Alexey Milovidov). - Support
Decimaltypes when writing intoIcebergtables, including decimal partition columns and decimal min/max statistics. #115832 (Konstantin Vedernikov). - Web UI: the query text selection stays visible after the editor loses focus, so it is possible to see what the
Run selectedbutton will run. #116201 (Alexey Milovidov). ReplicatedMergeTreemutations now automatically prune affected partitions from theWHEREcondition when possible. Mutation queries also now accept multiple values in theIN PARTITIONclause. #110968 (Alexey Milovidov).- Allow
JOINon keys that have no common supertype, such asUInt64andInt64. Previously such queries were rejected withThere is no supertype for types UInt64, Int64. Keys are now converted to the type of the values they have in common, and a value outside that range does not match anything. #112951 (Alexey Milovidov). - Reduce the volume of logs from the parallel replicas coordinator: it no longer prints every part and all its mark ranges on each announcement, read request, and response. #115833 (Alexey Milovidov).
- The
Maybe you meanthint for an unknown column, function, or table is now printed before the query instead of after it, so it stays visible for long queries. When a column cannot be resolved from a table expression with an alias, the message also names the table behind the alias. #116809 (Alexey Milovidov). - Comparing a number with an empty or truncated string literal, such as
WHERE numeric_column <> '', now reportsCannot convert string '' to type Int32instead ofAttempt to read after eof. A correlated subquery returning several columns where one value is expected now also reports that directly. #116812 (Alexey Milovidov). - A
Valuesrow whose values are fine but whose,or)is missing or misplaced now reports the missing delimiter and the column it should follow, instead of claiming that the last value could not be parsed as its own type. #116877 (Alexey Milovidov). - TLS CA certificates configured with
openSSL.server.caConfig/openSSL.client.caConfigandcaConfigof composableprotocolsare now reloaded on file changes and onSYSTEM RELOAD CONFIG, allowing CA rotation without restart for server, client, and Keeper connections. #117387 (James). - Bare
UNIONnow tells you to writeUNION ALLorUNION DISTINCT, or to setunion_default_mode, instead of naming an internal AST class. TheEXCEPTandINTERSECTvariants are reworded the same way. #116815 (Alexey Milovidov). - An aggregate function used in
WHEREorPREWHERE, often through an alias such asSELECT count() AS c FROM t WHERE c > 1, is now told to useHAVINGinstead. Values that cannot be parsed asDateno longer claim to be too short when that is not the reason; the error now names the expected format. #116817 (Alexey Milovidov). - Invalid calls to the internal
viewExplaintable function now returnBAD_ARGUMENTSinstead of analyzing the invalid expression and potentially failing with an unrelated error such asUNKNOWN_TABLE. #108384 (Christoph Viebig). - Unexpected
jemallocwarnings are no longer suppressed, and the server now reports disabled per-CPU arenas insystem.warnings. #116899 (Azat Khuzhin). - Enable reading
ReplacingMergeTreedata in reverse order withFINAL. #115345 (Alexey Milovidov). - Added the
snapshot_zstd_compression_levelKeeper coordination setting to configure theZSTDcompression level used for snapshots. It defaults to3, preserving the existing behavior. #116866 (Antonio Andelic). - A typo in the key, index, or TTL expression of an
ALTER TABLEnow suggests the column that was probably meant, the waySELECTalready does. Previously it printed a list of available columns that, for aMergeTreetable, was dominated by virtual columns and truncated before the real ones. #116915 (Alexey Milovidov). - Aggregate functions that take parameters and are wrapped with the
-Arraycombinator now preserve those parameters correctly, so expressions such asargMaxArray(2)and state types such asAggregateFunction(groupArrayMovingSum(42), UInt64)no longer drop them. In debug and sanitizer builds this also fixes an internal assertion. #110143 (Groene AI). rseqis now enabled correctly on x86-64 builds that use link-time optimization; previously it was silently disabled. #117700 (Azat Khuzhin).- Take a column’s
CODECinto account when estimating how many bytes a query reads from compact parts. The estimate compressed a sample with the default codec (LZ4) no matter how the data is really stored, so a column stored with a stronger codec was overestimated, which inflateseffective_max_reading_threadsand can make automatic parallel replicas distribute a query that is cheaper to run on a single node. #114535 (Nikita Taranov). Icebergtables stored onS3can now read data files from a different bucket than the table metadata. #116771 (Konstantin Vedernikov).- An aggregate function with the
-Ifcombinator whose condition has the wrong type, or is missing, now says that the last argument is the condition and must beUInt8, instead of only reporting an illegal type for the last argument. AnASOFjoin with no inequality predicate now says that one is needed in addition to the equality predicates, instead of ending the message in, in .. #116916 (Alexey Milovidov). clickhouse-localnow exposessystem.warnings, and ClickHouse now checksrseqcompatibility at startup. #117717 (Azat Khuzhin).- The
TimeSeriestable engine, the PromQL dialect and thetimeSeries*aggregate functions are moved from the experimental tier to the private preview tier. Settingsallow_experimental_time_series_tableandallow_experimental_time_series_aggregate_functionsare renamed toenable_time_series_tableandenable_time_series_aggregate_functions; the old names remain as aliases. #118124 (Nikita Mikhaylov). TimeSeriestables now store an explicit schema version in theversionengine setting. The PromQL execution layer supports only a declared range of versions and rejects queries over tables outside that range with an instructive error. #111204 (Nikita Mikhaylov). ATimeSeriestable definition copied withCREATE TABLE ... ASnow gets the settings of the new table, and the newid_typesetting letsCREATE TABLE ... AS srccopy onlysrc’s definition without reading its target tables. #118517 (Vitaly Baranov). #119613 (Vitaly Baranov).- Reads from
TimeSeriestables now respect thejoin_algorithmand the partition-wise aggregation settings of the query instead of overriding them, and the internal join of samples and tags supportsfull_sorting_merge. #118864 (Nikita Mikhaylov). Thepromql_evaluation_timesetting defaults toautoregardless of thecompatibilitysetting. #119202 (Raúl Marín). - Join runtime filter settings are now production-tier (previously experimental). #117383 (Robert Schulze).
- Improved syntax error messages. An unclosed bracket is now reported at the place where the parser stopped, which is next to the actual mistake, and every unclosed bracket is listed with its own position; previously the outermost bracket was blamed, which in a large query can be thousands of characters away from the mistake. A mistyped keyword is now named explicitly (
Maybe you meant: SELECT.) instead of only being one item in a list of dozens of alternatives. #116806 (Alexey Milovidov). - The
psql-style\dof the interactive client now describes a table when a table name is given (\d hits), like it does inpsql; without an argument it still lists the tables. #118281 (Alexey Milovidov). clickhouse-localnow merges theconfig.dandconf.ddirectories of the current directory into its configuration even if there is no main configuration file, so a directory with aconfig.dno longer additionally requires an emptyconfig.xml. #118410 (Alexey Milovidov).- Added the
clickhouse_versionandsystem_processorcolumns to the system log tables. #117896 (Miсhael Stetsyuk). EXPLAIN ANALYZEnow shows more information about the estimation for joins. #114792 (Kirill Kopnev).- Automatic parallel replicas now support queries with
LIMITandOFFSET. #117402 (Nikita Taranov). - Object storage writes (
INSERTintos3,azureand other object storage tables) now support parallel replicas. #119214 (Konstantin Vedernikov). - Added the
min_partition_age_to_force_merge_secondsMergeTreesetting: when every part in a partition is at least this old, theSimpleandStochasticSimplemerge selectors compact that partition’s parts within themax_bytes_to_merge_at_max_space_in_poollimit. #115547 (Valery Petrov). TRUNCATE TABLEon aReplicatedMergeTreetable no longer blocks concurrentDROP,RENAMEand other DDL queries on the same table while the data is being removed. #114672 (Nikolay Degterinsky).- Allow
ALTER TABLE ... MODIFY SETTING storage_policyforMergeTreetables when newly added disks contain only a matchingformat_version.txtand an emptydetached/directory under the table path. #107736 (Maxim Orlovsky). - Added the
s3_upload_checksum_algorithmsetting to choose the checksum sent withS3uploads (MD5,CRC32orSHA256). The default is empty and keeps the current behavior. UseCRC32orSHA256on FIPS builds, whereMD5is unavailable and uploads would otherwise carry no checksum, which buckets with Object Lock reject. #107318 (Sebastian Vercruysse). - Partition field summaries are written into the manifest list of
Icebergtables. #118796 (Konstantin Vedernikov). ConcurrentINSERTs into anIcebergtable through a catalog no longer back off on a commit conflict and retry immediately. #119238 (Konstantin Vedernikov). - Log when an object storage listing returns an empty page while reporting that more objects follow. This is legal and is handled correctly, but it has twice been the trigger for silently losing objects and nothing recorded that it occurred. #119065 (Sema Checherinda).
- A warning is now logged when a CTE is declared as
MATERIALIZEDbut the settingenable_materialized_cteis disabled, in which case the keyword is ignored and the CTE is inlined at each reference. Previously the keyword was silently ignored. #118032 (Dmitry Novik). - An unknown profile event name in the
trace_profile_events_listsetting now gives a readable error message with hints instead ofstd::out_of_range: unordered_map::at: key not found. #116049 (Alexey Milovidov). - The dictionary loader now logs
neverinstead of a timestamp in the year 294247 when an object has no automatic update scheduled (for example a dictionary withLIFETIME(0)), which previously looked like a scheduling bug next to a failed-update message. #118443 (Alexey Milovidov). - Correct the error message for an unsupported attribute in an
ip_triedictionary: it claimed thatArrayattributes are unsupported, while in fact they are supported and onlyNullableattributes are rejected. #118492 (Alexey Milovidov). MEMORY_LIMIT_EXCEEDEDis reported promptly forparallel_hashjoins whose hash-table construction uses deferred memory tracking. #116477 (Konstantin Morozov).- Less verbose logging of
INSERTs intoMergeTreeandReplicatedMergeTreetables. #116486 (Azat Khuzhin). - The hash tables behind the TLD lists (
firstSignificantSubdomainCustomand similar functions), the naive Bayes classifier and text indexes use a simpler, packed string representation. #117175 (Surya Teja). - ClickHouse Keeper now counts the per-entry allocation overhead in
latest_logs_cache_size_threshold,KeeperLatestLogsCacheSize, andlgif’slatest_logs_cache_size, so the configured limit tracks cache memory rather than only serialized payload bytes. #119045 (Nikita Taranov). Thelatest_logs_cache_entry_count_thresholdsetting is effective again and limits the in-memory latest-log cache by entry count independently oflatest_logs_cache_size_threshold. #119151 (Antonio Andelic). - Show the progress percentage again for queries reading from the
filetable function andINFILE. #119213 (Raúl Marín). - Warn when
CLEAR COLUMNleaves anEPHEMERAL-derivedMATERIALIZEDcolumn stale. #115371 (Shaohua Wang). - Reduced cancellation latency for
INTERSECTandEXCEPTqueries:KILL QUERYnow interrupts the hash-table build and filter loops within a single chunk instead of waiting for the whole chunk. #118046 (Roman Vasin). - The
compatibilitysetting can now keep selected new defaults in effect: settings changes markedStartUsingNeware no longer rolled back to the previous default whencompatibilitypoints to an older version. #114190 (Mikhail Artemenko). - Added write support for
DeltaLaketables onAzurestorage. #116698 (Smita Kulkarni). - Added aliases without the
allow_experimental_prefix for existing settings whose tier already marks them as experimental or beta; the old names continue to work. #119056 (Robert Schulze). - Bump the bundled
libsshfrom0.12.0to0.12.2. #119262 (Robert Schulze). - Function
replicatenow returns a constant column when all its arguments are constant, likearrayWithConstant. #111069 (sakshichitnis27). - The
PROJECTION_NOT_USEDandINCORRECT_DATAerrors offorce_optimize_projectionandforce_optimize_projection_namenow list every projection the optimizer considered and why each was rejected. #119624 (Mikhail Artemenko).
Bug Fix (user-visible misbehavior in an official stable release)
ALTER TABLE ATTACH PARTITION FROMis no longer replicated inReplicateddatabases. #94835 (MikhailBurdukov).- Invalid Azure upload-size settings (for example
azure_min_upload_part_size = 0orazure_max_blocks_in_multipart_upload = 0) are now rejected early with a clear error instead of triggering an internal exception (second_size > 0) deep in the write path. This applies to both query settings and Azure disk configuration. #103394 (Statxc). - Fixed wrong results for comma or
CROSS JOINqueries whoseWHEREclause compares columns from the two sides through a non-deterministic expression such asrand. Such queries could return rows that contradict their ownWHEREclause because rewriting the join toINNER JOINre-evaluated the expression per row on each side. #112938 (Groene AI). S3QueueandAzureQueuetables whose metadata handle is gone no longer fail withLogical error: 'Files metadata is empty'when read, altered, or flushed; they now reportTABLE_IS_DROPPEDinstead.SYSTEM FLUSH OBJECT STORAGE QUEUEon such a table no longer terminates the server. #113695 (Groene AI).- Fix
LOGICAL_ERRORwhen filtering anIcebergcolumn thatALTER TABLE ... MODIFY COLUMNmadeNullable. Closes #85029. #114521 (Groene AI). - PromQL grouping modifiers now support quoted label names. #114545 (Minh Vu).
- Fixed reading a table while a mutation is in progress: a
MATERIALIZEDcolumn could return a stale or incorrectly recomputed value, and selecting it together with an updated column could fail with an error. #114561 (Shaohua Wang). #115372 (Shaohua Wang). - Fixed an RBAC bypass in the
Aliastable engine that allowed users without privileges on the target table to reveal its schema, row count, size, and existence. #114596 (Kai Zhu). - Fixed a column that was renamed, dropped, and added again in one
ALTERreturning the dropped column’s values instead of its own default while the mutation was still pending. #114601 (Shaohua Wang). ANY RIGHT JOINandSEMI RIGHT JOINwith severalOR-ed conditions in theONclause no longer duplicate some right-table rows and lose others. A writtenANY LEFT JOINwas affected too, because the planner may swap the tables and execute it asANY RIGHT JOIN. #114676 (Vladimir Cherkasov).- Fix invalid backslash escape handling in text,
tokenbf_v1, andngrambf_v1indexes. #115634 (Elmi Ahmadov). - Fix crashes of the
Parquet,ORC, andIcebergreaders on malformed input: aDELTA_BYTE_ARRAYpage with an empty length stream, aDELTA_BYTE_ARRAYpage of aDecimalcolumn read under a filter, an out-of-range enum in anIcebergmanifest file, and an oversized allocation in the ORC library. #115703 (Alexey Milovidov). - Reject invalid names of projections and indexes. #115824 (Alexander Tokmakov).
- A
KeeperMaptable with unparsable metadata no longer prevents server startup; it is now quarantined instead. Closes #115881. #115941 (Groene AI). - Fixed
LOGICAL_ERROR: Index with name auto_minmax_index_<column> already existswhen a singleALTER TABLEstatement combinedRENAME COLUMNwith another command, such asMODIFY SETTING, on a table with implicit minmax indices (add_minmax_index_for_numeric_columnsand friends). Renaming a plain column also no longer leaves a followingDROP COLUMNfailing withUNKNOWN_IDENTIFIER, nor a followingADD COLUMNwithout its implicit index. #116063 (Groene AI). - Fixed a crash of stateless workers with object storage. #116067 (Konstantin Vedernikov).
- Fixed distributed queries that filter or compute on
Decimal,DateTime64, orTime64constants: pushed-down constants could fail withCANNOT_PARSE_DATETIME, lose precision, or change theirDynamicsubtype when sent to remote shards. #95055 (Yakov Olkhovskiy). - Fixed
JSON,Object, andDynamiccolumns hashing logically equal values differently depending on their physical layout: howJSON/Objectpaths were split between dynamic subcolumns and shared data, or whether aDynamicvalue sat in a typed or shared variant. Hash-based joins on such a key silently missed matches, and agrace_hashspill could raise aLOGICAL_ERROR(Invalid state transition). AJSONkey needed no non-default setting;Dynamicalso requiredallow_dynamic_type_in_join_keys. #109450 (Groene AI). - Setting a Keeper coordination timeout such as
operation_timeout_ms,session_timeout_ms, orstartup_timeoutto a very large value no longer overflows and expires the wait immediately. Builds with the undefined behavior sanitizer no longer abort. #112088 (Groene AI). - Fixed a
bloom_filterskip index dropping granules that contain matching rows when aStringorFixedStringcolumn is compared for equality against a constant that is wider than the indexed type, so queries such asSELECT count() FROM t WHERE s = toFixedString('abc', 5)no longer silently return too few rows. #112639 (Groene AI). - Fixed a large
max_concurrent_threads_ratio_to_coresvalue inCREATE WORKLOADproducing an unspecified concurrent-thread limit. The ratio is now clamped before narrowing, so such a value means “no limit”. #113206 (Groene AI). - Fix wrong results when plan-based parallel replicas shipped a read pinned by
select_sequential_consistency. Follower replicas rebuilt the read without the pinned block-number boundary and returned rows the insert quorum never confirmed. Such a read is now executed locally. #114263 (Groene AI). - Fixed reading
Parquetfiles whose offset index does not start at row 0. Such a file could make the nativeParquetreader return wrong rows, or reportLOGICAL_ERRORinstead ofINCORRECT_DATA. The offset index is now validated when it is read. #114530 (Groene AI). - Fix query condition cache poisoning by
JOINqueries withquery_plan_join_shard_by_pk_ranges = 1, which made later queries with the sameWHEREcondition return too few rows. #114827 (János Benjamin Antal). - Fixed AI functions under-reporting provider usage in
system.query_logand in per-query quotas: counters accumulated before a failed request were dropped, and tokens for a response the provider billed for but that failed validation were never counted. #114905 (George Larionov). - Fixed
Coordination mode mismatch for stream <table>: got Default, expected WithOrderwhen a parameterized view is used as anINsubquery of an ordered query with parallel replicas enabled. A parameterized view used this way no longer plans its inner read with parallel replicas coordination on a replica. #114916 (Groene AI). - Fix asynchronous inserts into
JSONcolumns ignoring themax_dynamic_subcolumns_in_json_type_parsingsetting. Previously, an asynchronous insert (async_insert = 1) could store more dynamic paths than the setting allows, giving a different column layout than a synchronous insert with the same settings. The cap is now preserved when asynchronous inserts aggregate parsed data. #115329 (Mikhail f. Shiryaev). - Validate the discriminator of deserialized
Variantvalues, so malformed data is rejected instead of being read out of bounds. #115443 (Azat Khuzhin). - Fix
UNKNOWN_IDENTIFIERwhen creating a materialized view whose query uses an expression alias as the right argument ofIN. Closes #94894. #115651 (Alexey Milovidov). - Fix
RESTORE ... AS <new name>leaving theREFRESH ... DEPENDS ONlist of a refreshable materialized view pointing at the original database. The restored view refreshed in response to a table it no longer read, ignored refreshes of its own parent, and stopped refreshing entirely once the original database was dropped. #115689 (Groene AI). - Validate the deserialized states of
stochasticLinearRegression,stochasticLogisticRegression,groupUniqArray,groupArrayIntersect, andtopK, and of theResamplecombinator, so malformed data is rejected instead of being read out of bounds. #115701 (Alexey Milovidov). - Mask the
aws_external_idsetting of theDataLakeCatalogdatabase engine inSHOW CREATE DATABASEandsystem.databases.engine_full. It was previously printed in plaintext, unlike the other AWS credential settings. Closes #114999. #115791 (Groene AI). - Fixed
SELECT count()never terminating, or returning an invented row count, on a corruptedMsgPackorProtobufListfile. Theoptimize_count_from_filesfast path counted rows without requiring the read position to advance, so a two-byteProtobufListfile produced billions of rows and never returned. Such input is now rejected with the same error the ordinary read path gives. #115884 (Groene AI). - Fixed
ATTACH TABLE ... AS REPLICATEDand theconvert_to_replicatedflag file accepting a conversion whose ZooKeeper path is not a safe path. On a server whosedefault_replica_pathsubstitutes{database}or{table}, a name containing/used to resolve to a path inside another table’s subtree, letting the converted table register a replica under a table it has no privileges on. Such a conversion is now rejected withBAD_ARGUMENTS, the same way an equivalentCREATEalready was. Closes #115967. #115991 (Groene AI). - Fixed wrong results when joining against a view or
viewwhose projected column has the same name as a column of one of its own inner relations, for exampleSELECT expr(x.c0) AS c0 FROM a AS x, b AS y. The join order optimizer merged such an expression into the flattened join graph and then applied it twice, so the query silently returned skewed values. When the expression also changed the column type, the same cause producedAMBIGUOUS_COLUMN_NAMEat plan time instead. Closes #116036. #116152 (Groene AI). - Listing
tlsv1_3in<openSSL><server><disableProtocols>(or theclientequivalent) now actually disables TLS 1.3. Previously the token was dropped with no error or log line and the server kept negotiating TLS 1.3, so an operator who disabled it believed TLS 1.3 was off while it was not. Closes #79876. #116170 (Groene AI). - Fixed
Invalid number of columns in chunk pushed to OutputPort(LOGICAL_ERROR) when aSELECT ... FROM t STREAM ... ORDER BY ... LIMIT nquery read a table with aPROJECTION. Lazy materialization is no longer applied to aSTREAMread. #116187 (Groene AI). - Fixed
system.detached_tablesfailing withNOT_IMPLEMENTEDwhen the server has databases such asDictionary,Filesystem,HDFS,Overlay, orS3. Unsupported database engines are now skipped during iteration. Closes #104868. #107943 (Aditya Kumar). - Skip the Query Condition Cache for object-storage files whose
ETagis not a strong content identifier, such asHDFS. Previously a same-second, same-size overwrite could reuse stale skip marks and silently drop matching rows. Closes #112016. #112051 (Zhang Yifan). - Fixed text index functions
hasToken,hasAnyTokens,hasAllTokens, andhasPhraseoutsideWHERE/PREWHERE: they now apply the index’s tokenizer and pre/postprocessing in theSELECTlist, aggregate arguments, and withuse_skip_indexes = 0, so results match the index path. Closes #108808. #113154 (Elmi Ahmadov). - Fix wrong results for a query that calls the same table function twice with arguments that differ only in a part of the query that was not taken into account by the AST hash, such as
UNION ALLagainstUNION DISTINCT,INTERSECTagainstEXCEPT,LIMITagainstOFFSET, or the bounds of a window frame. The second call reused the result of the first one. #114171 (Alexey Milovidov). - Fix
THERE_IS_NO_COLUMN/NOT_FOUND_COLUMN_IN_BLOCKwhen a filter that runs afterFINALis a plain column reference. This affected an explicitPREWHERE bunderFINALand, with default settings, a row policy whose expression is a bare column. #114578 (Groene AI). - Fix loading old
S3tables with globbed paths andPARTITION BYafter upgrading from versions before 26.6. #115277 (Bharat Nallan). - Fix
Icebergidentity-partitioned reads: partition values are now taken from partition metadata instead of returned asNULL. Closes #110216. #116129 (Konstantin Vedernikov). KeeperMapnow writes single-expression primary keys without redundant outer parentheses, so metadata created by newer servers remains readable by ClickHouse 26.4 during supported rolling upgrades and rollbacks. #116369 (Sergey Kuznetsov).- Fixed
Kafkatables usingkafka_sasl_mechanism = 'AWS_MSK_IAM'failing authentication once an hour withSASL authentication error: Access denied. TheOAUTHBEARERtoken lifetime advertised tolibrdkafkais now capped by the remaining validity of the AWS credentials that signed the token, so the next token refresh is always scheduled before those credentials expire. Successful token refreshes are now logged, and unhelpful ClickHouse-side stack traces are omitted from broker-originated SASL errors insystem.kafka_consumers. #109125 (kalavt). - Fixed silent truncation of
DateTime64andTime64values with a scale above 6 whendate_time_64_output_format_cut_trailing_zeros_align_to_groups_of_thousandsis enabled. The printed fraction was capped at 6 digits, so aDateTime64(9)value of00:00:00.000000700rendered as00:00:00.000000even though the stored value was not zero. The documented output range of the setting widens from[0, 3, 6]to[0, 3, 6, 9]. #112854 (Groene AI). - Fixed the
dpsubanddpsizejoin-order optimizations (query_plan_optimize_join_order_algorithm = 'dpsub'/'dpsize') silently dropping single-table filter conditions from aJOIN ... ONclause, which could return extra rows. #114629 (Fisnik Kastrati). #118126 (Fisnik Kastrati). ZooKeepermulti requests now reject unsupported and mixed read/write operations. #115768 (Antonio Andelic).- You can now read
Icebergv2 tables whose manifests omit the optionalsnapshot_idcolumn, such as tables managed by BigQuery; reading one previously failed withCannot find column snapshot_id. A manifest that omitssequence_numberis also no longer read as sequence number0. Both values are inherited from the manifest list, as theIcebergspec requires. #116040 (Takayuki Enomoto). - Fixed
_pathpath normalization for globbed files and object-storage reads, soWHERE _path = '<path>'no longer misses rows because of redundant or leading separators. Globbed reads through symlinks and..names also no longer read or, withrename_files_after_processing, rename the wrong file. #116244 (Groene AI). #116252 (Groene AI). - Fixed wrong window function results for
PARTITION BYover a floating-point key (alsoJSON,Dynamic, and these types nested inNullable,LowCardinality,Array,Tuple,Map, orVariant) withmax_threads > 1: values that compare as equal, such as-0.and0., could hash into different threads, and one logical partition got several window frames. #116315 (Alexander Gololobov). - A
Native-protocol client can now forward an unknown setting to the server by name. Previously, when a client sent such a setting as a custom setting, the server left the real setting unchanged and reported it at its default value in the settings received with the query. #116317 (Miсhael Stetsyuk). - Fixed
h3Linereturning uninitialized memory in the tail of the result array when a line between two valid H3 indices cannot be drawn because it crosses pentagon distortion. Such a call now throwsINCORRECT_DATA. #116583 (Groene AI). CREATE TABLE ... AS <table function>no longer accepts aPRIMARY KEYin its column list. Previously, such a statement wrote table metadata that the server could not parse back on the next start, so the database failed to load with a syntax error. #116645 (Groene AI).- Fixed wrong row counts and dropped rows when a
DateTime64primary-key column is filtered throughtoStartOfDay,toRelativeSecondNum,toRelativeMinuteNum,toRelativeHourNum,toRelativeDayNum,toRelativeWeekNum,toMonthNumSinceEpoch, ortoYearNumSinceEpochwith values outside theUInt32-seconds range (before 1970 or beyond 2106). These functions claimed to be always monotonic to the primary index, but their standard-precision results wrapped for out-of-rangeDateTime64, breaking primary-key pruning. #110344 (Groene AI). - Fix regressions around
use_legacy_to_time:MergeTreekey expressions usingtoTimethat were created with the legacy semantics now work again, andCREATE TABLE ... AS SELECT,CREATE TABLE ... AS <table function>, andCREATE MATERIALIZED VIEWno longer fail or silently flattenNestedcolumns whenuse_legacy_to_time = 1. Closes #117001. #110958 (Groene AI). #116953 (Yarik Briukhovetskyi). - Fix
OPTIMIZE TABLE ... MANIFESTonIcebergtables: tables whose metadata file omits the spec-optional top-levelrefsobject no longer fail withPoco::NullPointerException, and an experimentalIcebergtable whose rows had all been deleted no longer crashes. Closes #112082. #112163 (Groene AI). #111241 (Smita Kulkarni). - Fix a server crash during a
JOINthat spills to disk. When an allocation failed while the join rehashed its buckets, the in-memory join was left either holding released data or absent altogether, and another build thread could dereference it. #113410 (Groene AI). - Fix wrong statistics-part pruning for negated floating-point predicates with
NaN. #113507 (Han Fei). - Fix a spurious
PreconditionFailed(Code: 499) error when creating or committing to anIcebergtable. If the object store drops the response to the metadata write after the object was written, the retry of that conditional write hits its own object and the query fails even though the write succeeded. Also stop a conditional multipart completion from reporting success over an object it did not write, silently losing the write it was meant to reject. #113994 (Groene AI). - Fixed lightweight
UPDATEonReplicatedMergeTreebeing rejected withTIMEOUT_EXCEEDEDafter a few seconds under concurrent updates, long before the configuredlock_acquire_timeoutelapsed. The Keeper lock acquisition loop was bounded by a fixed number of tries instead of by the timeout, so raisinglock_acquire_timeouthad no effect. #114125 (Groene AI). - Fix
ORDER BY ... LIMITqueries onTuple()columns raising aNOT_IMPLEMENTEDexception when top-K dynamic filtering is enabled. Direct empty tuples now skip the optimization, while supported nested composite types continue to use top-K filtering. #114182 (Langning Zhang). - Fix
Icebergtables partitioned bytoRelativeDayNumortoRelativeHourNumpublishing the non-canonical transform namesdaysandhoursin metadata. ClickHouse now writes the spec-defined singular namesdayandhour, so external readers such aspyicebergcan parse the partition spec. #114864 (yanglongwei). - Fix the server failing to start when
listen_hostcontains both::and0.0.0.0andarrowflight_portis configured, and fix two gRPC listeners silently sharing one port in the same configuration.listen_trynow also covers the gRPC and Arrow Flight protocols, which bind their listening socket when they are started. #115074 (Alexey Milovidov). - Fix a case where expensive ZooKeeper exception logging could delay session finalization and leave pending requests unresolved. #115396 (Antonio Andelic).
- An invalid
http_handlersconfiguration is now reported with its own error instead of being wrapped intoNETWORK_ERROR "Listen [host]:port failed". Previously, whenlisten_trywas in effect, the error was only logged as a warning aboutlisten_hostand the server started without serving HTTP at all. The same applies to the Prometheus listener onprometheus.port, to the Keeper control endpoints onkeeper_server.http_control, and toSYSTEM START LISTEN HTTPinclickhouse-local, which blamedlisten_hostandhttp_port. #115548 (Groene AI). - Fixed zero-precision
DateTime64andTime64text conversions returningDateTimeorTimeinstead ofDateTime64(0)orTime64(0):toDateTime64OrNull,toDateTime64OrZero,parseDateTime64BestEffort,parseDateTime64BestEffortOrNull,parseDateTime64BestEffortOrZero,parseDateTime64BestEffortUS,parseDateTime64BestEffortUSOrNull,parseDateTime64BestEffortUSOrZero,toTime64OrZero, andtoTime64OrNull. This previously prevented conversion of dates before1970-01-01and made theTime64functions silently lose values thattoTime64parses. #115618 (Mark Needham). #116979 (Navneet Kumar). - Fixed a server startup failure after creating an
Aliastable whose target did not exist yet and later became anAliastable itself. Such a table was accepted byCREATE, but rejected while loading metadata, which aborted startup withBAD_ARGUMENTS. TheAliastarget restrictions are now applied only to freshly supplied definitions. #116153 (Groene AI). - Fix
SHOW CREATE TABLEfailing instead of describing the table when the table’s storage object cannot be opened, for example aDataLakeCatalogtable the catalog reports as unreadable. TheAliastarget-access check now consults the engine name of the create query instead of opening the table. #116231 (Groene AI). - Fix
ProfileEvents['SelectedRows']andProfileEvents['SelectedBytes']being counted twice for reads from file, object-storage, data lake, queue, and executable table engines and table functions, and for executable dictionaries and UDFs. They now agree withread_rowsandread_bytes, as does theRead:line ofEXPLAIN ANALYZE. #116427 (Groene AI). #116679 (Groene AI). - Fixed
executable_pooldictionaries,executable_pooluser-defined functions, andExecutablePooltables waiting ten times longer than the configuredmax_command_execution_timewhen the process pool is exhausted, while the resulting error still reported the configured value. Closes #116467. #116560 (Groene AI). - Fixed a server crash when reading an
Icebergtable whose manifest list declares a very largemanifest_length. The declared value was used as the metadata cache entry weight, overflowing the cache accounting and terminating the server. The size measured while reading the manifest file is now used instead. #116564 (Groene AI). - Fixed a hang when a query names a database that does not exist, either through the
databasesetting (for exampleSELECT 1 SETTINGS database = 'no_such_db') or through thedatabasefield of a gRPC request. Such a query now fails withUNKNOWN_DATABASEinstead of blocking its connection forever; while it was hung it was also invisible tosystem.processesand toKILL QUERY. #116582 (Groene AI). - Fixed a use-after-free where a subscriber of workload entity changes, such as an object-storage disk, could be destroyed while its own change callback was still running. Destroying a workload entity subscription now waits for an in-flight callback and stops new ones from starting. Reachable from a
CREATE TABLEwith an inlinedisk(...)definition whose startup fails, concurrently withCREATE RESOURCEorDROP RESOURCEfrom another session. #116607 (Groene AI). - Fixed an exception when reading an
Icebergtable whose manifest marks a delete file as an equality delete without listing any equality field id. Such an entry is now rejected withICEBERG_SPECIFICATION_VIOLATIONinstead of an untypedstd::out_of_range. #116617 (Groene AI). - Fixed the
filetable function reading and writing outsideuser_files_pathwhen a..reached the path behind a directory symlink leavinguser_files_path: through brace expansion in a glob pattern, or through a..partition id inINSERT INTO FUNCTION file(...) PARTITION BY. #116767 (Groene AI). - Fixed corrupted or crafted
Gorilla-compressed data being decoded to wrong values instead of being rejected. Such data is now rejected withCANNOT_DECOMPRESS. #116820 (Groene AI). - Fixed the
looptable function disclosing the column names and types of anAliastable’s target to a user who holds no privilege on that target: a query that read no rows received them in its response header.loopnow requires table-levelSELECTon the target, matching what it already required of the table name it is given. #116873 (Groene AI). - Fixed incorrect results or an exception for
-Stateaggregates combined with-OrDefaultor-OrFillunderWITH TOTALS,ROLLUP, orCUBE. #99980 (Ilya Yatsishin). - Fixed
IcebergINSERTwriting manifest-wide aggregate column statistics into everydata_fileentry when a partition produced more than one data file. Each entry’snull_value_counts,column_sizes,lower_bounds, andupper_boundsnow describe only the data file it points at. Previously an entry could report more nulls than the file had rows, so a spec-conforming external reader could prune files that contained matching rows. #112414 (Groene AI). - Fix a server abort while committing a mutated part when its column or secondary-index sizes had not been computed yet. #112691 (Groene AI).
- Fix reading corrupted
ArrowStreamfiles. A malformed per-buffer uncompressed-length prefix in a compressed Arrow IPC record batch could reach the allocator as an enormous allocation size and produceLOGICAL_ERROR; it is now rejected asINCORRECT_DATA. #113006 (Groene AI). - Fix wrong results for
GROUP BYwhose only key is an injective function of constants, for exampleSELECT 1 FROM t GROUP BY materialize(NULL). Such a key could be removed, leaving the query with noGROUP BYand no aggregation, so it returned one row per input row instead of one row per group. Over aMergetable that mixes a local and a remote child, the same cause could also raise the exceptionChunk info was not set for chunk in GroupingAggregatedTransform. #114981 (Groene AI). - Fixed the exception
Not-ready Set is passed as the second argument for function 'in'in three cases: when selecting from aMergetable (or themergetable function) whose underlying table has a row policy containing anINsubquery, when a query withpartial_result_on_first_cancel = 1was cancelled while building the set forIN (subquery), and when a correlated subquery whose body containsIN (subquery)runs withcorrelated_subqueries_use_in_memory_buffer = 0, whichmake_distributed_plan = 1also sets. #114058 (Groene AI). #115083 (Alexey Milovidov). #115868 (Groene AI). - Fix authentication over the PostgreSQL wire protocol for users with several authentication methods. Users who also had an
ssh_keymethod, or another method with no password, were rejected withInvalid user or passwordeven when the correct password forscram_sha256_passwordwas supplied, and the wrong SCRAM salt was sent whenscram_sha256_passwordwas not the last method. #115084 (Alexey Milovidov). - Fixed
THERE_IS_NO_COLUMN(Cannot find column in source stream) forSELECT DISTINCT expr(k) ... ORDER BY kon a table with an aggregate projection grouped onk. Closes #112168. #115147 (Groene AI). - A
textindex is now used forhasAnyTokens,hasAllTokens, andhasPhrasecalled with an explicit tokenizer argument when that argument denotes the same tokenizer as the index. Previously the three-argument form always fell back to a full scan. Closes #115275. #115348 (Groene AI). - Fix an exception in a window function over a
Tuplewith a sparse element, for examplegroupConcat(t) OVER (). #115705 (Alexey Milovidov). - Conversion between named tuples with disjoint element names is now positional instead of silently filling the result with default values, and aliases that only give names to tuple elements can now repeat without error, for example
SELECT tuple(1 AS x), tuple(2 AS x). #115717 (Alexey Milovidov). - Cancel in-flight merges, mutations, and part fetches during graceful server shutdown instead of waiting for the running step to finish. Previously a single slow merge step or a large part download could delay shutdown for its whole duration. #115733 (Alexey Milovidov).
- Fixed a
WHERE _table = ...orWHERE _database = ...condition over aMergetable silently returning no rows when the matching child table reads its data from other tables, for example aDistributed,Merge,Buffer, orAliaschild. Such children are now always read, and the condition filters their rows. #116371 (Alexey Milovidov). - Fix corrupted output when
framing_output_formatis used together withhttp_write_exception_in_output_format = 1(the default forcompatibilitybelow 25.11). Data packets after the first one repeated the bytes of the first packet padded with zeros, and the query failed withstd::length_error. This affected the Web UI, which reported a JSON parse error after the first few rows. #116620 (Alexey Milovidov). - Fix links between settings, functions, and section headings on the built-in
/docspage. References to other settings or functions did nothing when clicked, and#heading anchors put a corrupted section into the URL. #116635 (Alexey Milovidov). - Fixed an exception when reading from a table after
DETACHandATTACHof a partition with patch parts created by lightweight updates. #116695 (Anton Popov). - Fixed silently wrong results when reading a
Parquetfile whose offset index disagrees with the page data on anArray,Map, or nested column. Such a page is now rejected withINCORRECT_DATAinstead of returning another page’s values under the requested row numbers. #116788 (Groene AI). - Fix background cleanup of unused
store/directories on encrypted disks. ClickHouse can now revoke permissions and remove these orphaned directories instead of failing during cleanup. #116919 (Ivan Shelestov). - Fix
Native-protocol memory allocation from truncated input: server-declared sizes no longer make the client allocate memory for data that has not arrived; exception strings are read as they arrive, the decompressed block size is bounded, and the maximum number of rows in aNativeblock is now one billion. #117011 (Alexey Milovidov). - Fix the exception
max_rows > 0(and possible incorrect merge results in release builds) inMergingSortedTransformwhen an input delivers a trailing empty chunk together with end-of-stream, for example underoptimize_read_in_order. #117048 (Alexey Milovidov). - Internal queries derived from an existing
QueryPlannow preserve execution limits and shared resources instead of losing settings such asmax_threadsand concurrency control. #109722 (Groene AI). - Fix wrong results when an
Enum8orEnum16constant is compared with aStringorFixedStringcolumn. The constant was converted to the enum’s underlying number instead of its name, so primary-key andPARTITION BYpruning, thebloom_filterskip index,INandNOT INsets, and thevaluestable function could silently use the wrong value. Matching rows could be dropped,NOT INcould keep rows it should exclude, andINcould disagree with=on the same constant. #112647 (Groene AI). - Fix wrong
ORDER BYandDISTINCTresults, andCANNOT_CONVERT_TYPEfor aggregate functions, when reading aMergetable whose declared column type does not preserve the sort order of a source table’s type, for exampleUInt64over a source holding negativeInt64. #113242 (Groene AI). - Fix
minandmaxreturning a wrong value when the implicit_minmax_count_projectionanswered them from a part-level bound that is not a real row value:NULLin aNullablesorting key,NaNin a floating-point key, or aTuplebound assembled component-wise. Such a query now reads rows instead of using the projection. #115151 (Groene AI). - Fixed a settings-constraint bypass: a
SETTINGSclause inside a subquery, a CTE, or a view’s inner query was applied without checking the settings constraints, so it could leavereadonlymode or override aCONST,MIN, orMAXconstraint such asadditional_table_filters, breaking row-level isolation. Nested clauses are now clamped to the constraints instead. #115397 (Itamar Tempelhof). - Fix
enable_adaptive_aggregatorwithmax_rows_to_group_byinthrowmode: adaptive aggregation no longer silently falls back to the regular algorithm, and the merged total is now checked against the limit in parallel two-level aggregation, including bucket Top-K and spill-to-disk paths. #116451 (Nihal Z. Miaji). - Fixed wrong results and an exception in primary-key analysis for
intDivanddivideover aDecimalkey with an integer constant divisor that does not fit the decimal’s native width. Such a query could return no rows at all instead of the matching ones. #116608 (Groene AI). - Column names such as
inf,infinity,nan,true, andfalseare now quoted when formatted, so a sorting key that refers to them no longer writes metadata the server cannot parse on the next start. Previously the table, and with it the whole database, failed to load. #116802 (Alexey Milovidov). - Fix a server crash when creating a table whose columns form a long chain of
DEFAULTexpressions, such asc1 DEFAULT c0 + 1, c2 DEFAULT c1 + 1, .... Planning such a statement no longer exhausts the thread stack. #116978 (Groene AI). - Fixed a
ReplicatedMergeTreereplication queue getting stuck forever after a new replica was added by cloning an existing one. The queue could contain twoALTER_METADATAentries for the sameALTER, so subsequentALTERs waited indefinitely andSYSTEM SYNC REPLICAtimed out. #117107 (Alexey Milovidov). - Detect a column-count mismatch between a tuple and a subquery in the
INclause during analysis, preventing constant folding from silently hiding the error. #97540 (Alexey Milovidov). - Fix
LOGICAL_ERROR(Temporary part ... already added) whenOPTIMIZE ... DRY RUNruns concurrently with a real merge, or with anotherDRY RUN, on the same parts. #110916 (Groene AI). - Fixed a server startup crash when the background updater for dictionaries and executable user-defined functions applied an empty configuration before the first configuration repository was registered. #113238 (Groene AI).
- Fixed a data race and a use-after-free on the metadata of
DeltaLakeandIcebergtables. Concurrent queries readingtotal_rowsortotal_bytesfromsystem.tablesfor the same table could crash the server. Closes #113265. #113427 (Groene AI). - Fixed
arrayROCAUCandarrayAUCPR, and their aliasesarrayAUCandarrayPRAUC, returning a different result for the same data depending on the order of the array elements when a score wasNaN. ANaNscore now makes the resultNaN. Closes #104763. #115101 (Groene AI). - Fix
RESTOREof an incrementalS3backup chain whose locator authenticates by assuming a role withextra_credentials(role_arn = ...). The role identifiers are now kept in the<base_backup>locator of the backup metadata, so each backup in the chain can reopen its base; previously chains deeper than one level could not be restored at all. Chains already written without them can still be restored withuse_same_s3_credentials_for_base_backup = 1, except when the locator is a named collection. #116223 (Julia Kartseva). - Fixed missed insert deduplication when a block reaches the sink with sparse column representation, for example
INSERT ... SELECTfrom a part with sparse serialization. Such an insert did not deduplicate against the same data inserted seconds ago from unmerged parts. #116287 (Mikhail f. Shiryaev). - Functions
h3PolygonToCellsandh3PolygonToCellsWithContainmentnow check for query timeouts andKILL QUERYwhile covering a polygon, and reject vertices whose longitude is outside-180..180or latitude outside-90..90degrees. Previously a polygon with such a vertex could keep a thread busy for tens of minutes, ignoring both. Closes #116195. #116335 (Raúl Marín). - Fixed the exception
... to have 0 rows, but it has 1: while executing function materializewhen a dictionary withLAYOUT(DIRECT())is read through themergetable function. Closes #116269. #116378 (Groene AI). - Fix a
bloom_filterskip index returning fewer rows forINon anArraycolumn when the set contains an empty array, for exampleWHERE x IN ([]). Closes #116431. #116449 (Groene AI). - Fixed wrong results from search functions (
hasPhrase,hasToken,hasAnyTokens,hasAllTokens) on a text index whosepreprocessororpostprocessorusesINorNOT IN, such asif(token IN ('the'), '', token). The transform was silently ignored whenever the predicate was evaluated on rows instead of read from the index, so matching rows could be missing. Closes #116476. #116578 (Elmi Ahmadov). - Fixed a 404 (
S3_ERROR) when reading anIcebergtable through a path that is a parent of the table directory, with the metadata document named by theiceberg_metadata_file_pathsetting. Writes and maintenance operations on such a table are now refused instead of acting outside the table. Closes #116985. #117037 (Groene AI). - Fixed incorrect results from
sum(if(cond, 0, 1))whencondhas typeLowCardinality(Nullable(...))andoptimize_rewrite_sum_if_to_count_ifis enabled, which is the default. Rows where the condition wasNULLwere not counted. Closes #116938. #117046 (Pratham Nayak). - Fixed
clickhouse-clientandclickhouse-localnot emitting the--chimealert for a long-running query that ends with an error. The threshold was checked against the query time last reported by the server, which is not refreshed when a query fails, so it could be arbitrarily behind the real duration of the query. It is now checked against the time the client actually waited. #117179 (Alexey Milovidov). - Fixed a server crash when executing
ALTER TABLE ... MATERIALIZE TTLon a table that is not aMergeTreebut whose metadata carries a TTL. This can affectAliastables whose target has a TTL andMaterializedViewtables that declare a TTL on one of their own columns. Closes #117327. #117181 (Groene AI). - Fixed a
LOGICAL_ERRORin KQLtimespanparameter handling forLowCardinalityinterval arguments. #117162 (Groene AI). - Fix
temporary_files_buffer_sizeandformat_avro_schema_registry_*accepting out-of-range values that then made every subsequent query in the session fail with no way to recover. Such values are now bounded when set. Closes #113782. #113787 (Pedro Ferreira). - Fix
allow_feature_tierrejectingmerge_tree_-prefixed settings in settings profiles as unknown and rejectingCREATE TABLEbecause ofMergeTreesettings applied bycompatibilityor themerge_treeconfig section. Also fix constraints on amerge_tree_-prefixed setting being bypassed when the setting is written through its alias, and a statement that rewrites such a setting to its current value being refused by aCONSTconstraint. #113156 (Raúl Marín). - Fix a server crash and out-of-bounds write when inserting into a column with a long chain of compression codecs, for example
CODEC(FPC, FPC, ..., FPC). Such chains are now rejected withCANNOT_COMPRESS; chains longer than 255 codecs, which previously could write unreadable parts, are rejected up front withBAD_ARGUMENTSunlessallow_suspicious_codecsis set. #113877 (Groene AI). - Fix
OpenSSLcipherListbeing silently ignored when its value is written on its own line, as XML or YAML auto-formatters do. The configured value is now trimmed before it reachesOpenSSL, and an invalid cipher list is reported instead of discarded, so the server no longer keepsOpenSSL’s default cipher list while appearing to honor the configured restriction. Closes #115808. #116053 (Groene AI). - Fix a server crash in the
ReplicatedMergeTreecleanup thread whenmax_replicated_logs_to_keep = 0. That value is now rejected, matching the documented domain of the setting. #117147 (Groene AI). - Fix path traversal in
RESTORE: backup metadata entries whose<name>is not already normalized are now rejected withINSECURE_PATHinstead of being restored outside the part directory whileRESTOREreports success. #117371 (Groene AI). - Fixed memory leaks of abandoned nested aggregate states. #113926 (Groene AI).
- Preserve row counts above the signed 32-bit range on the
PostgreSQLwire protocol. #114397 (Minh Vu). - Fixed
ILLEGAL_COLUMNforARRAY JOINqueries filtered by an emptyINset, including an empty list and an emptySettable. Closes #116018. #116057 (Groene AI). - Fixed
Aliastables ignoring row policies defined on their target tables. AnAliastable now combines the row policies of both the alias and its target table. #116290 (Kai Zhu). - Fixed concurrent writes of the same
format_schema_source = 'string'or'query'schema being rejected withCANNOT_OPEN_FILEorATOMIC_RENAME_FAIL. #116502 (Groene AI). - Fixed
moduloOrNull,intDivOrNull,divideOrNull, andpositiveModuloOrNullreturning the raw division result instead ofNULLwhen dividing by a constant zero inside a subquery whose result is read or persisted by an outer query. Closes #116500. #116594 (Groene AI). - Fixed
Icebergpartition pruning when a manifest’s partition tuple contains fields ClickHouse cannot model. Such tables no longer fail withSTD_EXCEPTION, and a manifest whose tuple length disagrees with its own spec is now rejected withICEBERG_SPECIFICATION_VIOLATIONinstead of returning deleted rows. #116615 (Groene AI). - Fixed wrong results from
sumKahanandsumKahanIfwhen the aggregated batch does not start at the first row of the block, including window frames, parallelGROUP BY, andoptimize_aggregation_in_order = 1. #116990 (Groene AI). - Fixed
GenerateRandomreads with a trivialLIMITreturning no rows because the source-count reduction could overflow to zero. Absurdly large requested stream counts are now also rejected withPARAMETER_OUT_OF_BOUND. #117171 (Groene AI). - Fixed out-of-bounds access in
timeSeriesGroupArray. #117404 (Vitaly Baranov). - Fixed
GROUP BYemitting a group from a zero-row block, returning a row withcount() = 0. Closes #116830. #117503 (Yarik Briukhovetskyi). - Fixed
arrayIntersectwith mixedNullableand not-Nullablearguments. Such calls could fail or return spurious default-valued elements for some data types;arrayUnionandarraySymmetricDifferenceare unaffected. #117577 (Groene AI). ATTACH PARTITION FROM,REPLACE PARTITION, andMOVE PARTITION TO TABLEno longer accept a non-adaptive part whoseindex_granularitydiffers from the destination table’s. Previously such a part could return wrong row counts in release builds. Closes #117524. #117594 (Groene AI).- Fixed
max_joined_block_size_rows = 0(documented as unlimited) making a hash join emit one left row per output block instead of honoringmax_joined_block_size_byteswhen a left row has multiple right matches. Closes #102007. #117604 (Groene AI). - Fixed
hasColumnInTabledisclosing whether a column exists on the target of anAliastable when the user lacksSHOW COLUMNSon the target. The function now requires that privilege on the target too. #117621 (Groene AI). - Fix silent data loss when a TTL expression applies a large interval directly to a
DateorDateTimecolumn by widening the arithmetic away from 16/32-bit overflow. #101793 (BoloniniD). - Fix
Cannot insert field with type ...when inserting a row that omits anAggregateFunctioncolumn whose argument types containLowCardinality.defaultValueOfTypeNameis fixed for the same type names. #102403 (Enric Calabuig). - Fixed a privilege-escalation gap where the
executabletable function did not enforce theTABLE ENGINE ON Executablegrant. Withtable_engines_require_grantenabled, a user deniedCREATE TABLE ... ENGINE = Executablecould still run the same server-side script viaSELECT ... FROM executable(...). It now requiresGRANT TABLE ENGINE ON Executable, matchingCREATE TABLE. #109331 (Groene AI). - Fix silently wrong
GROUP BYresults withoptimize_aggregation_in_order = 1. Groups were merged into one another and aggregate values were wrong when the matched sorting-key prefix contained a reverse (DESC) column, and, independently of reverse keys, when a group-by key was a negative monotonic function of aFloatsorting-key column around theNaNboundary. This affected a singleMergeTreetable and aMergetable over such tables. For aMergetable whose underlying tables read the matched prefix in opposite physical directions, aggregation in order is now declined because a single stream direction cannot describe both. #112200 (Groene AI). - Fix
_path/_filefiltering for object storage,file, andurlreads. AGLOBAL INsubquery over_pathor_fileof a path without globs no longer throwsNot-ready Set is passed as the second argument for function 'globalIn'; an explicitly named archive member is filtered before the archive is opened;Hivepartition columns are inferred for an explicitly named key that does not exist; andurlCluster/fileClusternow prune a filtered-out path on the initiator instead of handing it to a replica. #112968 (Alexey Milovidov). FileLogtables no longer silently skip files that appear afterCREATE TABLE. The directory watch ran as aBackgroundSchedulePooltask but never returned, so it held its slot of the per-task-type budget forever; oncebackground_schedule_pool_sizetimesbackground_schedule_pool_max_parallel_tasks_per_type_ratiotables existed, further tables never watched their directory at all andSELECTreturned fewer rows instead of erroring. The watch now runs on its own thread. #113897 (Groene AI).- A query queued on a full distributed connection pool now responds to
KILL QUERY, and tomax_execution_timeat the defaulttimeout_overflow_mode = 'throw', instead of waiting until another query happens to release a connection, and a positiveconnection_pool_max_wait_msnow actually expires. Previously the wait ended only on success at every value of the setting, so the configured timeout was ignored,max_execution_timewas reported long after its deadline, and the query could not be killed. The wait applies per replica, so an expired one is a soft failure that fails over to the remaining replicas and only then reportsALL_CONNECTION_TRIES_FAILED. #113979 (Groene AI). - Fix wrong results when a filter on a
JSONsubcolumn that mixes a literal prefix with a quoted path segment is analyzed against aJSONAllPathsskip index. The subcolumn name was misparsed, so all granules were skipped and the query returned fewer rows than it should. #114873 (Pavel Kruglov). - Fix wrong results when a
SELECTwithselect_sequential_consistency = 1on aReplicatedMergeTreetable runs with classic (task-based) parallel replicas. Every replica performed a complete local read clamped to the quorum boundary instead of a coordinator-assigned slice, so rows were returned once per participating replica. #114945 (Groene AI). - Fixed
CREATE DICTIONARYfailing withIncorrect type of ID column: must be UInt64, but it is LowCardinalitywhen the simple primary key is declared asLowCardinality(UInt64)anddictionary_validate_primary_key_typeis enabled. Closes #104539. #115139 (Groene AI). - Fix a hang in workload memory reservations when an increase races with an in-flight decrease. #116085 (Azat Khuzhin).
- A
Kafkatable withkafka_keeper_pathset (StorageKafka2) no longer skips messages it had already consumed when a streaming cycle fails part-way through; previously those messages were never delivered to the materialized views and a later cycle committed an offset past them. As a consequence, with the defaultkafka_handle_error_modean unparseable message now blocks the table instead of being silently skipped, matchingStorageKafka.kafka_handle_error_mode = 'stream',kafka_handle_error_mode = 'dead_letter_queue', andkafka_skip_broken_messagesremain the ways to skip such a message. #116485 (Groene AI). - Fixed the
Unexpected return type from materializelogical error when reading a column that has atextindex through the index after a metadata-only or not-yet-materializedALTER MODIFY COLUMN(including lazyJSONtype hints) that requires a read-time type conversion. #116549 (Pavel Kruglov). - A table created with
CREATE TABLE ... AS <table function>(...)is no longer resolved to answer aSYSTEM STOP-family lock query or asystem.tablessize query about it. Previously those statements contacted the endpoint of every such table, so one unreachable endpoint made them fail or stall. Until such a table is first accessed it now reportsNULLsizes and an emptydata_paths, andDROP TABLE ... IF EMPTYremoves it instead of reportingTABLE_NOT_EMPTY. #116774 (Groene AI). - Fixes wrong results when a
minmaxskip index,ORDER BY, orPARTITION BYis built over anArray,Tuple, orMapholding aBool, such asArray(Tuple(Float64, Bool))orMap(String, Bool), and when aminmaxindex serves anORDER BY ... LIMITover aBoolcolumn. Previously, rows that the predicate accepts could be dropped, because the stored bound and the value compared against it represented the boolean differently. #116897 (Groene AI). - Fixed an external
GROUP BYexceedingmax_memory_usagewhenenable_adaptive_aggregatoris on. Intermediate data the adaptive aggregator held and could not release kept a thread on the baseline algorithm flushing its own hash table on every block, so each block wrote a temporary file and the merge then allocated a reader per file. That data is now written out first. #117326 (Groene AI). - Malformed
Nativeblocks can no longer overflow the allocation of aggregate-function states during deserialization and cause out-of-bounds writes. #117370 (Raúl Marín). - Fixed the byte width of the
Icebergmanifestlower_boundsandupper_boundswritten forintanddatecolumns: they were 8 bytes wide where theIcebergspecification requires 4. Spec-conformant readers such aspyicebergfailed withunpack requires a buffer of 4 byteswhile planning any scan carrying a filter on such a column. #117571 (Groene AI). - Remote-write async insert flush timeouts are now handled correctly: they return retryable
503 Service Unavailableinstead of408 Request Timeout, so Prometheus-compatible senders can retry them, andwait_for_async_insert_timeoutis now clamped instead of overflowing for large magnitudes. #117632 (Vitaly Baranov). #118040 (Groene AI). - Fixed
base58Encodeandbase58Decodeof 32- and 64-byte values on big-endian builds such ass390x. The fixed-size codec byte-swapped every 4-byte word unconditionally, so on a big-endian hostbase58Encodereturned a string that disagrees with the base58 specification and with every other architecture, andbase58Decoderejected well-formed input when given a 32- or 64-byte size hint. Little-endian builds are bit-identical to before. Strings previously produced by a big-endian build will change, because they were wrong. #117649 (Groene AI). - Fixed
format_schema_source = 'query'running the schema query with full privileges when used from a background task, such as a streaming engine consumer (Kafka,NATS,RabbitMQ,ObjectStorageQueue) or aBufferbackground flush. The schema query is now rejected there; useformat_schema_source = 'file'orformat_schema_source = 'string'instead, or pre-populate the schema cache. #117737 (Pavel Kruglov). - Fix
absentandscalarPromQL queries returning no result whenempty_result_for_aggregation_by_empty_setis enabled. #117816 (Valery Petrov). - A
bloom_filterindex over anArray(Nullable(T))column is now rejected atCREATE/ALTERtime. It used to be accepted and then made every insert, merge, and mutation of the table fail, withDROP INDEXrefused until the failed mutation was killed. #117899 (Alexey Milovidov). - Fix the
GROUPINGfunction rejecting constant aliases that are validGROUP BYkeys. #97504 (Héctor Pablos). - Fixed SQL injection in the
PostgreSQLwire protocol emulation. Prepared-statement parameters, in both the extended-queryParse/Bind/Executepath used bypsycopg2, JDBC,node-postgres, Npgsql, and others, and the simple-queryEXECUTEpath, were substituted into the executed SQL by raw string splicing, so a crafted parameter could break out of its value position and inject SQL. Parameters are now bound as data. This also fixes string parameters that previously failed withUNKNOWN_IDENTIFIERwhen a client sent them unquoted. #108469 (Groene AI). - Fix a
LOGICAL_ERROR(Part ... intersects previous part ... It is a bug or a result of manual intervention) that makes aMergeTreetable impossible to load: attaching it, and every later attempt to load it, fails with that exception, and debug and sanitizer builds abort. A merge could span a block gap holding an outdated part whose mutation version is higher than the merge result’s, producing a pair of parts on disk that neither contain nor are disjoint from each other. Closes #113864. #113941 (Groene AI). - Fix a
LOGICAL_ERROR: Next task callback is not set for query with idexception whenparallel_replicas_plan_basedis enabled and the query reads a system log table. #114022 (Groene AI). - Fix
files_readandbytes_readinsystem.backupsandsystem.backup_logbeing permanently undercounted after a successfulRESTORE, because a concurrent restore task holding an early snapshot could overwrite a larger count published by another task. #114304 (Groene AI). - Fix wrong results when a non-boolean condition, such as a bare integer column in
WHERE, is left alone after the other conditions are merged into theJOINcondition or pushed down. Rows whose condition value was a non-zero multiple of 256 were skipped. #114533 (Vladimir Cherkasov). - Fixed a single
ALTERwith twoMODIFY COLUMNsubcommands on the same column silently corrupting that column’s default: a default set by one subcommand was dropped, and aREMOVE DEFAULT/MATERIALIZED/ALIASwas undone, whenever a following subcommand restated the column type. #114807 (Groene AI). - You can now access nested properties on a
Nullable(JSON)value, for examplecol::Nullable(JSON).Id. Previously this failed withFirst argument for function tupleElement cannot be Nullable(JSON), which made it impossible to combine a cast toNullable(JSON)with property access on the result. OuterNULLrows now propagate through extracted paths using the existing subcolumn semantics: paths whose type can representNULLreturnNULL, while types such asArrayandMapreturn their default values. #114863 (Luís Lizardo). - Fix an integer overflow in the deserialization of
Stringvalues in the binary formats, and bound the recursion of the binary deserialization ofDynamicandJSONvalues. #115702 (Alexey Milovidov). PostgreSQLcompatibility now handlespg_catalogqualifiers case-insensitively like PostgreSQL does, and the synthetic OIDs exposed throughpg_namespaceandpg_classare now unique, sopsqlcommands such as\dno longer duplicate tables or list them under the wrong schema. #115960 (Alexey Milovidov).- Fixed data loss in
MergeTreewhen a merge runs while anALTER TABLE ... RENAME COLUMNis still pending. The merge applied the rename but did not record it, so the mutation applied it a second time and read the renamed column as missing, filling it with defaults. Columns without a default expression, such asDynamic, lost their values. #115981 (Alexey Milovidov). - Fixed a query over an
Icebergtable returning fewer rows than the table holds when a manifest declares a lower bound above the upper bound for a filtered column. Such a pair describes an empty range, so min/max pruning dropped the data file holding the matching rows; those bounds are now ignored instead. Closes #116499. #116604 (Groene AI). - Fixed two
Binary Viewer(/binary) bugs: the image was not centered on load if the URL contained parameters such asuser, and the connection parameters (host,user) were lost from the URL after moving the view. Thepasswordparameter is no longer kept in the address bar or browser history. #117065 (Alexey Milovidov). - Fix a large performance regression, present since 26.5, for a query that filters on a column with an equality and orders by a later column of the same sorting key. Read-in-order analysis did not look through an
ALIASnode on the filter column, so the filtered column was not recognized as constant and the read was not done in order, forcing a full sort of every matching row before theLIMITapplied. This reaches a table with a normalPROJECTION, whose rewrite wraps the query filter in such an alias, and a table-levelALIAScolumn used as a predicate. #116854 separately made a base table that can serve theORDER BYitself preferred; this fixes the case where only the projection can. #116835 (Groene AI). - Fixed wrong results when reading the
.nullsubcolumn of a column that went through a metadata-onlyTtoNullable(T)ALTERand then had aRENAME COLUMNstill pending:IS NULL,IS NOT NULL,count(), and an explicitx.nullread reported rows holding real data asNULL. #116901 (Groene AI). - Fixed a stack overflow when reading hadoop-snappy data containing many blocks that decode to nothing. #116994 (Alexey Milovidov).
- The handshake response of the
MySQLwire protocol is now bounded, so a client can no longer make the server grow memory during the handshake. Themysql_require_secure_transportserver setting is now enforced from the actual state of the connection instead of a capability bit advertised by the client. #117003 (Alexey Milovidov). - Fix background
Distributedinserts that deleted unsent spool files after a split batch got a transient error. ClickHouse now keeps the files and retries the batch. #117034 (Rory Shanks). - Fix wrong results for
GROUP BYanduniq*overMACNumToString,unhex,unbin, andUUIDStringToNum. All four declared themselves injective, so the default-enabledoptimize_injective_functions_in_group_byandoptimize_injective_functions_inside_uniqgrouped and counted by the raw argument: arguments that map to the same result came back as separate groups and were counted separately byuniqExact. #117210 (Alexey Milovidov). - Fix wrong results from the default-enabled
optimize_uniq_to_count.uniq(x)over aSELECT DISTINCT xorGROUP BY xsubquery reported one distinct value too many when the column contained aNULL, and counted the extra super-aggregate rows ofWITH ROLLUP/WITH CUBEas additional distinct values. #117222 (Alexey Milovidov). - Fix
NO_SUCH_COLUMN_IN_TABLEfor every query using a text index while a mutation is pending withapply_mutations_on_fly = 1. Until the mutation materialized,hasToken,hasAnyTokens, andhasAllTokenson the indexed column could not be executed at all. #117277 (Alexey Milovidov). - Several aggregate function deserializers allocated memory from a size declared in the serialized state before reading the payload, so a state of a few bytes could request gigabytes. They now read only what the buffer already holds. #117536 (Groene AI).
getServerSetting,getMergeTreeSetting, andgetMacroreturned the values ofsystem.server_settings,system.merge_tree_settings, andsystem.macrosto any user, bypassing theSELECTgrant that reading those tables requires. They now require the same grant. #117551 (Raúl Marín).- Fixed a bug where the
analyzer_inline_viewssetting could bypass theSELECTaccess check on a view, letting a user without a grant on the view read its contents. #117555 (Dmitry Novik). ENGINE = EmbeddedRocksDB(ttl, rocksdb_dir, read_only)with an explicitrocksdb_dirnow requires theFILEsource grant thatfilerequires for the same directory:READ ON FILEto create such a table, plusWRITE ON FILEwhenread_only = 0. Previously it required no source grant, so a user holding onlyCREATE TABLEin a database of their own could point a table at another table’s directory and read its rows.ON CLUSTERandReplicated-database DDL are not covered: the replay runs with no user. The argument-less form is unaffected. Backward incompatible for anyone already using an explicitrocksdb_dirwithout them. #117428 (Groene AI). #117665 (Pedro Ferreira).- Fix
ALTERandCREATE TABLE ... ASdropping the other settings of aTimeSeriestable. #117693 (Vitaly Baranov). #117839 (Vitaly Baranov). #118119 (Alexey Milovidov). - Fix incorrect results for suffix
LIKEpatterns with escape sequences whenoptimize_rewrite_like_perfect_affixis enabled. Such patterns are now rewritten toendsWithonly when the suffix is an exact literal. #117712 (Alex Prabhat Bara). - Fix a dictionary with a
Redissource and anInt256key column silently returning the default value fromdictGetfor keys that exist inRedis. Wide integer key columns are now refused with a clear error instead of being admitted and never matching. #117735 (Pratham Nayak). - Fixed excessive memory usage when reading from
File,URL, object storage,GenerateRandom, or any other storage that uses the generic read path withmax_streams_to_max_threads_ratioabove 1. The number of output ports created after a read is now bounded bymax_threads, so aSELECTover a tiny table no longer allocates tens of gigabytes while the pipeline is still being built. #117772 (Alexey Milovidov). - Fix
ARRAY JOINproducing rows in incorrect order in some cases. #117918 (Yarik Briukhovetskyi). - Fix a potential out-of-bounds write in
formatDateTimeInJodaSyntaxwhen called with a time zone name longer than 32 characters. #117925 (Robert Schulze). - Fix
EXPLAIN QUERY TREEandEXPLAIN SYNTAXexposing column names and types of tables the user has no privileges for: the analyzer now checks that the user may see at least one column of the table at the moment a table identifier is resolved. The check also makes the error kind independent of whether the queried column exists and stops recording column names the user may not see intomissing_privilegesof the query log. Closes #78938. #117979 (Alexey Milovidov). - Fixed Keeper aborting when memory usage stays near the limit: moving finished changelogs and snapshots to object storage was refused, so the local log disk filled up. #117983 (Shaohua Wang).
- Fixed a
Kafka/RabbitMQ/NATS/FileLog/S3Queue/AzureQueuetable in a database withlazy_load_tablessilently stopping to feed its materialized views after a server restart. #118009 (Alexey Milovidov). - Fixed cancellation of a synchronous distributed
INSERT(distributed_foreground_insert) waiting for thatINSERTto finish instead of interrupting it.KILL QUERYagainst such an insert, a client disconnect, and server shutdown could block for as long as a shard was slow. #118013 (Groene AI). - Fixed a
LIMITbeing pushed intonumbers()when the query’sWHEREreferenced anarrayJointhrough aWITHalias, which could make the source stop before the expansion produced enough rows. #118045 (Yarik Briukhovetskyi). - Fix
Icebergschema evolution for additional nestedArray,Map, andStructcombinations whose inner fields are added, removed, or reordered. #118127 (Konstantin Vedernikov). - Fixed incremental backups to Azure Blob Storage storing the beginning of each file instead of its tail. Restoring such a backup silently dropped all the data written after the base backup. #114975 (Smita Kulkarni).
- Fixed potential data loss when an
INSERTintoReplicatedMergeTreewas cancelled or timed out while ClickHouse was recovering an uncertain Keeper commit. #111196 (kakao-tars-case). - Fixed object storage listing silently skipping objects when S3 returns an empty page together with a continuation token. This could make a
plain_rewritabledisk appear empty and hide table parts, and could make data lake tables read a stale snapshot. #118615 (Sema Checherinda). - Fixed a SQL injection in the PostgreSQL metadata queries. The
schemaof thePostgreSQLdatabase engine, the requested column names and the publication name were formatted into SQL literals without escaping, so a value containing a quote could execute arbitrary SQL on the connected PostgreSQL server as the role ClickHouse connects with. Reaching it throughschemaneeded onlyCREATE DATABASEplus use of a named collection whoseschemais overridable. #111516 (Shaohua Wang). - Hide the credentials that a setting value can carry, such as the password in
format_avro_schema_registry_urlorurl_base, everywhere a setting value is displayed or logged.system.query_log,system.processes,system.settings,system.settings_profile_elements,system.session_log,system.distributed_ddl_queue,SHOW CREATE USERandSHOW CREATE SETTINGS PROFILEpreviously showed them in plaintext to any user who could read them. #117523 (Raúl Marín).EXPLAINnow respectsformat_display_secrets_in_show_and_selectas well. #118129 (Kirill Kopnev). CREATE USER OR REPLACEand theOR REPLACEform ofCREATE ROLE,CREATE QUOTA,CREATE SETTINGS PROFILEandCREATE ROW POLICYnow require the correspondingDROPprivilege in addition toCREATE, because they overwrite an existing entity. PreviouslyCREATE USERalone was enough to reset the password of any other user, including a privileged one. #117960 (Alexey Milovidov).- Fix
CREATE OR REPLACE TABLE/VIEW/DICTIONARYandREPLACE TABLErequiring privileges on the internal temporary table they create (_tmp_replace_*). Its name is random, so no grant could cover it and the query failed withACCESS_DENIEDunless the user held wildcard grants on the whole database. The required privileges are now checked against the user-visible names only: replacing an object needs theCREATEandDROPgrants of its own kind, plusINSERTon it when the statement populates it. #117967 (Alexey Milovidov). TRUNCATE DATABASE ... ON CLUSTERandTRUNCATE [ALL] TABLES FROM ... ON CLUSTERran without checking any privilege: a user holding onlySELECTandCLUSTERcould destroy every table in a database, andreadonly = 1did not prevent it. Both now requireDROP DATABASE, the privilege the non-cluster spellings have always required. #118155 (Groene AI).- Fixed a privilege escalation in implicit access-rights computation: holding any single child privilege of the
ALTER TABLEgroup (for exampleALTER MODIFY COMMENT) on a view implicitly conferred the entireALTER VIEWgroup, so such a user could runALTER TABLE <view> MODIFY QUERYand rewrite the view’s query.ALTER VIEWis now implied only by the completeALTER TABLEgrant. A deployment that relied on a partialALTER TABLEgrant to alter views must now grantALTER VIEW(or one of its members) or the fullALTER TABLEexplicitly. #118194 (Groene AI). - Expressions supplied through the
additional_table_filtersandparallel_replicas_custom_keysettings are now subject to the column-levelSELECTcheck, and are no longer injected into the body ofSQL SECURITY DEFINERorNONEviews. Previously a user could evaluate predicates over columns they were not granted. #118063 (Dmitry Novik). - Forbid
CREATE TABLE ... AS viewIfPermitted(...), includingviewIfPermittednested in another table function such asremote, which now fails withBAD_ARGUMENTS, as it already does forevaland the*Clustertable functions. The function chooses between itsSELECTquery and theELSEfunction according to the current user, but a persisted table is resolved with no user and therefore full access: reading one reported the source table’s column names and types to a user with no grant on it, and theELSEfallback was unreachable. Tables created before this change keep loading; drop them to close the disclosure. #116885 (Groene AI). - Fixed a
Filesystemdatabase serving a table from its internal cache without theREAD ON FILEgrant. The grant was checked only while a table name was resolved for the first time, so once any user holding it had read a name, every user withSELECTon the database was served the contents of the file.EXISTS TABLE, which requires onlySHOW TABLES, answered from that cache and probed the directory without the grant too. Both now require it, and a user without it is refused before the existence of the file is observed. #119029 (Groene AI). - Apply
remote_url_allow_hostsbefore SQL-supplied S3 and Azure endpoints send schema, metadata, or container requests. #114357 (Rory Shanks). - Fixed the server deserializing the payload of a
Datapacket that arrives on a connection before any query. In interserver mode the connection is not authenticated until theQuerypacket is processed, so such a packet was rejected only after its Native block had been read, which let an unauthenticated peer choose the column type the server constructed. The packet is now rejected before its payload is touched. #118588 (Groene AI). - Each code for a time-based one-time password is now accepted at most once, as required by RFC 6238: reusing an already used code, or a code for an earlier time step, is rejected. A user with
time_based_one_time_passwordcan successfully authenticate at most once perperiod. #117563 (Vladimir Cherkasov). - Fixed wrong results when
join_algorithm = 'parallel_hash'is combined with a sorted consumer such asoptimize_aggregation_in_order,optimize_distinct_in_orderorLIMIT BY. With several join slots and a single-level hash map the join does not keep the order of the left table, so the read-in-order-through-join optimization must not advertise the left sort order in that case. #109225 (Groene AI). - Fixed a
LOGICAL_ERROR(Join is supported only for pipelines with one output port) raised by a mergeJOINwhen its two sides reached the join with a different number of output ports. #109393 (Groene AI). - Fix wrong results when a doubly negated expression is compared with a constant, such as
WHERE (NOT NOT c) > -0.5. Index analysis cancelled the twoNOTs and compared the column itself with the constant, pruning parts, granules and partitions that do match. #116381 (Alexey Milovidov). - Fixed wrong results after
ALTER TABLE ... MODIFY ORDER BYon a table with a descending sorting key column (ORDER BY a DESC). TheALTERsilently dropped theDESCdirection while existing parts stayed physically sorted the old way, so primary key index analysis pruned the wrong granules and queries returned missing rows. Such anALTERis now rejected. #116473 (Groene AI). - Fix the
Invalid status NotActive for associated outputlogical error that could happen for queries with a highmax_threads, for example aGROUPING SETSaggregation over a remote table. #116478 (Alexey Milovidov). - Fixed reading uninitialized memory as literal data when decompressing a malformed
LZ4-compressed block. #116992 (Alexey Milovidov). - Fix silently missing rows for a predicate on
toMillisecond,toMicrosecondortoNanosecondof aDateTime64primary key. All three claimed to be monotonic everywhere, although they restart at zero every second, so primary-key analysis treated the predicate as one contiguous key range and pruned granules that contain matching rows. #117246 (Alexey Milovidov). - Fix wrong row counts from the default-enabled
query_plan_merge_filter_into_join_conditionwhen an equality conjunct of theWHEREfilter contains a non-deterministic function such asrand(). The conjunct was moved into the join condition, where it is evaluated once per join input row instead of once per output row, and cloned into the build-side runtime filter as a second evaluation site. #117247 (Alexey Milovidov). - Fix the default-enabled
query_plan_merge_expression_into_joinreturning rows that violate the query’s ownJOIN ONcondition when a subquery computes a non-deterministic expression that is then used as a join key. The merged expression was computed twice from the raw inputs, drawing independently for the match and for the output column. #117250 (Alexey Milovidov). - Fix the default-enabled
use_join_disjunctions_push_downsilently dropping rows when the filter above a join hides a non-deterministic function inside a lambda body, as inarrayExists(z -> rand(z) % 2 = 0, [a]). The extracted pre-filter was pushed below the join while the original filter stayed on top, so the lambda was drawn twice per row and only rows passing both draws survived. #112700 (Groene AI). - Fixed a filter containing a non-deterministic function being moved below
ARRAY JOIN, which evaluated it once per source row instead of once per expanded row and made whole arrays pass or fail together. #117756 (Alexey Milovidov). Fixedrand,generateUUIDv4and other non-deterministic functions being evaluated before anarrayJoinreplicates the rows, which silently duplicated their values across the expanded rows. #118963 (Alexey Milovidov). - Reject a
CHECKconstraint whose expression containsarrayJoin. Such a constraint was accepted and then read past the end of the inserted block, surfacing as a nonsensicalArray of size 18446744073709551613 is too large, or an abort in a debug build, or blamed a violation on the wrong row. #117267 (Alexey Milovidov).arrayJoinin a table constraint is now also rejected when the definition is copied byCREATE TABLE ... AS srcorCLONE AS src, stated by a full-definitionATTACH, or declared asASSUME. A constraint containing it that is already stored in the metadata of a table is no longer used by the query-time constraint optimizer, which could remove aWHEREthat the constraint did not really imply. #117799 (Alexey Milovidov). - Reject a TTL expression that contains
arrayJoin. Such a TTL was accepted and then silently deleted rows whose own TTL was far in the future, and read past the end of the expression column when an array was empty. #117266 (Alexey Milovidov). - Fix a silent result change for a query over a trivial view over a
Distributedtable whoseWHEREor view-keyedadditional_table_filterscontains a bareIN some_tablepredicate. The default-enabledoptimize_trivial_view_pushdown_to_distributedshipped that predicate to the shards, where it was evaluated against each shard’s local table of that name instead of the initiator’s, so it disagreed with theIN (SELECT ...)spelling of the same predicate. #117278 (Alexey Milovidov). - Fixed
query_plan_aggregation_bucket_top_ksilently dropping result rows when anarrayJoinsits between the aggregation and theORDER BY ... LIMIT. #117464 (Alexey Milovidov). - Fixed
SELECT ... FINALwith aWHEREon the partition key expression returning a superseded row when the partition key is computed from a floating-point sorting-key column: partition pruning dropped the partition holding the deduplication winner. #117509 (Alexey Milovidov). - Fixed
mutations_sync = 3,lightweight_deletes_sync = 3andalter_sync = 3performing no wait at all onReplicatedMergeTree, so a mutation orALTERreturned as if it had synchronised. As documented, the value now behaves the same as2and waits for all replicas. This also affectsOPTIMIZE,TRUNCATE,DROP/DETACH PARTITION,REPLACE PARTITIONandMOVE PARTITION TO TABLE, which take the samealter_syncwait path. Statements that previously returned immediately now wait, and can raiseUNFINISHEDwhen a replica is inactive; set the value to0,1or2to choose a different wait explicitly. #117517 (Groene AI). - Fixed the logical error
Cannot add ZooKeeper operation because query is executedwhen runningTRUNCATE TABLEon aTimeSeriestable in aReplicateddatabase. #117902 (Raúl Marín). - Fix a lightweight
UPDATEsilently not applied to rows of a data part when the patch part is written in thev1format (patch_parts_version = 'v1') and covers rows of several data parts. One row was lost when a data part’s patch rows began in a later granule of the patch part, which made the result depend onmerge_tree_min_read_task_sizeandmax_block_size. All updates for a data part were lost, on disk as well as at read time, when the patch part had no final mark (index_granularity_bytes = 0) and that part’s patch rows began in the patch part’s last granule. #117962 (Groene AI). - Fix wrong results and a
NOT_IMPLEMENTEDexception when a lightweight update’s patch part is applied on top of a pendingALTER TABLE ... UPDATE col = <constant>withapply_mutations_on_fly = 1. The constant-folded column was not materialized before the patch was written into it, so the patch was either silently discarded or the read failed. #118545 (Shaohua Wang). - Fixed
system.tables.total_rows/total_bytesovercounting a non-replicatedMergeTreetable while a patch part from a lightweightUPDATEis alive, andSELECT count()returning that inflated number withapply_patch_parts = 0. #117463 (Alexey Milovidov). - Fixed a query with a
hasToken-family predicate on atextindex silently returning no rows when the query also read a column modified by a pending lightweight update. #118496 (Shaohua Wang). - Fix excessive patch-part reads for lightweight updates on tables with redundant parentheses in sorting-key expressions, such as
ORDER BY (k). #118878 (Anton Popov). - Fixed the
LOGICAL_ERRORReading from materialized CTE '...' before its materialization completedraised by a lightweightUPDATE, or a lightweightDELETEinlightweight_update_forcemode, whose predicate contains anINsubquery that defines a materialized CTE, when the set is built at run time. #119489 (Dmitry Novik). - Fixed a retried
INSERT SELECTover a join not being deduplicated when the two attempts differed only in whether a column was carried as a lazily replicated column. #118004 (Alexey Milovidov). - Fixed a logical error
Cannot write to finalized buffer(an abort in debug and sanitizer builds) in the non-replicatedMergeTreededuplication log when opening the next log file during rotation failed, for example after a transient I/O error on the deduplication log’s disk. Such a failure no longer fails the insert that triggered the rotation, so a retry of that insert is not wrongly deduplicated. #118089 (Alexey Milovidov). - Fix silent data loss on upgrade in
Distributedbackground inserts withbackground_insert_split_batch_on_failure: batch recovery no longer deletes a spool file that was never sent when a later file of the same batch was quarantined intobroken/by a previous server version. #118211 (Alexey Milovidov). - Fixed
SELECT count()returning too many rows for a negated comparison (!=,NOT IN,NOT LIKE) over aNullableprimary key column: the exact-count optimization counted the NULL-key rows that theWHEREcondition rejects. #118214 (Alexey Milovidov). - Fixed
AMBIGUOUS_COLUMN_NAMEon every read of a table that has a column named like a subcolumn of another column (for examplea.size0next to anArraycolumna) afterALTER TABLE ... MODIFY COLUMNchanged that column’s type. #118228 (Alexey Milovidov). - Fix unbounded memory growth from time zone names of the form
Fixed/UTC±HH:MM:SS. Every distinct name permanently cost ~4.6 MiB that the server never gave back, and 172801 of them were accepted. Only offsets that a time zone can have are accepted now: a whole number of quarters of an hour, no further from UTC than 14 hours. #118286 (Alexey Milovidov). - Fixed
MULTIPLE_EXPRESSIONS_FOR_ALIASunderrewrite_in_to_joinfor a query that repeats one identical aliasedIN (subquery)expression more than once. #118292 (Alexey Milovidov). - A table created with
CREATE TABLE ... AS <table function>(...)is no longer resolved to answer asystem.columnssize query about it. Previously selectingdata_compressed_bytes,data_uncompressed_bytesormarks_bytescontacted the endpoint of every such table, so one unreachable endpoint made the whole scan fail. Until such a table is first accessed it now reports zero sizes. #118302 (Groene AI). - Fixed an
Inconsistent AST formattinglogical error for an aliasedINexpression whose left operand also has an alias when it is nested inside a function-argument list, e.g.SELECT ifNull(sum((x AS a1) IN [y] AS c3 = TRUE), 0). #110229 (Groene AI). - Fix a logical error (server abort in debug/sanitizer builds) when a constant-folded comparison appears in the
SELECTlist together withgroup_by_use_nulls = 1andGROUP BY GROUPING SETS. #110703 (Groene AI). Fixed aBad casterror, and wrong results in release builds, when an aggregate reads a derived table that usesGROUP BY ALLwithROLLUPorCUBEundergroup_by_use_nulls = 1. #110921 (Groene AI). Fixed a return type mismatch error whengroup_by_use_nullsis used withGLOBAL INin aGROUP BYkey. #116980 (George Larionov). - Fixed a
LOGICAL_ERROR(“query tree node does not have valid source node”) when aMergetable wrapping aDistributedtable is joined and a bare column of the joined-away side is used as a predicate. #111327 (Groene AI). - Fixes a
LOGICAL_ERROR(Column identifier ... is already registered), aMULTIPLE_EXPRESSIONS_FOR_ALIASerror and aNOT_FOUND_COLUMN_IN_BLOCKerror for a query whoseIN/NOT IN/GLOBAL INright operand names a table expression that also appears in theFROMsection, for exampleSELECT l.x FROM l JOIN (SELECT x FROM r) AS r ON l.x = r.x WHERE l.x IN r. Also makesORDER BY <alias> WITH FILL ... INTERPOLATE (<alias> ...)inside a CTE or any other copied subquery raiseINVALID_WITH_FILL_EXPRESSION, as the same query already does when it is not copied: the check was silently skipped for the copy, and such a query returned rows instead of the error. #112219 (Groene AI). - Fixes
NOT_FOUND_COLUMN_IN_BLOCKwhenquery_plan_join_shard_by_pk_ranges = 1is combined withjoin_algorithm = 'full_sorting_merge'and a join input is filtered on a sorting-key column that is not the join key and is not selected. Closes #112402. #112664 (Groene AI). Fixed rows being silently dropped from a join whenquery_plan_join_shard_by_pk_rangesis enabled and the primary key is a floating-point column containingNaN. #118918 (Alexey Milovidov). - Fixed
Code: 476(Can not use WITH TIES without ORDER BY) raised by a remote shard, and the logical errorLIMIT WITH TIES without ORDER BYraised on the initiator, when selecting from aMergetable over aDistributedtable with aJOINandORDER BY ... LIMIT n WITH TIES. The child query kept itsLIMITclause after itsORDER BYwas removed. #113594 (Groene AI). - Fixed
LOGICAL_ERROR: There are no events in epollwhen a distributed query withuse_hedged_requestsis cancelled or completes early (for example because of aLIMIT) while a replacement replica is still pending. Closes #113981. #114065 (Groene AI). - Fixed
... PARTITION <value>statements against a table whosePARTITION BYcontainsmodulowith an unsigned left operand and a signed right operand, such asPARTITION BY (37528 % c0)withc0 Int32. Such a statement raisedLOGICAL_ERROR, or silently affected no partition. A value outside the range of the partition key type is now rejected withARGUMENT_OUT_OF_BOUNDinstead of silently matching nothing. #116606 (Groene AI). - Fix
BAD_ARGUMENTSfor a query that combines severalquantilecalls where at least one level is written as an integer literal, for exampleSELECT quantile(1)(x), quantile(0.5)(x). The default-enabledoptimize_syntax_fuse_functionsrejected the integer level while the aggregate function itself accepts it, so the query failed although each call is valid on its own. #117211 (Alexey Milovidov). - Fixed wrong results for
GROUP BY,LIMIT BYanduniq*overbech32Encode,dictGetHierarchyandreverseUTF8: the three functions declared themselves injective, so the default-enabledoptimize_injective_functions_in_group_byandoptimize_injective_functions_inside_uniqgrouped and counted by the raw argument, although distinct inputs can produce the same result. #117239 (Alexey Milovidov). #117357 (Alexey Milovidov). #118432 (Alexey Milovidov). - Fix
has,indexOfandcountEqualover an array of numbers returning a match for a needle thatequalsdoes not consider equal:has(arr, -1)matched anArray(UInt64)element equal to theUInt64maximum, andhas(arr, 16777217)matched anArray(Float32)element equal to16777216. The constant-array path already answered correctly, so the same haystack gave different results depending on whether it was a constant or a materialized column. The same phantom matches were returned for anArray(LowCardinality(T))column, which also matched a needle its element type cannot represent outside the numeric domain and reported every element equal to the default value as a match for aNULLneedle. In the other direction, a needle counting a different unit than the element, such as aDateTimesearched in anArray(Date), was found nowhere althoughequalsconsiders the pair equal; such a pair is now compared in the type the two meet in. #117313 (Alexey Milovidov). - Fixed
uniqThetaand its variants silently returning a value that is too low when reading anAggregateFunction(uniqTheta, ...)state that another Apache DataSketches implementation had written in the compressed Theta sketch form. #117422 (Alexey Milovidov). - Fixed undefined behavior and an empty result of a
SELECT ... ORDER BY <distance function> LIMIT n OFFSET mover a table with avector_similarityindex whenn + m, orLIMITmultiplied byvector_search_index_fetch_multiplier, overflowsUInt64; such a query now skips the index and runs the exact search. #117713 (Alexey Milovidov). #117892 (Groene AI). - Fixed a
LOGICAL_ERROR(Invalid number of columns in chunk pushed to OutputPort) for a vector search over a column with aQuantized(...)codec whenvector_search_use_quantized_codesand the experimentalmake_distributed_planwere both enabled. #118850 (Groene AI). - Fixed an external
GROUP BYwithenable_adaptive_aggregatorexceedingmax_memory_usageor failing withMEMORY_LIMIT_EXCEEDEDinside the aggregator’s own memory valve: the working set of the memory-pressure sweeps was sized from constants unrelated tomax_bytes_before_external_group_by, and records staged before the aggregator thawed its tables stayed resident until the merge, so a thawed thread wrote a temporary file per block. Both are now bounded by that threshold. #117880 (Alexey Milovidov). #118474 (Groene AI). - Fixed a comment
ALTERon aKeeperMaptable in aReplicateddatabase being applied only to the local replica. Keeper kept the pre-ALTERCREATEstatement and digest, so other replicas never saw the change and the next start declared the replica lost, reverting theALTERand, if no other table shared itsKeeperMappath, dropping its data. #118011 (Groene AI). - Fixes
bloom_filterskip indexes on big-endian platforms (s390x), where the index payload was never written or read, so a query using such an index returned no rows for data that is present. #118164 (Vadim Ilves). - Fixed
arrayIntersectreturning a spuriousNULLwhen it is missing from one of the input arrays. #118312 (Minh Vu). FixedarrayIntersect,arrayUnionandarraySymmetricDifferencemishandling aNullableargument whose elements do not fit the common element type:arrayIntersect([toNullable(1)], [toNullable(257)])returned[1], andarrayUnion([1], [toNullable(257)])failed withILLEGAL_COLUMNinstead of returning[1,257]. #118485 (Groene AI). - Fixed a
UInt64constant that does not fitUInt32matching an unrelated row of aDateTimecolumn inIN(and in anORchain of equalities, which is rewritten intoIN): the constant was truncated modulo 2^32 instead of being excluded from the set. #118367 (Alexey Milovidov). - Fixed
CORRUPTED_DATA(“Cannot get value from Set”) for aFINALquery withORDER BY ... WITH FILL INTERPOLATEwhose filter is anINset moved intoPREWHERE: the set placeholder column is no longer kept alive past the filter. #118420 (Alexey Milovidov). - Fixed
lcmreturning a negative result forInt128andInt256arguments when exactly one of them is negative, e.g.lcm(toInt128(-6), toInt128(4))returned-12instead of12. #118431 (Alexey Milovidov). - Fixed
text,tokenbf_v1andngrambf_v1skip indexes not being used when the searched constant has typeLowCardinality(String)(e.g.hasToken(s, toLowCardinality('rare'))ors = toLowCardinality('rare')), which caused a silent full scan. Such predicates now prune granules like their plainStringcounterparts. #110017 (Groene AI). - Fix a
textorngrambf_v1index silently dropping matching rows when the indexed column is compared for equality against aFixedStringvalue, or searched withhasAnyorhasAlloverFixedStringneedles. Happens at default settings, sinceuse_skip_indexesandenable_full_text_indexare both on. #117314 (Alexey Milovidov). - Fix rows silently dropped by an
ngrambf_v1index for aLIKEpattern with a run of escaped backslashes before a wildcard. #118673 (Alexey Milovidov). - Fixed a
bloom_filterskip index dropping granules that hold matching rows forhasAny/hasAllagainst a constant array whose elements are of a different date/time type than the indexed column, andTYPE_MISMATCHfor aDate32element. #118956 (Alexey Milovidov). - Fixed wrong results when a table declares both a
Mapcolumnmand a column named exactly`m.key_<key>`(dots are legal in column names), or has that name claimed by a subcolumn such as aTupleelement or a typed JSON path. Skip-index analysis read the name as the map’s key subcolumn and pruned every granule whose map lacks<key>, so amapKeysormapValuesindex (ngrambf_v1,tokenbf_v1,sparse_grams,bloom_filter,text) dropped rows that matched the predicate. #119457 (Groene AI). - Fixes incorrect primary-key pruning for
hasandnotHaswhen array element types differ from the key type, such asStringliterals againstEnumorFixedStringkeys. #115294 (Alexey Milovidov). - Fixed rows being silently dropped by partition pruning, primary key analysis and
minmaxskip indexes when aNaNis involved: a comparison constant that holds aNaN, possibly nested in a tuple or appearing only after conversion to the key type, as inNOT (f < 'nan'). #116763 (Groene AI). A string constant such as'nan'compared with a floating point column under an injective key transform such asORDER BY toString(f), sof != 'nan'skipped the granule holding theNaNrow. #117501 (Groene AI). AFloatprimary key holding±infwhere the predicate’s arithmetic maps that endpoint toNaN, e.g.WHERE k / inf = 0. #118468 (Alexey Milovidov). - Fix wrong results when
indexHintis given an argument that index analysis cannot read as a condition.indexHint(256)was narrowed toCAST(256, 'UInt8')= 0 and discarded every part, so the query silently returned an empty result; a wide integer such asindexHint(toUInt256(256))did the same, and aString,DecimalorNULLargument threw. Such an argument now contributes no filter, consistently for the primary key,minmax,setandbloom_filteranalysis. Closes #111684. #114048 (Groene AI). Also fixed a bare key column of a type with no boolean reading (UInt256,Int128,BFloat16, or theirLowCardinalityforms) being read ascolumn != 0insideindexHint,NOT indexHint(x)failing withILLEGAL_TYPE_OF_ARGUMENT, and a negatedindexHintin a disjunction keeping its condition un-inverted, socount()could report rows that no row of the table matches. #119209 (Groene AI). - Fixed wrong results from
optimize_functions_to_subcolumns. ATupleelement or aJSONpath named like an automatic subcolumn could be mistaken for it, so for examplelength(c.a)onTuple(`a.size` UInt64, `a` String)returned the element instead of the length;empty,notEmpty,isNull,isNotNull,count,mapKeys,mapValues,mapContains, andm['key']were affected the same way. Separately,lengthon anArrayorMapinside aNullable(for exampleNullable(JSON(`a` Array(Int64)))) returnedNULLinstead of0for aNULLrow,tupleElementon a member of aNullable(Tuple(...))column could fail withLOGICAL_ERROR, and a function is now rewritten only to a subcolumn of the same root column, so a physical column such as`j.m`is no longer confused with thempath ofJSONcolumnj. #115777 (Pavel Kruglov). #119150 (Groene AI). #119631 (Groene AI). - Declaring
STATISTICS(...)on anALIASorEPHEMERALcolumn is now rejected when the table is created or altered, instead of being accepted and making every subsequentINSERTfail withNOT_FOUND_COLUMN_IN_BLOCK. Closes #114791. #115882 (Groene AI). - Fixed
CREATE TABLEaccepting a subcolumn as aUNIQUE KEYelement, of either a user column (for exampleUNIQUE KEY (`c.null`)) or a virtual one (UNIQUE KEY (`_partition_value.1`)), which produced a table that could never be inserted into, failing everyINSERTwithNOT_FOUND_COLUMN_IN_BLOCK. Such a definition is now rejected withBAD_ARGUMENTS. Closes #114470. #115854 (Groene AI). - Fixed an in-process Keeper client (
KeeperOverDispatcher) reporting a failedmultitransaction as successful, because a rolled-back batch’s aggregate error was leftZOK. #117135 (Sergei Trifonov). - Fixed OOM when reading a
Parquetfile with an invalidnum_childrenfield in the schema. #117797 (Michael Kolupaev). - Fixed a
Parquetreader bug where a filter on aUUIDcolumn could silently return fewer rows than the file holds, or reject a valid file withINCORRECT_DATA: Statistics have min_value > max_value. Parquet sortsuuidstatistics by big-endian bytes while ClickHouse sortsUUIDby its second half, so those statistics are no longer used for row group or page pruning. Closes #118371. #118387 (Groene AI). - Fixed wrong results when reading a
Parquetfile with a nullable struct column without an explicit schema. Schema inference pushed the nullability down to the tuple elements and returnedTuple(Nullable(...), ...), which cannot hold a struct-level NULL, so a NULL struct was read as a tuple of NULLs. Such a column is now inferred asNullable(Tuple(...))whenallow_experimental_nullable_tuple_typeis enabled. That setting was also added to theParquetschema inference cache key, so a schema cached under one of its values is no longer reused under the other. #115653 (Groene AI). - Fix reading
ArrowandArrowStreamfiles containing values hidden by NULLs or unused nested ranges, which could cause validation errors or expose undefined values. Fix nullable tuple conversions and destination defaults, dictionary decoding under requested types, and NULL dictionary entries for complex types. Accept compatible shared dictionaries with differing field annotations and reject replacement dictionaries inArrowfiles. Validate nested row counts before allocation and read bufferless batches incrementally without materializing their entire declared row count. #110531 (Nihal Z. Miaji). Fix reading a flattenedTuplesubcolumn (e.g.`s.v`) from anArrow/ArrowStreamfile whose column is a nullable struct returning column defaults instead of the actual data whenallow_experimental_nullable_tuple_typeis enabled. Also fixORCreads resolving a column or struct field name to the first case-folded match underinput_format_orc_case_insensitive_column_matching, which returned another field’s data when two names differ only by case. #109741 (Groene AI). - Fix a crash and wrong results when reading the
DWARFformat with column types other than the ones the format produces, for exampleSELECT * FROM file('a.elf', DWARF, 'tag String'). Requesting a column that does not exist in the format now reports a proper error instead ofstd::out_of_range. #118794 (Raúl Marín). - Fix data silently dropped when reading a hadoop-snappy stream whose block has several subblocks and the input is refilled in the middle of that block, which happens when the file is read over a pipe or HTTP. #118705 (Alexey Milovidov).
- Fixed two defects in the legacy binary settings format, used for native-protocol clients declaring a revision below 54429. Signed integer settings (for example
max_partitions_to_readoriceberg_snapshot_id) were silently ignored, and were reported as changed while holding their default, so they overrode the table-level value with that default. Settings required to be greater than zero (for examplemax_block_size) were not validated when read from that format. #118610 (Groene AI). - Fixed a query over an
Icebergtable returning rows that had been deleted, when a position-delete manifest declares a lower bound above the upper bound for the reservedfile_pathcolumn. Such a pair describes an empty range, so the delete file was skipped for every data file it covers; those bounds are now ignored instead. Closes #118113. #118181 (Groene AI). - Fixed reading an
Icebergtable failing withICEBERG_SPECIFICATION_VIOLATIONafter a column was dropped while its data is still present in the data files. Closes #113324. #116488 (Konstantin Vedernikov). - Fixed
write_full_path_in_iceberg_metadatawriting an unresolvablelocal://URI, with a doubled root slash, into the metadata of anIcebergLocaltable, so that no external Iceberg reader could open it. A local table location is now spelledfile:///path, and a backend without a namespace no longer contributes an empty authority segment. #117828 (Groene AI). - Fixed writing
Icebergstatistics on top of Azure storage. #119369 (Konstantin Vedernikov). ATTACH TABLEof a data lake table no longer reads anything from object storage, and such tables no longer report row statistics in system tables. #117584 (Konstantin Vedernikov).- Reading a table backed by local object storage (
paimonLocal,icebergLocal,deltaLakeLocal, or a disk withobject_storage_type: local) whose metadata references a file that is missing on disk now fails with aFILE_DOESNT_EXISTexception naming the file, instead of a rawstd::filesystemerror surfaced as the opaqueSTD_EXCEPTION(code 1001). #115542 (JIaQi Tang). - Fixed a
SELECTfrom a table withpaimon_incremental_read = 1failing withREPLICA_IS_ALREADY_ACTIVE(“Failed to activate Paimon replica after Keeper reconnection”) on the first read after the server’s Keeper session was lost and re-established. #118457 (Groene AI). - Fixed a spurious
Code: 76 CANNOT_OPEN_FILEerror (Parent directory doesn't exist) on any write to anhdfsdisk. Removing a blob deleted its emptied object-key prefix directory, which could race a concurrent write that had just created the same directory and not yet opened its object. Emptied prefix directories are now kept. #118654 (Groene AI). - Fixed a server refusing to start after
remote_url_allow_hostswas tightened while a database with theHDFSengine existed: the host check ran during metadata loading and took every other database down with it. #118964 (Alexey Milovidov). - Fixed a server that refused to start after the directory backing a
Filesystemdatabase had been removed. Such a database is now loaded without tables and can be inspected and dropped, while aCREATE DATABASEorATTACH DATABASEissued by a user is still rejected when the path does not exist. #118684 (Groene AI). - With
enable_analyzer = 1(the default), fixedINCOMPATIBLE_TYPE_OF_JOINandNOT_FOUND_COLUMN_IN_BLOCKerrors when anALL INNER JOINagainst a table with theJointable engine carried anONcondition referencing only that table, such asON t.key = j.key AND j.value > 100. The condition is now applied after the join, which is what the equivalentWHEREspelling already did. Closes #116541. #116612 (Groene AI). - Fixed uneven partition distribution in the
Kafkaengine withkafka_keeper_path(StorageKafka2) whenkafka_num_consumersis greater than 1. A node running N consumers could claim N times its fair share of the topic’s partitions and hold them indefinitely, leaving other replicas idle. #116843 (Aparajita Pandey). clickhouse-localnow preserves detailedPoco::Exceptionmessages from local query execution instead of reporting them as genericSTD_EXCEPTIONerrors. This includes errors returned by themysqltable function. #116884 (Mark Needham).- Fixed
HashJoinright-side memory accounting when a memory limit interrupts a join build. A block could be stored without being counted, so the join under-reported its size to the memory limits and the spilling thresholds, and aJoinengine table held the memory of a failedINSERTfor the rest of its lifetime. #116991 (Groene AI). - Fix wrong aggregate values from the default-enabled
optimize_rewrite_aggregate_function_with_ifwhen the constant is in the first branch of theifand the condition can be NULL, for examplesum(if(c, 0, x))oravg(if(c, NULL, x)). Rows whose condition was NULL were silently dropped from the aggregate. #117221 (Alexey Milovidov). - Fixed a signed integer overflow when the effective table lock timeout, the smaller of
lock_acquire_timeoutand a non-zeromax_execution_time, was above roughly 9.2e9 seconds or a large negative value. Reading or writing aLog,TinyLog,StripeLogorFiletable built the lock deadline from it without bounding it first, so the wait was no longer bounded by the setting. #117974 (Groene AI). divideDecimalno longer returns0instead of the correct value when the dividend reduces to a single digit after being rescaled to the result scale, for exampledivideDecimal(toDecimal256(5, 0), toDecimal256(1, 0), 0)ordivideDecimal(toDecimal32(5.6789, 4), toDecimal32(2, 0), 0). The bug was present in every release since 22.12, so any stored result of such a division is wrong and should be recomputed. #118346 (Minh Vu).- Fixed
ClickHouseDictionarySource table cannot be dictionary tablebeing raised for a dictionary whose source is a table on another ClickHouse server that happens to share the dictionary’s database and table name. The check against a dictionary using itself as its own source now applies only when the source is the local server. #118441 (Alexey Milovidov). - Fix
arrayElementOrNullover an array of tuples, andarrayElementover an array ofNullabletuples, returning a tuple of default values instead ofNULLfor a constantUInt64index close to the maximum ofUInt64, such astoUInt64(18446744073709551615). #118447 (Minh Vu). - Fixed a query parameter being reported as unset (
UNKNOWN_QUERY_PARAMETER) when it is the entireINTERPOLATEexpression, as inORDER BY x WITH FILL INTERPOLATE (value AS {p:Int64}), while the same parameter nested in a larger expression worked. Closes #118458. #118568 (Groene AI). The same for a parameter that is the entire predicate of a lightweightDELETE, as inDELETE FROM t WHERE {p:UInt8}. #118667 (Groene AI). - Fix partition pruning and primary key filtering being silently disabled when
parallel_replicas_min_number_of_rows_per_replicais set inside a subquery or CTE instead of at top query level. #116529 (Yarik Briukhovetskyi). - Fixed wrong results and a
LOGICAL_ERRORforSELECT ... FINALundermake_distributed_plan = 1when aPREWHEREor a row policy is deferred until afterFINAL(apply_prewhere_after_final, or the defaultapply_row_policy_after_final). #116626 (Groene AI). - Fixed wrong results from JIT-compiled conversions of a floating point value to an integer or
Decimaltype when the value does not fit the destination: a comparison against the converted value could be evaluated against the pre-conversion value, so the same query could flip between repeated executions. Such conversions are now evaluated by the interpreter, which also means they raiseCANNOT_CONVERT_TYPEforNaNorInfandDECIMAL_OVERFLOWonDecimaloverflow where an arbitrary value was previously returned. Closes #117442. #117590 (Groene AI). Fixed wrong results from a JIT-compiledCASTof aNullablevalue to a non-Nullabletype: converting a NULL must raiseCANNOT_INSERT_NULL_IN_ORDINARY_COLUMN, but the compiled expression returned the nested value instead, so the same query silently started answering with wrong data oncemin_count_to_compile_expressionwas crossed. Such a conversion is no longer compiled. #119079 (Groene AI). - A simple
Queryin the PostgreSQL wire protocol now destroys the unnamed prepared statement and the unnamed portal, as PostgreSQL does, so a laterBindorExecuteon them is rejected instead of silently reusing stale extended-query state. #118210 (Groene AI). portRFCnow returns the explicit port of a URL whose host is an IPv6 address in brackets, such ashttp://[2001:db8::1]:8080/, instead of the default port. #118632 (Alexey Milovidov).portandportRFCnow return the explicit port for valid URLs with a query string or fragment after the port. #118482 (Minh Vu).fuzzBitsandgenerateULIDnow return an independently generated value per row when all of their arguments are constants, instead of one value repeated for every row. #118643 (Alexey Milovidov).- Fix
EmbeddedRocksDB,KeeperMapandRedisreturning no rows forWHERE key = <literal of another date-family type>, such as aDatekey compared with aDateTimeliteral. #118689 (Alexey Milovidov). - Fixed the row numbers shown in the Web UI for a page other than the first one: they restarted at 1 on every page instead of counting from the page’s position in the whole result. #116614 (Alexey Milovidov).
- Fix delayed ClickHouse Keeper shutdown when idle client sessions are blocked in socket polling. #118014 (Antonio Andelic). Fix graceful shutdown of
clickhouse-keeperhanging for up to 300 seconds when a client connection onkeeper_server.tcp_port_secureis stalled in a TLS read. #119450 (Groene AI). - Fixed a Keeper crash when a member that was removed from the cluster is added back without its process being restarted. Such a member could also replay already-applied entries. #118740 (Shaohua Wang).
- Fix handling of regular expressions ending with an unescaped backslash in
match,extractAll,countMatchesandsplitByRegexp. Such invalid patterns are no longer incorrectly treated as trivial substring matches. #118229 (Alex Prabhat Bara). - Fixed
matchandcountMatchesreturning wrong results for a pattern whose character class starts with a literal]([]a]b) or contains a literal[next to an alternation (abc[[]|b): the required-substring prefilter demanded a substring the pattern does not require. The same defect madeoptimize_rewrite_regexp_functionsturn such areplaceRegexpAllintoreplaceRegexpOne. #118342 (Alexey Milovidov). - Fix
startsWith*array functions returning suffix matches for some variants. #118672 (Minh Vu). - Fixed an out-of-bounds access that could happen with the
getURLHostRFCfunction. #119026 (Groene AI). - Fix the HTTP connection pool comparing
disk_connections_store_limit,storage_connections_store_limit, andhttp_connections_store_limitagainst the total number of connections in the group instead of the number of stored connections. A server whose concurrency exceeded the limit cached no connections at all, opened a new TCP connection for every request to object storage, and could exhaust the ephemeral port range of the host. The limit now bounds only the idle connections kept for reuse. #119078 (Alexey Milovidov). - Fixed the hash-family join algorithms treating a non-NULL
Nullable(Tuple(...))key that contains a NULL element as a NULL key, which made the result of a join depend on thejoin_algorithmsetting.INwith a subquery over such a key was affected in the same way. #119081 (Alexey Milovidov). - Fix wrong results when
analyzer_compatibility_join_using_top_level_identifier = 1and aJOIN ... USINGkey resolves to aSELECT-list alias whose name is a virtual column of the left table expression, such asSELECT upper(t._part) AS _part FROM t JOIN r USING (_part). The raw virtual column value was silently used as the join key instead of the aliased expression. #119102 (Groene AI). - Fixed a
LOGICAL_ERROR(Got read request from replica N for unknown stream <table>) whenparallel_replicas_plan_basedis enabled and a join is distributed across replicas. #118084 (Groene AI). - Fixes a case where
date_time_overflow_behavior = 'saturate'clamped an out-of-range value to the whole second and discarded the sub-second component. Closes #113152. #116122 (Yarik Briukhovetskyi). - Fix
system.dictionaries.bytes_allocatedmisreporting memory forHASHED_ARRAYdictionaries: the key containers contributed their element count instead of their buffer size in bytes, so the reported figure came out roughly 2-5x lower than the memory the dictionary actually held, and the bit-packed per-attribute null masks were counted in elements, which over-reported that term by 8x. #118641 (George Viamontes). Fixed the same figure over-reporting memory for nullableRANGE_HASHEDdictionaries, whose bit-packed nullable mask was counted one byte per flag. #118675 (Minh Vu). - Fixed
max_execution_time_leafandtimeout_overflow_mode_leafbeing ignored for queries executed with parallel replicas (includingINSERT SELECTwithparallel_distributed_insert_select = 2). #69540 (Igor Nikonov). - Fix
CREATE TABLE ... CLONE AS SELECT ...andCREATE TABLE ... CLONE AS <table_function>silently ignoring theCLONEkeyword and creating a plainCREATE ... AS SELECTinstead. These shapes are now rejected withBAD_ARGUMENTS. #105004 (Tuan Pham Anh). - Fix a logical error (a server abort in debug builds) when a non-transactional
DROP PARTITION,DETACH PARTITION,DROP PART,REPLACE PARTITION FROMorMOVE PARTITION TO TABLEcovered a part whose creating transaction had not committed yet. Such an operation now fails withSERIALIZATION_ERRORand can be retried once the creating transaction finishes; it no longer removes or replaces any part of the affected batch. #105116 (Tuan Pham Anh). - Fix a logical error when a correlated
MATERIALIZEDCTE is referenced more than once inside aJOIN. Such a CTE is now rejected at analysis time withUNSUPPORTED_METHOD, consistently with the single-reference andIN-subquery paths. #108883 (Groene AI). - Fix a logical error
Invalid cast from Nothing to native type(an abort in debug/sanitizer builds) whencompile_expressions = 1compiled an expression with aNullable(Nothing)operand, e.g.and(Nullable(Nothing), <native comparison>). #111508 (Groene AI). - Fix wrong results with
enable_parallel_replicas = 1when a join tree contains a join other than the leftmost one that cannot be applied independently per replica: a strictness other thanALLoutside aLEFTjoin, for examplet1 INNER JOIN t2 ON t1.c = t2.c ANY INNER JOIN t3 ON 1, which returned the row once per replica instead of once; aFULLjoin, which emitted every row twice; or aPASTEjoin, which pairs rows by position. Parallel replicas are now disabled for such a join tree, as they already are for the equivalent two-table join. #112317 (Groene AI). - Fix a segfault and silently wrong results when reading a
sizeNsubcolumn of a nestedArray(JSON)path. Closes #113686. #113752 (Groene AI). - Fixed wrong results and a server abort when a
JOIN ONcondition evaluated during anie_joinjoin containsarrayJoin. Such a condition is now rejected withINVALID_JOIN_ON_EXPRESSION. PreviouslySEMI/ANTI/LEFT/RIGHT/FULLjoins using theie_joinalgorithm could return duplicated or missing rows, or abort the server. #114325 (Groene AI). - Fix reading a
LogorTinyLogtable whose array or map elements are missing while their sizes are present: such a table returned rows with elements that are not there and made the server read out of bounds. It is now reported asINCORRECT_DATA. #115528 (Alexey Milovidov). - Fix a segmentation fault when reading in order from a
Mergetable overMergeTreetables whose sorting key is shorter than the key prefix chosen for the query. #116364 (Groene AI). - Fix
LOGICAL_ERROR: GroupingAggregatedTransform pushed bucket N twicewhenmake_distributed_planpicks theShuffleaggregation strategy while the aggregation must produce results in bucket order (for example withdistributed_aggregation_memory_efficient). It is now planned as a partial aggregation plus a merge. #116446 (Groene AI). - Fix wrong row order when sorting a
LowCardinalitycolumn of a floating-point type whose dictionary holds two entries that compare equal, such as-0.0and+0.0. A multi-columnORDER BYdid not apply the remaining keys to those rows, and theMergeTreewriter’s stable sort did not keep them in insertion order, changing which rowReplacingMergeTreekeeps. #116870 (Groene AI). - Fixed wrong results from the default-on
optimize_time_filter_with_preimagefortoYear/toYYYYMMpredicates at the column type’s maximum (Dateat 2149,DateTimeat 2106), aDECIMAL_OVERFLOWexception for the same predicates on aDateTime64(9)column at 2262, and wrong results for the same predicates onDateTime/DateTime64columns in time zones whose year or month boundary is not local midnight (America/Lima,America/Managua). #117451 (Alexey Milovidov). - Fixed
NOT_IMPLEMENTED(“Cannot decorrelate query, because ‘DelayedCreatingSets’ step is not supported”) for a correlated subquery whoseWHEREbuilds a set, for example anIN (subquery), or adictGet(...) >= constcomparison thatoptimize_inverse_dictionary_lookuprewrites into one. #118412 (Alexey Milovidov). - Fixed a race between
SYSTEM RESTORE DATABASE REPLICAand the DDL worker of aReplicateddatabase. The restore re-initialised the replica while the previous DDL worker was still running its own startup recovery, so the recovery could mark the wrong range of replicated-DDL log entries as finished, or move local tables to_broken_replicated_tables. The worker is now stopped before the restore touches Keeper. #118481 (Groene AI). - Fixed
WITH RECURSIVElosing its recursiveness in the second and later branches of aUNION,INTERSECTorEXCEPT. When a later branch had noWITHclause of its own, the first branch’sWITHlist was copied into it without theRECURSIVEmarker, soWITH RECURSIVE src AS (SELECT 1 AS id UNION ALL SELECT id + 1 FROM src WHERE id < 3) SELECT sum(id) FROM src UNION ALL SELECT sum(id) FROM srcwas rejected withUNKNOWN_TABLE, and returned a wrong value for the copied branch when an enclosing CTE of the same name existed.CREATE VIEWalso stored the copied branch withoutRECURSIVE. #118510 (Groene AI). - Fixed a
GLOBAL RIGHT JOINoverDistributedtables returning unmatched rows of the right table once per shard: the original left table is now broadcast and the preserved right side stays sharded. Closes #95728. #118611 (Anton Ivashkin). - Fix an endless
ORDER BY ... WITH FILLwhen theSTEPis too small to change the value it is added to. #118633 (Alexey Milovidov). - Fix the
Invalid local IN function name globalInerror for a query withINover aUNIONofDistributedtables whendistributed_product_mode = 'global'orprefer_global_in_and_joinis enabled. #118639 (Alexey Milovidov). toLastDayOfMonthandtoLastDayOfWeekof aDateargument now saturate at theDatemaximum (2149-06-06) instead of wrapping around to 1970. The wrapped result also silently dropped matching rows through primary-key pruning. #118642 (Alexey Milovidov).- Fixed a crash and a
LOGICAL_ERRORin themergeTreeIndextable function when reading a key column whoseALTER TABLE ... MODIFY COLUMNbetweenTandLowCardinality(T)has an unmaterialized mutation. The key column is now emitted in the type the current metadata declares. #118709 (Groene AI). - Fix
SYNTAX_ERRORwhen loading views, materialized views, or projections whoseSELECTlist starts with a column namedTOP. #118754 (Kirill). - Fixed
optimize_or_like_chainreturning extra rows forORchains ofLIKE/ILIKEpatterns that do not end in%: a value followed by a trailing newline wrongly matched the filter. #118766 (Jimmy Aguilar Mena). - Fixed a
LOGICAL_ERROR(“Expected CommonSubplanReferenceStep to reference CommonSubplanStep”) raised at query planning time whenquery_plan_convert_join_to_in = 1was used with a correlated aggregating scalar subquery. The optimization now keeps theJOINinstead of rewriting it when either join input carries a common subplan node. #118797 (Groene AI). - Fix a wrong result for
SELECT * APPLY (x -> f(x))overJOIN ... USING (a, b): everyUSINGcolumn was named after the lambda parameter (f(x)) instead of the matched column, so two output columns shared one name, and wrapping the query inSELECT * FROM (...)returned oneUSINGcolumn’s values under the other column’s position; a type-returning lambda such astoTypeNamefailed withAMBIGUOUS_COLUMN_NAMEinstead. The same happened forCOLUMNS(a, b) APPLY (x -> f(x)), and for two or moreARRAY JOINcolumns. The lambda form ofAPPLYnow names these columns likeAPPLY fand a plain*already did. #118825 (Groene AI). - Fixed a server crash that could happen when a
WORKLOADsetting limiting concurrency (e.g.max_concurrent_queriesormax_bytes_inflight) was lowered below the number of currently in-flight resource requests while the workload was active. #118836 (Sergei Trifonov). - Fixed a logical error (
Method == not implemented for AST) raised by aSETof a custom setting that already held an AST value such asdisk(type = 's3', ...). Assigning such a setting a second time in one session, or clamping a nestedSETTINGSclause against it, reached a comparison that was never implemented. #118993 (Groene AI). - Fixed a broken part in
detached/never being renamed with thebroken_prefix by theATTACH_PARTexecutor, which left it occupying a valid part name and failing every later attach attempt. #118999 (Alexey Milovidov). - Fix
TOO_DEEP_SUBQUERIESbeing thrown forGLOBAL INandGLOBAL JOINsubqueries in two analyzer cases: whenmax_subquery_depthis set, the depth is now counted in nested subqueries instead of query tree nodes; and when aUNIONis on the path to theGLOBALsubquery,UNIONnodes no longer count toward that depth. Closes #79345. Closes #119623. #119033 (Vladimir Cherkasov). #119650 (Groene AI). - With
prefer_column_name_to_alias = 1, an unqualified column name that is ambiguous between joined tables now resolves to the alias with the same name, as the old analyzer did, instead of throwingAMBIGUOUS_IDENTIFIER. #119192 (Vladimir Cherkasov). #119906 (Vladimir Cherkasov). - Fix a wrong-order merge (logical error
Virtual row does not cover sort columnin debug builds) when reading in order with virtual rows andORDER BYcontains constants, e.g.SELECT DISTINCT a, b FROM t ORDER BY 'x', a, 'd' COLLATE 'cs', bon a table with key(a, b). #119195 (Vladimir Cherkasov). - Fixed wrong results when a table’s sorting key expression resolves to a different result type in the query than in the table, for example a key of
CAST(json.b, 'String')read withcast_keep_nullable = 1. Read-in-order treated the two as interchangeable, so rows could come back out of order,optimize_aggregation_in_ordercould split groups and report wrong aggregates, andread_in_order_use_virtual_row = 1could fail withLOGICAL_ERROR: Virtual row has different type. #119385 (Groene AI). - Fixed
BACKUPof aMemorytable reading an unrelated file namedtmp_sizes_jsonfrom the server’s working directory: thesizes.jsonshipped inside the backup is now built in memory, so such a file can no longer make the backup fail or add foreign entries to it. #119330 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen aMergeTreeskip index usesmortonEncodeorhilbertEncodedirectly and a query filters on one of the curve arguments. #119355 (Minh Vu). - Fixed an
ALTERon a view or materialized view withSQL SECURITY DEFINERdeleting the auto-created<user>:defineraccount when theALTERdid not change the definer. Every laterSELECTfrom the view, and everyINSERTinto a materialized view’s source table, then failed permanently withThere is no user '<user>:definer' in 'user directories'(UNKNOWN_USER). #119357 (Groene AI). - Fixed a materialized view whose
SELECTcontains aUNION,INTERSECTorEXCEPTin a subquery or CTE breaking afterDETACH TABLE+ATTACH TABLE, or afterRESTORE: every subsequentINSERTinto its source table failed withUNION mode UNION_DEFAULT must be normalized, and underenable_analyzer = 0it was silently evaluated as a plain union, returning wrong results.ATTACH TABLE(short form) andRESTOREnow re-run set-operation normalization on the stored definition. #119365 (Groene AI). - Fix an
ALIAScolumn that references another column (b UInt64 ALIAS a) reading back as the default value of its type when the table is read through aMergetable over aDistributedtable with a remote shard. #119561 (Alexey Milovidov). - Fix
arrayShiftLeftandarrayShiftRightwhen an explicitNULLdefault is used with a nullable array. #119626 (Minh Vu). - Fix
ALTER TABLE ... MODIFY SETTING name = DEFAULTbeing ignored. Closes #49613. #118526 (Vitaly Baranov). - Fix
arrayNormalizedGinirejecting valid rows with different array sizes in the same block. #118631 (Minh Vu). - Fix
substringIndexandsubstringIndexUTF8rejectingUInt64counts aboveInt64::max()instead of interpreting them as negative counts. #118645 (Minh Vu). - Fix a logical error for an asynchronous
INSERTcombined with a non-parallel quorum (insert_quorumgreater than one or'auto'together withinsert_quorum_parallel = 0) when the data is sent as blocks over the native protocol. Such a query is now rejected withUNSUPPORTED_PARAMETER, as it already was when the data was inlined in the query text. #118968 (Alexey Milovidov). - Fixed a graceful shutdown silently discarding the rows of a
Buffertable whose destination lives in another database or is anotherBuffertable. #118985 (Alexey Milovidov). #116898 (Jayme Bird). - Fix a use-after-free in the gRPC server when a query with a streaming input finishes while a read of the next message is still in flight. #115707 (Alexey Milovidov).
- Custom object metadata written to Google Cloud Storage over the S3 API without HMAC credentials, which is how ClickHouse Cloud on GCP accesses object storage, now takes effect: the headers that GCS spells with the
x-goog-prefix are translated for every request, not only for server-side copies. Previously GCS discarded thex-amz-spelling silently, so the write succeeded and the metadata was not applied. #119042 (Sema Checherinda). - Fixed a crash when reading a subcolumn of a
Variant,Dynamic, orJSONcolumn whose own type isNullableorLowCardinality(Nullable)from aMergeTreetable, for exampleSELECT value.`Tuple(a Nullable(UInt32), b String)`.aover aDynamiccolumn. Previously such a read hit aLOGICAL_ERRORin debug builds and crashed in release builds. #112338 (Groene AI). - With
shutdown_wait_backups_and_restores = 0, aBACKUPorRESTOREwhose I/O did not return could keep the server from terminating on a singleSIGTERM. That wait is now bounded byshutdown_wait_unfinished, and new backups and restores are refused once shutdown has begun. #115377 (Groene AI). - Fix wrong results when query plan optimizations treat non-deterministic expressions as deterministic, including lambdas and WebAssembly UDFs, which could silently drop rows. #117248 (Alexey Milovidov). #117249 (Alexey Milovidov).
- Fix
Column identifier ... is already registered(LOGICAL_ERROR) for a correlated subquery over aVIEWon aDistributedtable. Such a query is now refused withCorrelated subqueries are not supported with remote tables, the same as a correlated subquery over theDistributedtable itself. The same applies to parameterized views,Mergetables over such views, and materialized views whose target is such a view. #117335 (Alexey Milovidov). - Fixed
transformand the simpleCASE expr WHENform returning the default value instead of the matching one when the expression is aNullable(Enum)column. Only the member whose numeric value was0used to match. Closes #117206. #117520 (Groene AI). - Fix
SYSTEM RELOAD DICTIONARY <bare-name> ON CLUSTERandSYSTEM UNLOAD DICTIONARY <bare-name> ON CLUSTERso normal distributed DDL clusters resolve the bare dictionary name against the initiator’s current database before queuing the task, matching existing table-likeON CLUSTERDDL behavior. Closes #114322. #117596 (Alexander Yoon). - Fixed silently missing rows for predicates on
toUnixTimestampof aDateorDate32primary key or column with statistics: the conversion wraps aroundUInt32for dates after 2106-02-07, but index analysis assumed it was monotonic everywhere. #117709 (Alexey Milovidov). - Fixed a query getting stuck when the server fails to start a thread for a parallel task, for example when a thread pool is exhausted. #117781 (Alexey Milovidov).
- Fixed wrong results for a distributed query whose folded constant contains a
DateTimevalue. The constant is now sent to secondary servers as its raw Unix timestamp wherever the receiving side re-applies the literal’s declared type, so DST fall-back overlaps no longer reinterpret it as another instant. #117837 (Groene AI). - Fixed queries failing with
AUTHENTICATION_FAILEDafterRENAME DATABASEon aReplicateddatabase that usescluster_secret. The cached cluster object kept the old database name, which participates in the interserver handshake. #117874 (Kirill Shokhin). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhentransform_null_in = 1and a distributed or parallel-replicas query aggregates over a predicate that an analyzer pass rewrote intoIN, such asSELECT sumIf(id, has([1, 2, 3], id)) FROM t. #117897 (Groene AI). - Fixed
THERE_IS_NO_COLUMN(Cannot find column ... in source stream) when a query shipped as a serialized query plan (serialize_query_plan = 1) reads aMergetable that spans a local table and aDistributedtable. #117969 (Groene AI). - Fixed a
SELECTreturning fewer rows than it should when aJSONsubcolumn is compared with anEnumconstant whose label is the empty string, and the table has aJSONAllPathsskip index (bloom_filter,tokenbf_v1,ngrambf_v1, orsparse_grams). #117975 (Groene AI). - An
Enumconstant wrapped inVariantorDynamicand compared against aStringorFixedStringcolumn no longer uses the enum’s underlying number instead of its name, which previously madeIN,NOT IN, and key analysis use the wrong value. #117998 (Groene AI). - Fixed a
Replicateddatabase being unable to recover a lost replica if it held aRemoteorRemoteSecuretable whose target is a table function such asmerge(...)that no longer resolves. #118221 (Groene AI). - Fixed
Not found column ... in blockfor a query that combines a constantORDER BYkey,LIMIT BY, andLIMIT ... WITH TIES. #118222 (Alexey Milovidov). - Fixed two overflow cases where
memory_usage_overcommit_max_wait_microsecondslost the wait it was asked for and timed out immediately instead of waiting for memory to be freed. #118227 (Groene AI). - Fixed
CREATE VIEWbeing refused withSUSPICIOUS_TYPE_FOR_LOW_CARDINALITYorILLEGAL_COLUMNwhen the view’s inferred column type is gated by settings such asallow_suspicious_low_cardinality_typesorenable_time_time64_type. Views store no data, so those storage-type checks no longer block them. #118298 (Groene AI). - Fixed
Not-ready Set is passed as the second argument for function 'globalIn'when aPREWHEREor row-level filter expression containing anINsubquery is evaluated by a query planned to theFetchColumnsstage. #118359 (Groene AI). SELECT count() FROM <set-table>now works for theSetengine, using the table’s stored row count instead of failing withMethod read is not supported by storage Set. Reading regular columns from aSettable is still unsupported. #118491 (Alexey Milovidov).- Fixed
sequenceMatchEventsreturning an event chain that the pattern does not authorize, for example one that skips a(?t...)time gate between two of the returned events. The returned chain now always matches a prefix of the pattern. Closes #118120. #118497 (Groene AI). - Fixed
toSecond,toStartOfMinute,toStartOfHour,toStartOfInterval, and the othertoStartOf*functions returning wrong values for pre-1970DateTime64values in time zones whose historical offset had a sub-minute component, such asEurope/Amsterdambefore 1937 orAsia/Kolkatabefore 1906. #118501 (Alexey Milovidov). - Fix array aggregation functions returning non-default values for empty arrays when the lambda result is constant. #118636 (Minh Vu).
- Conversions of 128- and 256-bit integers to
DateTime,DateTime64, andTime64now saturate like the 64-bit conversions instead of wrapping or storing an out-of-range value. This also fixes silent row loss through primary-key pruning. #118717 (Alexey Milovidov). - Fix a possible heap buffer overflow on malformed blob-storage responses. #119054 (Arsen Muk).
- Preserve input sorting for
groupArrayInsertAt,stochasticLinearRegression, andstochasticLogisticRegression, so anORDER BYfeeding them is not optimized away. #119142 (Ivan Babrou). - Fixed a crash and a
LOGICAL_ERRORfor statements that writetrim(BOTH '' FROM x)where a function is expected, such as in a column’sSTATISTICS(...)orCODEC(...)list,INDEX ... TYPE,ALTER TABLE ... ADD STATISTICS, a table function, a named collection, orSETTINGS. #119317 (Groene AI). - Fix
CHECK TABLEpermanently reportingFound unexpected projection directoriesafter a mutation when the part carries a projection that the table has since dropped. #119348 (Alexey Milovidov). - Fix a wedged mutation queue after
ATTACH PARTITIONof a partition that was detached before aDROP COLUMN: mutations of a Compact part carrying the dropped column no longer fail forever withUNKNOWN_IDENTIFIER. #119354 (Alexey Milovidov). - Fix a bug where unfiltered
TRUNCATE ALL TABLES FROMqueries permanently disabled merges on retainedMergeTreetables, causing laterOPTIMIZE TABLE ... FINALqueries to fail withABORTED. #119425 (Paul Annesley). - Fix
Unexpected value 0 in enumthrown by string functions such asLIKE,match, andpositionwhen applied to aNullable(Enum)value that isNULL, includingNULLs produced by aLEFT JOINwithjoin_use_nulls = 1. #119513 (Alexey Milovidov). - Fix
arrayJaccardIndexwhen its input arrays contain duplicate elements. #119560 (Minh Vu). modulo,positiveModulo,moduloOrZero, andmoduloOrNullno longer return wrong results when one operand is a signed integer and the other is an unsigned integer at least as wide. #119616 (Serhiy Bzhezytskyy).- A
Filesystemdatabase no longer keeps pointing at a removed directory, which previously made the server refuse to start on the next restart. #119618 (Alexey Milovidov). - Fixed a standalone
UPDATE ... SETreading the wrong table when a mutation expression names a table that a same-namedWITHelement hides but the subquery does not see because its ownSETTINGSclause disablesenable_global_with_statement. #119630 (Groene AI). - Fixed a stack buffer overflow when reading a
BITcolumn from MySQL through themysqltable function, theMySQLtable and database engines, or MySQL dictionaries. #119680 (Alexey Milovidov). - Fix
sparseGramsignoringmax_ngram_lengthwhenmin_cutoff_lengthis specified. #119713 (Minh Vu). - Fix
BACKUPandRESTOREof aLogorTinyLogtable when one column occupies zero bytes on disk while the table has rows, such as a column ofcountResamplestates over an empty range. Previously the restored table could come back empty or fail withFILE_DOESNT_EXIST. #119722 (Groene AI). - Fix a race between
ALTER TABLEandRENAME TABLE/EXCHANGE TABLES. #103044 (Nikolay Degterinsky). - Fix
BACKUPofEmbeddedRocksDBtables. Previously only the table metadata was stored in the backup and the actual data was silently dropped, soRESTOREproduced an empty table. The backup now includes all key-value pairs and restores them correctly. #109327 (Groene AI). - Fix
toStartOfWeekandtoLastDayOfWeekwith a Sunday-first week mode returning a wrapped day number for aDate32value outside the representable calendar, for example aftertoDate32('1970-01-01') + INTERVAL 2147483647 DAY. The week boundary is now computed at the calendar boundary, consistently with the Monday-first week modes. #111923 (Groene AI). - Fixed
mergeTreeCodecBlockCountsdisclosing whether a source table exists, and even its engine type, to a user without any privilege on that table. Resolving the table function, for example withDESCRIBE, now checks access before consulting the catalog. #116647 (Alexey Milovidov). - Messages of the PostgreSQL wire protocol are now parsed within their declared size, so a malformed message can no longer make the server allocate memory for a payload that never arrives. #116998 (Alexey Milovidov).
- Fixed
CREATE TABLE dst AS srccopying the schema of anENGINE = Aliastable’s target for a user who holdsSHOW COLUMNSon the alias but no privilege on its target. The statement now requires table-levelSHOW COLUMNSon the target, matchingDESCRIBEof that target. #117702 (Groene AI). - Fixed the query condition cache serving a “no matching rows” verdict to a query that differs from the cached one only in a setting that changes how a function evaluates, such as the
formatdatetime_*/parsedatetime_*settings orfunction_locate_has_mysql_compatible_argument_order, which silently dropped all matching rows. #117803 (Alexey Milovidov). - Fixed a
CAST AS Tuple can only be performed between tuple types or from Stringerror, and silently wrong results for aTuple(String, ...)key, when aMergeTreesorting, partition or skip-index key wraps a singleTuple-typed column in a deterministic function (for exampleORDER BY toString(k)) and the query filters that column withk IN (tuple(...)),k NOT IN (tuple(...))or a multi-column subquery set. #118899 (Groene AI). - Fix queries that use a higher-order function together with
ARRAY JOIN: a lambda that captures nothing is no longer moved across theARRAY JOINstep away from the function that applies it. #119186 (Yarik Briukhovetskyi). - Fix
TYPE_MISMATCHin the selectivity estimator when a predicate on aDateTime64column uses an unconvertible string literal. Closes #119126. #119265 (Han Fei). - Fix unstable ordering of equal sorting keys during inserts, which could cause
CollapsingMergeTreeto retain stale rows when cancellation and replacement rows were inserted together withoptimize_on_insertenabled, andReplacingMergeTreeto retain the wrong row when versions were equal. #119474 (Anton Kovalenko). - Fixed cleartext credentials in
system.asynchronous_insert_log.query. Secrets of table functions such ass3,urlormysqlare now masked as[HIDDEN], the same waysystem.query_logmasks them. #119487 (Sema Checherinda). - Fix a crash when reading a table with active lightweight updates whose sorting key contains a column that is missing in the data part and has a
DEFAULTexpression. #119540 (Groene AI). - Fixed Keeper replaying its local changelog tail one entry at a time after a restart when the changelog is stored on object storage. The commit read-ahead used to discard its own prefetched entries whenever it missed the serve deadline, so on storage slower than that deadline it could never catch up and every entry cost two object reads. The default of
log_readahead_commit_window_bytesis now 16 MiB instead of 500 MiB, since it bounds a prefetch window rather than a cache. #119627 (Shaohua Wang). - Fix unbounded memory growth from time zone names of the form
libc:<suffix>. These are internal interfaces of thecctzlibrary that ClickHouse never intended to expose: any suffix was accepted, each distinct name permanently cost ~4.6 MiB that the server never gave back, and the time zone silently behaved as UTC instead of the name being reported as unknown. They are rejected now. #119634 (Alexey Milovidov). - Fix incorrect pruning for space-filling-curve indexes with
UInt64arguments. #119663 (Minh Vu). - Fixed
sum(x + 1) OVER (...)returning a single row holding the overall total instead of the windowed result.optimize_arithmetic_operations_in_aggregate_functions, which is enabled by default, rewrote the windowedsumintosum(x) + 1 * count(x), an expression over plain aggregates that cannot carry theOVERclause, so the window definition was discarded. Bothenable_analyzer = 1(the default) andenable_analyzer = 0were affected. #119699 (Groene AI). - Fix
substringUTF8returning too many code points when a negative offset starts before the beginning of a string. #119840 (Minh Vu). - Fix
URLHierarchy,URLPathHierarchy, andURLHashfailing to recognize valid URL schemes containinga,z,0, or9. #119844 (Minh Vu). - Fix
mapSubtractsubtracting duplicate keys in its first argument. #119845 (Minh Vu). - Fixed the server not validating the schema of the second and subsequent data blocks that a client sends for an external table over the
Nativeprotocol. Such a block could make the data be interpreted as a type other than the one it was sent as. #119849 (Alexey Milovidov). - Fixed AST formatting of the
APPLYcolumn transformer: a column-name prefix containing a single quote or a backslash, or a function name that needs back-quoting, was emitted without escaping, soformatQueryreturned a query that either could not be parsed or parsed back to a different query. #119851 (Groene AI). - Fixed a crash of the server caused by a table with
ENGINE = NATSwhose credentials the broker started to reject, for example after a password rotation or on an expired token. Such a table now recreates its connection and resumes consuming once the credentials are accepted again, instead of staying silently idle. #119853 (Alexey Milovidov). - Fixed
timeSeriesTagsToMaptreatingFixedStringtag names and values differently between the array form and the separate-argument form.FixedStringpadding is now trimmed consistently, so the same logical tags produce the same map and lookups such asmapContains(..., 'a')work in both forms. #119859 (Minh Vu). - Fixed wrong results when
join_algorithm = 'direct'reads the right-hand table of a join from aMergeTreetable and plan-based parallel replicas (parallel_replicas_plan_based = 1) are enabled. Such a join could silently return only part of the rows that should have matched, with no error reported. The lookup read that the join performs is no longer distributed across replicas. #119861 (Groene AI). - Fixed data loss where a
MergeTreepart whosecolumns.txtwas left empty (zero bytes) by an interrupted metadata rewrite was detached as broken on load, discarding all of its rows. For a wide part the column list is now rebuilt from the part’s owncolumns_substreams.txtand the table metadata, as it already was for an absentcolumns.txt; when the rebuilt list cannot be validated, the part is left untouched for recovery instead. #111597 (Groene AI). - Integers in the
TSV,TSVRaw,TSKVandCustomSeparatedformats can now be zero-padded (007) or carry a redundant leading+(+7), spellings that previously failed to parse but thatCSValready accepted. The same reader serves other conversions from text to an integer, soWHERE i = '007'on a numeric column, query parameters andCAST('[007]' AS Array(Int64))accept them too. A field that is a lone+remains an error, now reported asCANNOT_PARSE_NUMBERon every one of these routes instead of a route-specific code. Schema inference is unchanged:007still infers asString. #113910 (Groene AI). - Fixed permanent data loss in
ALTER TABLE ... EXECUTE remove_orphan_filesonIcebergtables withiceberg_use_version_hint = 1. Whenmetadata/version-hint.textnamed an older version than the newest committed metadata file, every object of the newer committed snapshot, including its data files, was deleted as an orphan. Reachability is now computed from the authoritative current metadata, and a metadata listing this command cannot order unambiguously is refused instead of resolved by listing order. #114324 (Groene AI). - Fix buffer overflows and a server abort on malformed responses from external servers: an Azure Blob Storage endpoint that returns more data than was requested or omits the
ETagheader, and aMySQLserver that returns an oversizedBITvalue.Azurereads, copies and deletes, andS3copies made by backups and byS3Queuepost-processing, are now pinned to the object generation they selected, so an object overwritten in place is reported instead of silently mixing two generations. Also fix the decoding of aMySQLBITvalue shorter than 8 bytes on big-endian hosts. #115706 (Alexey Milovidov). - Fixed a crash inside the crash handler itself when a fatal signal arrives during startup of
clickhouse-server,clickhouse-keeperorclickhouse-local. The handler dereferenced the global context, which does not exist yet at that point, so right after logging the stack trace it took a second fault, hung for about five minutes, and never sent the configured crash report. #116245 (Groene AI). - Fixed
CLEAR COLUMNsilently leaving aMATERIALIZEDcolumn derived from the cleared column at its old value. This happened whenever the mutation had already built a stage before the recompute was appended: another pending mutation coalescing with theCLEARinto one pass, which needs no special settings, or an enabledenable_block_number_column/enable_block_offset_column. The wrong value was permanent; later merges did not repair it. #117296 (Shaohua Wang). - Fixed
ILIKEon atextindex returning rows the predicate does not match, and skipping rows it does match, when the pattern or the data contains a non-ASCII code point that case-folds onto an ASCII letter. Affected indexes with alowerUTF8/upperUTF8preprocessor and patterns whose needle containsk. #117354 (Jimmy Aguilar Mena). - Fixed wrong results in five cases where a
WHEREpredicate on a join key was pushed to the other side of aJOINwhose two keys have different types. Such a key is no longer substituted when the keys’ common type is a float, because-0.0and+0.0are join-equal but differ bit for bit; nor when it isDynamicorJSON, whose runtime contents the static type does not describe; nor when the key is unstable within the query or changes the row count; nor in a conjunct that reads a column’s representation rather than its value, asisConstantandtoColumnTypeNamedo, including when such a read or an unstable function is hidden inside a lambda body. Separately, withenable_analyzer = 1, a predicate on the wider of two differently typed join keys is now also used as an index condition on the other table of a plainINNER JOIN, so it is read through its primary key instead of in full; previously onlyANY INNER JOIN,LEFT JOINandRIGHT JOINgot this. #117973 (Groene AI). Also fixed aLOGICAL_ERROR(Unexpected return type from _CAST) when such a predicate was pushed down to a side thatjoin_use_nullswidens toNullable. #120109 (Groene AI). - Fix rows silently dropped by index analysis for
has(array_of_named_tuples, key)when the tuple fields are declared in another order and the key is a function of the column. #118706 (Alexey Milovidov). - Fixed ClickHouse Keeper returning
ZNOAUTHfor every request on a node whose ACL list is empty but is stored under a nonzero internal ACL id, which happens for Keeper data converted from a ZooKeeper snapshot or written by a very old Keeper. Such nodes are unrestricted again, as they were before 26.6. Closes #117603. #118965 (Groene AI). - Fixed
YYYYMMDDhhmmssToDateTime64returning incorrect fractional seconds for timestamps before 1970-01-01. #119240 (Raúl Marín). - Fixed a crash when a disk is configured with
metadata_type = webormetadata_type = web_indexon top of a non-web object storage. Such a configuration is now rejected withINVALID_CONFIG_PARAMETERinstead of interpreting an unrelated object storage as a web one. Closes #119798. #119818 (Groene AI). Icebergtables recovered from stored metadata no longer enable background compaction or old-file cleanup unless those settings are explicitly stored in the table definition. #119977 (János Benjamin Antal).- Fixed a
NATStable whose settings all come from a named collection (ENGINE = NATS(collection)with noSETTINGSclause) being written to its metadata file with a danglingSETTINGSkeyword. The stored definition could not be parsed again, so the table failed to load and aborted the load of its whole database, making unrelated tables in it inaccessible. Closes #119120. #120025 (Groene AI). - Fixed non-idempotent formatting of a function named
SOME: the name was printed unquoted, so the server read its own output back as theSOMEarray quantifier.formatQuery('SELECT 1 < SOME(a, b -> 1)')returned a query that re-parses toarrayExists, and a user-defined function whose body compared against`some`(...)was persisted without the quotes and then failed to load after a restart. #120096 (Groene AI). - Fix reading a column that has two streams whose names differ only by escaping, for example a
Tupleelement namedsize0inside anArray, or a typedJSONpath named like a substream of a sibling path. Such columns returned wrong values, failed withCANNOT_READ_ALL_DATAor another exception, and made the table unmergeable. #115670 (Pavel Kruglov). - Fix
least,greatest,bitShiftRight,midpoint, andavg2returning wrong results when a JIT-compiled expression has anInt128result. With the defaultcompile_expressions = 1, a negativeInt128result could be treated as unsigned after a few executions. #118363 (Groene AI). - Fix
ttl_only_drop_partspreventing expired columns from ever being cleared. A columnTTLrequires rewriting the part, so with this setting enabled an expired column could be kept forever instead of being cleared. Column-TTLrewrites are now scheduled separately and still run whenttl_only_drop_partsis enabled. #118428 (Alexey Milovidov). - Fix
mergeTreeTextIndexbypassing row policies: reading the text index is now denied whenever a row policy applies to the table, regardless of which columns the policy uses. #119032 (Elmi Ahmadov). - Fix
force_primary_keyincorrectly rejecting some queries withINDEX_NOT_USEDwhenoptimize_extract_common_expressions(enabled by default) simplifies the filter to a trivial primary-key condition wrapped in an implicit cast. #119083 (kasimtj). - Fix
groupNumericIndexedVectorreturning a value that is too large when an index repeats in the input, and returning different results depending onmax_threads. Also fixnumericIndexedVectorPointwiseMultiplyandnumericIndexedVectorPointwiseDividedropping zero-valued indices, andnumericIndexedVectorPointwiseDivideby a vector of all ones keeping the value of an index the divisor is missing instead of zeroing it. AgroupNumericIndexedVectorStatealready stored in a table is not repaired by the upgrade and has to be recomputed. #119564 (Alexey Milovidov). isNullandIS NULLnow return1for everyNULLrow, including when the column’s NULL mask holds a byte other than0or1, which theNativeformat permits and whichifcan produce from its condition column. Previously such a row could contribute its raw byte, sosum(isNull(e))returned30where20is correct.if(cond, x, NULL)with aNullablexno longer returnsNULLfor a row whose condition byte was neither0nor1. If an older server stored a value computed fromisNullon such a column (sorting key, skip index, partition key, projection,MATERIALIZEDorDEFAULTcolumn), rebuild it. #119785 (Groene AI).- Preserve explicit time zones in
timeSeriesRangeDateTime64results. #119858 (Minh Vu).
Build/Testing/Packaging Improvement
- Added a CMake file for compiling ClickHouse with the
nvcccompiler. Related: #116807. #117734 (Konstantin Vedernikov). Added thecudfcontrib library. #117869 (Konstantin Vedernikov). - Added a build option to select 4 KiB or 16 KiB jemalloc page size on AArch64 instead of the default 64 KiB. #115424 (Azat Khuzhin).
- Fixed several portability issues on
illumos, including missingtermios.h, register-macro conflicts, and floating-point environment casts. #117363 (Joshua Carp). - ClickHouse is now built as a position independent executable on Linux amd64 and aarch64 with glibc, including the release builds, so the text segment is subject to ASLR. Addresses in the bare stack trace of a fatal log are now file offsets relative to the object that contains them, annotated with that object for frames outside the main executable, so they can be resolved with
addr2line -e <object> <hex>regardless of where the binary was loaded. For the same reasonsystem.errors.last_error_trace,system.error_log.last_error_traceandsystem.crash_log.tracenow store a frame of the main executable as its file offset, keeping runtime addresses for frames in other objects. #117449 (Groene AI). #119284 (Alexey Milovidov). - Fixed compilation of
benchmark_statisticswithENABLE_BENCHMARKS=ON. #116292 (Groene AI). - Use
cctztzdata 2026c. #116539 (Konstantin Bogdanov). - Restored the bundled
aws-c-httplibrary to v0.11.0 after it had been accidentally reverted to an older submodule revision. #116911 (Alexey Milovidov). - Fix building
ArrowFlightprotobuf files with the CMakeUnix Makefilesgenerator by creating theprotocoutput directory before invokingprotoc. #116879 (Alexey Bakharew). - Reduced compile time and object file sizes by removing redundant template instantiations in comparison functions, binary arithmetic,
arrayDistance, hashed dictionaries, andargMin/argMax. #117540 (Konstantin Bogdanov). - Fix building
unit_tests_dbmswhen ClickHouse is configured with-DENABLE_LIBRARIES=OFF(and-DENABLE_RUST=OFF). #105684 (Ivan Babrou). - Harden official builds by enabling full RELRO: the global offset table is now mapped read-only after startup. #119037 (Raúl Marín).
- Cross-compilation sysroots updated: FreeBSD builds now target FreeBSD 14 (13 is end-of-life), riscv64 and loongarch64 builds use current Debian glibc and kernel headers. Unused files were removed from the sysroot submodule. #119049 (Konstantin Bogdanov).
- Fixed startup of the shell-based Docker server images when an absolute
filesystem_cachespath is a missing directory below a directory the server does not own. The entrypoint now prepares these cache directories with the same ownership handling asstorage_configurationdisk paths. #118842 (thien-ch). - Update
opensslto 3.5.8. #118927 (Actuele AI). - Update
xxHashto v0.8.3. #117597 (Actuele AI). - Update
libxml2to 2.15.4. #118649 (Actuele AI). - Update
libdivideto v5.4.0. #118660 (Actuele AI). - Update
Jieba-CPPto v1.0.0. #118889 (Actuele AI). - Update
minizip-ngto 4.2.2. #118886 (Actuele AI). - Update
miniselectto 0.4.0. #118887 (Actuele AI). - Update
openldapto 2.6.15. #118888 (Actuele AI). #119359 (Actuele AI). - Update
sparsehash-c11to v2.11.1. #118891 (Actuele AI). - Bump
croaringfrom v4.5.1 to v5.1.1. Serialized bitmaps are unchanged on little-endian platforms; on big-endian platforms the on-disk layout ofgroupBitmapstates changes to the portable little-endian format. #118917 (Actuele AI). - Update
xzto v5.8.4. #119360 (Actuele AI). - Update
librdkafkato v2.15.1. #119467 (Actuele AI). - Update
simdjsonto v4.6.11. #119508 (Actuele AI). - Fixed building ClickHouse with
clang23, which emitted alifetime-safetydiagnostic that was suppressed only forclang24 and later. #118005 (Navneet Kumar). #119211 (mosya415).
ClickHouse release 26.8 LTS, 2026-08-27. Presentation, Video
Backward Incompatible Change
- The
X-ClickHouse-FormatHTTP request header now explicitly selects the format of the response: it is an alias for theoutput_formatsetting, so it overrides theFORMATclause of the query and the path extension. In previous versions, it only set the default when the output format was unspecified, like thedefault_formatparameter. This provides an “out-of-band” option to request data in a desired format. It never changes how the request body of anINSERTis parsed - useinput_formatorformatfor that. #105249 (Alexey Milovidov). - Unquoted JSON numbers for
DateTimeandDateTime64columns inJSONEachRowand similar formats are now interpreted as Unix timestamps with optional sub-second precision, consistent withValues,CAST, andtoDateTime64. Previously, a fractional number such as1703363853.035was rejected, and a bare integer such as1703363853was read as the raw scaled value ofDateTime64, producing a1970-...timestamp. Quoted strings and ClickHouse’s own JSON output are unaffected. #108091 (Alexey Milovidov). - The default value of
max_insert_threadschanged from1toauto, which resolves to the number of CPU cores available to the server. This parallelizesINSERT SELECTby default, andmax_insert_threadscan now also parallelize the writing side of a plainINSERTwhen the destination write path can safely fan out. This can change the number of parts created by such queries and the order of inserted rows. To restore the previous behavior, setmax_insert_threadsto1, or setcompatibilityto a version below26.8. #109000 (Alexey Milovidov). #109006 (Alexey Milovidov). - The
PostgreSQLandMaterializedPostgreSQLdatabase engines now respectremote_url_allow_hosts, like thePostgreSQLtable engine, thepostgresqltable function, and DDL-created dictionaries already do. Withremote_url_allow_hostsconfigured,CREATE DATABASEand user-issuedATTACH DATABASEnow rejectPostgreSQLandMaterializedPostgreSQLdatabases that point at disallowed hosts withUNACCEPTABLE_URL. Existing databases still load at server startup. #111135 (Alexey Milovidov). - The experimental
ALP(STD)codec now performsFloat32scaling arithmetic inFloat64. This improves compression ratios and eliminates exception-heavy compression of decimal data, butFloat32values written by earlier versions may now decode 1 ULP differently. #111627 (Raufs Dunamalijevs). - Removed the
librarydictionary source.SOURCE(LIBRARY(...))now fails withUNKNOWN_ELEMENT_IN_CONFIG, and thedictionaries_lib_pathserver setting is obsolete and has no effect. #111980 (Alexey Milovidov). - Removed the Apache Arrow library-based reader and writer for the
ArrowandArrowStreamformats. The native ClickHouse implementation, which has been the default since 26.7, is now the only one. The settingsinput_format_arrow_use_native_readerandoutput_format_arrow_use_native_writerare obsolete: they are still accepted, but have no effect, so a query that set them to0to force the Apache Arrow implementation now uses the native one. #111996 (Alexey Milovidov). - Reject timespan setting (milliseconds/seconds) values that overflow Int64 microseconds. #112757 (Azat Khuzhin). This might be an incompatibility only when you used absurdly large values that overflowed.
- TLS credentials of a
MySQLsource (ssl_ca,ssl_cert,ssl_key) can no longer be specified as file paths from SQL, such as inCREATE NAMED COLLECTION, query arguments, orCREATE DICTIONARY, because the server opens those files with its own privileges. Paths remain supported in the server configuration file. Elsewhere, pass the certificate or key contents in the newssl_ca_pem,ssl_cert_pem, andssl_key_pemparameters, which are masked in logs and inSHOWqueries like passwords are. #112070 (Alexey Milovidov). - Privilege checks for the
SYSTEM ... CACHE ON CLUSTERcommands now use each command’s own privilege instead of theSYSTEM DROP CACHEprivilege group. This lets holders of a single granular cache privilege run its matching command, and prevents a holder of the group from runningSYSTEM SYNC FILESYSTEM CACHE ON CLUSTERwithoutSYSTEM SYNC FILESYSTEM CACHE. #114042 (Groene AI). - For views whose body is a plain
SELECTover a singleDistributedtable, the whole outer query is now pushed to the shards (new settingoptimize_trivial_view_pushdown_to_distributed, enabled by default). This changes observable behaviour for such views:FINALandSAMPLEwritten on the view reference are now propagated to the shard-local table instead of being ignored, andextremesis not reported on single-shard clusters. Setoptimize_trivial_view_pushdown_to_distributed = 0to restore the previous behaviour. #101791 (simonmichal). - Lightweight
UPDATEpatch parts now use a new v2 on-disk format sorted by (sorting_key..., _block_number, _block_offset) and applied with a new merging algorithm. Peak memory is bounded by the largest equal-sort-key run instead of the full patch, and updates that cross merge boundaries no longer fall back to in-memory Join apply. Old-format patch parts remain readable. During a rolling upgrade from a version before 26.8, keeppatch_parts_version = 'v1'or use thecompatibilitysetting until all replicas are upgraded. #103182 (Anton Popov). - Added the
VALID FOR <interval>clause toCREATE USERandALTER USERas a shorthand forVALID UNTIL. The expiration deadline is computed as the current time plus the given interval at query execution time and stored in theVALID UNTILform. Thevalid_untilcolumn of thesystem.userstable now has the typeArray(DateTime64(0))instead ofArray(DateTime), so that deadlines beyond the year 2106 are represented exactly; tooling that reads this column should handle the new type. #110171 (Alexey Milovidov). EXPLAIN SYNTAXnow returns the reformatted query as a singleStringrecord (with embedded newlines) instead of one record per line, so its output is a recoverable single row that is directly usable (for example,SELECT count() FROM (EXPLAIN SYNTAX ...)returns1). This is controlled by the newsingle_recordoption, which defaults to1; setsingle_record = 0to restore the historical one-record-per-line output. OtherEXPLAINkinds (PLAN/PIPELINE/AST) keep their per-line tree output. #110479 (Alexey Milovidov).- Extended the supported range of
Date32from[1900-01-01, 2299-12-31]to[0000-01-01, 9999-12-31], matchingDateTime64. Parsing and conversions now accept the extended range instead of silently clamping to the old boundaries. Backward compatibility notes: in the numeric conversiontoDate32(N), values in[120530, 2932896]are now interpreted as day numbers (dates from2300-01-01to9999-12-31) instead of Unix timestamps in early 1970, matching the rule that a number that fits into the day-number range is a day number; numbers below the day number of0000-01-01and timestamps after9999-12-31saturate to the new boundaries. #111534 (Alexey Milovidov). arrayIntersectandarraySymmetricDifferenceno longer treat a value repeated inside a single argument as if it appeared in several arguments. Queries relying on the previous behavior can now return different results:arrayIntersect([1], [2], [1, 1])returns[]instead of[1],arrayIntersect([1, 2], [2], [1, 1, 2])returns[2]instead of[1, 2], andarraySymmetricDifference([1], [2], [1, 1])returns[2, 1]instead of[2]. ForarraySymmetricDifferencetwo arguments are already enough:arraySymmetricDifference([1], [2, 2])returns[2, 1]instead of[1]. A value is now counted for an argument only when it was present in every argument before it, so the result contains exactly the values present in all of the arguments. As part of the same change,arrayIntersectbuilds its hash table from the smallest argument rather than from all of them, which makes it up to 1.85x faster and use a third less memory when the arguments differ a lot in size.arrayUnionis not affected. #113021 (Alexey Milovidov).disable_insertion_and_mutationnow prevents background consumption fromKafka,RabbitMQ, andNATStables while still allowing direct writes to external storage. GatedKafka2,NATS, andRabbitMQtables do not initialize consumers for directSELECT. The recently introducedmessage_queue_disable_insertionsetting now requires a server restart. #113660 (Christoph Wurm).- A window
PARTITION BYorORDER BYover anAggregateFunctioncolumn is now rejected withILLEGAL_COLUMN, as top-levelORDER BYover such a column already was. Previously such a query was accepted by at least one analyzer, and windowPARTITION BYpartitioned differently depending onmax_threads. The refusal also covers a state nested inArray,Tuple,Map,VariantorSimpleAggregateFunction. ASimpleAggregateFunctionover an ordinary type,QBit, andGROUP BYandDISTINCTover a state, are unaffected. #113878 (Groene AI). - The
include_fromsetting no longer defaults to/etc/metrika.xml. Previously that file was used for configuration substitutions whenever it existed, even though nothing in the ClickHouse configuration referred to it. If you relied on that implicit substitutions file, add<include_from>/etc/metrika.xml</include_from>explicitly to each affected config file; separately loadedusers.xmland XML dictionary configs need their owninclude_fromelement. #114161 (Alexey Milovidov). - The
NATStable engine accepts credentials inline in the newnats_credentialssetting (the same payload as a.credsfile), and no longer acceptsnats_credential_filefrom SQL: the path is a reference to a file on the server filesystem, which the server opens with its own privileges, so it can only be specified in a named collection defined in the server configuration file, or asnats.credential_filein the server configuration itself. A query may replace such a configured path with inlinenats_credentials, unless the operator pinned it with<nats_credential_file overridable="false">. Tables created before this restriction keep working after an upgrade. #114644 (Alexey Milovidov). - Asynchronous metrics can now have the
Mapdata type, and the per-CPU-core and per-device metrics were converted to single key-value metrics:OSUserTimeCPU0,OSUserTimeCPU1, … became a singleOSUserTimeCPUmetric with a map from the CPU core number to the value (and similarly for the otherOS*TimeCPU*metrics,CPUFrequencyMHz_*,Temperature*,EDAC*,Block*_*,Network(Receive|Send)*_*,Disk*_*,*BlobsQueueEstimate, andAsyncLogging*QueueSize).system.asynchronous_metricshas a newkey_values Map(LowCardinality(String), Float64)column (thevaluecolumn isNaNfor such metrics),system.asynchronous_metric_loglogs them as one row per key using a newkeycolumn, the Prometheus endpoint exports them with a label (e.g.ClickHouseAsyncMetrics_BlockReadBytes{device="sda"}), and the GraphiteMetricsTransmittersends them as<prefix>.<Metric>.<key>. If your monitoring reads the old metric names, set the newasynchronous_metrics_key_values_modeserver setting tolegacy_namesto publish every key as a separate scalar metric under its previous name again, or tobothto publish both forms at the same time while the monitoring is being migrated; the setting is applied bySYSTEM RELOAD CONFIG, without a restart. #115333 (Alexey Milovidov). #116791 (Alexey Milovidov).
New Feature
- Added
CREATE HANDLER,ALTER HANDLERandDROP HANDLERstatements to define custom HTTP handlers from SQL, persisted in a local or Keeper storage. Added thecurrentHandlerandcurrentRequestURLfunctions, thesystem.handlerstable, and thehttp_handler_name/http_request_urlcolumns insystem.query_log. #106231 (Alexey Milovidov). - Added a way to access tables and databases via URL paths in the HTTP interface (e.g. `/database/table.format.gz?filter=a>0`), plus new settings (`http_allow_database_as_path`, `http_allow_table_as_file`, `http_allow_filters_as_path`, `http_allow_filters_as_unrecognized_url_parameters`, `select`, `order`, `sort`, `filter`, `page`, `compression`, `format`, `input_format`, `output_format`, `default_format`, `database`) that compose with one another and with the existing `query` URL parameter. #105249 (Alexey Milovidov).
- Add framing formats, selected by the new setting
framing_output_format: they multiplex different response parts of the query in a single HTTP response stream — chunks of data, totals and extremes, progress packets, profile events, server logs, and exceptions. Implemented framing formats:None(default, everything works as before),EventStream(HTTP server-sent events),JSONEachPacketBase64, andJSONEachPacketString(a JSON object per packet with base64-encoded or string data). #110127 (Alexey Milovidov). - Added the
default_session_userserver setting: the user to authenticate as when a client connects without specifying a user name (previously hardcoded todefault; the native, MySQL, and PostgreSQL protocols now accept an empty user name instead of rejecting it, and Arrow Flight honors the setting instead of its own hardcodeddefault). Composable protocol endpoints in theprotocolssection can override it per endpoint with adefault_session_userkey, so different listening ports can serve different anonymous users. Setting it to an empty string prohibits connections without a user name. Interserver connections never use the default session user. #110179 (Alexey Milovidov). - Support pipe operators in SQL queries:
FROM t |> WHERE x > 1 |> AGGREGATE count() AS c GROUP BY y |> ORDER BY c DESC |> LIMIT 10, similar to the pipe syntax of GoogleSQL. AnySELECTquery can be followed by a chain of|>operators, and each operator wraps the query before it into a subquery, so the resulting AST is the same as for the equivalent query with nested subqueries. In a query that starts with theFROMclause, theSELECTclause is now optional and defaults toSELECT *. #111151 (Alexey Milovidov). - Added the
parseQueryToJSONandformatQueryFromJSONfunctions to serialize and deserialize ASTs as JSON, and an experimentalclickhouse_jsondialect enabled byenable_json_ast_dialect. #100412 (Alexey Milovidov). #113480 (Nikita Fomichev). - New setting
run_query_in_background. The server accepts the query, immediately returns an empty result, and runs it to completion regardless of what happens to the connection. The result is discarded. Track the query by itsquery_idinsystem.processesandsystem.query_log. Intended for long queries likeINSERT ... SELECT,CREATE TABLE … AS SELECT, orCREATE MATERIALIZED VIEW … POPULATEthat must not die with a dropped connection. #112816 (Miсhael Stetsyuk). - Added a new system table,
system.user_query_log, which shows every user their own query log records without requiring access to the query log table. The original implementation and the idea belong to Yue Ni (@niyue), #104462. #110156 (Alexey Milovidov). - Implement the remaining items of the URL unification (issue #59617). The new
s3_basesetting resolves relative URLs in thes3table function and theS3table engine (and the functions sharing their configuration:s3Cluster,gcs,oss), similarly tourl_base. The newURLdatabase engine treats table names as URLs, resolves them against an optional base URL, and dispatches by the URL scheme, so files, web and object storage are handled uniformly. It replacesFilesystemin the default (Overlay) database ofclickhouse-localwith afile://base URL, so plain file names keep working, and you can also writeSELECT * FROM 'https://example.com/data.csv'. #111512 (Alexey Milovidov). - Added the
bigquerytable function and theBigQuerytable engine for reading from and writing to Google BigQuery tables, including public datasets. The table structure is inferred from the BigQuery table schema. Authentication supports an OAuth access token, a service account key inJSONformat, and an OAuth client with a refresh token. #110166 (Alexey Milovidov). - Plain
CREATE MATERIALIZED VIEW ... POPULATEis now locally atomic: the view is subscribed to new inserts of the source table and the existing data is snapshotted together under a brief exclusive lock on the source, so rows inserted through the same server concurrently with the population are no longer missed or duplicated (new settingmaterialized_views_populate_atomically, enabled by default). The guarantee covers the local insert path only; inserts arriving on another replica or through a distributed write path are outside the cut, and it requires a source that can provide a pinned snapshot (theMergeTreefamily andMemory); other sources, as well asCREATE OR REPLACE/REPLACEand views created inReplicateddatabases, keep the legacy non-atomic population.POPULATEcan now also be used together withTOto backfill the target table. #108715 (Alexey Milovidov). - Keeper can store data on disk now, in a custom LSM tree. It has similar performance to the previous storage. Use coordnation setting
use_lsmt_storage = trueto enable,storage_memory_only = falseto store files on disk, adddata_storage_pathordata_storage_diskto config to specify where to put the files. To write to S3, pointdata_storage_diskto a disk of types3_plain. #113903 (Michael Kolupaev). - The “S3 tables” engine catalog for data lakes, the same as #103220 but with a working
INSERT. #113505 (Konstantin Vedernikov). - Add support for Snowflake Horizon. You can now query Iceberg table in Iceberg behind the horizon catalog. You can also write to the Iceberg table via the catalog. #114547 (Melvyn Peignon).
- Added support for the
Puffinfile format. It can be used with thefile,url,s3, and similar table functions. #103936 (Konstantin Vedernikov). - Support the
GROUPSframe mode for window functions (SQL:2011), e.g.any(price) OVER (PARTITION BY symbol ORDER BY ts GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING). In aGROUPSframe the boundaries count whole peer groups — sets of rows that are equal on theORDER BYkey — soN PRECEDING/N FOLLOWINGmeanNpeer groups before/after the current row’s peer group, rather than physical rows (ROWS) orORDER BYvalue distances (RANGE). #108653 (Nihal Z. Miaji). - Added the
mergeTreeCodecBlockCountstable function, which reports for each part, column, and substream of aMergeTreetable how many compressed blocks use each codec. #109623 (Raufs Dunamalijevs). - Added the
MultiPointgeo data type, stored asArray(Point), and included it in theGeometrytype. #109951 (David Meng). - Added the
_etagvirtual column forHDFSstorage. #108255 (Zhang Yifan). - The native
ORCreader and output format now supportuniontype, mapping it to the ClickHouseVarianttype. Previously, reading such columns failed withUnsupported ORC type, and writing them failed withILLEGAL_COLUMN. #110078 (Alexey Milovidov). #110085 (Alexey Milovidov). - Added a
japanesetokenizer for text indexes and thetokens,hasAnyTokens, andhasAllTokensfunctions, using the MeCab morphological analyzer. The dictionary is loaded at runtime from a location set in the server configuration and verified against a SHA-256 checksum before use. #111420 (Jimmy Aguilar Mena). - Added a
chinesetokenizer for thetokensfunction andMergeTreetext indexes. It segments Chinese text into words using a dictionary and a Hidden Markov Model (the algorithm follows jieba), withcoarse_grained(default) andfine_grainedgranularities. Continues #80174. #89945 (Amos Bird). - Added a new
icutokenizer for text indexes and thetokens,hasAnyTokens, andhasAllTokensfunctions, providing locale-aware Unicode word segmentation (including dictionary-based segmentation for languages such as Chinese, Japanese, and Thai). #109940 (Jimmy Aguilar Mena). - Added a
splitByRegexptokenizer for text indexes and thetokensfunction. It splits the input into tokens using a regular expression as the separator, for exampletokenizer = splitByRegexp('[^\p{L}\p{N}#+]+'), which allows preserving tokens containing special characters such asC++orC#that other tokenizers would break apart. #110002 (Jimmy Aguilar Mena). - The Keeper HTTP dashboard now includes a Cluster tab that shows Raft membership as a topology graph with health colors, lag, and priority, so you can see which nodes are healthy, lagging, or unreachable and open the leader’s dashboard directly. #111655 (yanglongwei).
- A new server configuration section,
create_union_system_log_tables, requests the creation and automatic maintenance ofall_...tables (e.g.system.all_query_log) that query the union of a system log table, its rotated versions and/or the same tables across all replicas of a cluster. Theremote,remoteSecure,clusterandclusterAllReplicastable functions now accept a trailingSETTINGSclause with the settings of theDistributedstorage they create, e.g.clusterAllReplicas('default', system.query_log, SETTINGS skip_unavailable_shards = 1). #112670 (Alexey Milovidov). - Add
nats_credentialssetting to the NATS table engine, allowing users to specify NATS credentials inline as a string (matching the payload of a.credsfile). #110733 (addshore). - Added the sort-based
IEJoinalgorithm for joins whoseONclause has two inequality comparisons (<,<=,>,>=) between the joined tables, enabled by addingie_jointo thejoin_algorithmsetting. Supported kinds areALL INNER/LEFT/RIGHT/FULL JOINandSEMI/ANTI LEFT/RIGHT JOIN. Previously such queries were executed as aCROSS JOINwith a filter (INNERonly), which is much slower on large tables. #109920 (Vladimir Cherkasov). - Added the aggregate function
gini, which computes the Gini coefficient of finite, non-negative numeric values, including grouped and distributed aggregations. #112280 (Amirreza Akhondi). #114643 (Groene AI). - Added the
HiveTextoutput format, which writes Apache HiveLazySimpleSerDetext. Fields are separated by\x01; rows by theformat_hive_text_rows_delimitersetting (default\n); and nestedArray,Map, andTuplevalues use Hive’s separator list. The output targets Hive’s defaultLazySimpleSerDeand is not symmetric with ClickHouse’sHiveTextinput for nested values or custom row delimiters. #107582 (Alexey Milovidov). - Added support for constant labels on the Prometheus metrics endpoint: a new
<labels>section inside<prometheus>adds the configured labels to every exposed metric, which helps distinguish multiple clusters scraped by the same Prometheus. Label values support standard config substitutions such asfrom_env. Closes #85969. #111672 (Valery Petrov). - Added the
always_fetch_mutated_partsetting. When enabled, a replica can download mutated parts from another replica instead of executing mutations locally. #113020 (Rory Shanks). - Added the aggregate function
mergedJSONPatchfor RFC 7396-style merge-patch aggregation overJSONvalues, including state-merge support andAggregatingMergeTreeusage. Users can aggregate aJSONcolumn using a timestamp or another ordering column as the sort key to compute the latest state. #108349 (larryluogit). - Added the
aiSimilarityfunction, which computes the semantic similarity between two texts using an embedding model. It returns aNullable(Float32)in[-1, 1], where1means the texts are identical, orNULLif an operand isNULL/empty or its embedding failed. #110777 (David Meng). - Add
restore_table_data,restore_access_entities, andrestore_functionsrestore settings for granular control over what gets restored. These can overridestructure_onlyfor individual categories — e.g.structure_only=true, restore_access_entities=truerestores table definitions and access entities without table data. #102402 (Nikita Fomichev). - The array subscript operator supports an array of integers as the index:
arr[indexes]returns the elements at all of the given positions, equivalently toarrayMap(i -> arr[i], indexes). #108371 (folly). - Add function
notHas, the negation ofhasfor arrays, maps, and JSON. When the haystack is a constant array,notHas(constant_array, x)is rewritten tox NOT IN constant_arraybyoptimize_rewrite_has_to_in(enabled by default), so it executes via a set lookup and can prune by the primary key index likeNOT IN. #109926 (Nihal Z. Miaji). - Functions
arrayElement(thevec[n]operator) andarraySlicenow work for theQBitdata type:qbit[n]returns the n-th vector element at full precision, andarraySlice(qbit, offset, length)returns a projection to a subset of dimensions. Both read only the bit planes of the stride groups they need, and slices aligned to stride-group boundaries reuse the stored streams without copying. This closes #109942. #109953 (Utkal Singh). - Support animated PNG in the
PNGoutput format. Atcolumn turns the result of a query into an animation, with the time scale oftset byoutput_format_image_time_multiplier_secondsandoutput_format_image_time_divisor_seconds, andoutput_format_image_streaming_animationto write the frames out as the query produces them instead of buffering them in memory. #112846 (Alexey Milovidov). - New function
aiRedactthat detects and redacts personally identifiable information (PII) in text using an LLM provider. Specify the categories to redact (e.g.['email', 'name']) or pass an empty array to use a default set of PII categories. Matched values are replaced with a token ([REDACTED]by default). #110464 (David Meng). - Add
aiFilterfunction that evaluates a natural-language condition against text with an LLM and returnsUInt8for use inWHERE,PREWHERE, andJOIN ... ON. #110594 (yanglongwei). - Support TLS/SSL connections to PostgreSQL for the
PostgreSQLtable engine, thepostgresqltable function, thePostgreSQLandMaterializedPostgreSQLdatabase engines, andPostgreSQLdictionaries:sslmodeplus the certificates and the key, given either as literal contents (sslrootcert_pem,sslcert_pem,sslkey_pem; masked like passwords) or as paths (sslrootcert,sslcert,sslkey; accepted only from a named collection defined in the server configuration file). #110615 (Alexey Milovidov). - ClickHouse server now has an introspection port. This is a native protocol TCP listener that starts before the server begins attaching tables and stops only after the tables’ detach completes. During these windows, an operator can connect to it with
clickhouse clientand run queries such asSHOW PROCESSLIST,SELECT * FROM system.stack_trace, orSYSTEM INSTRUMENT ADD 'QueryMetricLog::startQuery' SLEEP ENTRY 0.5. Additionally, the default value of theshutdown_wait_unfinishedserver setting is increased from 5 to 120 seconds. The previous default was smaller than the connection poll interval, so the server could force exit in the middle of shutdown instead of waiting for outstanding connections to finish. #110838 (Miсhael Stetsyuk). - Introduce emulated ZooKeeper metrics in Keeper
mntrcommand:zk_leader_uptime,zk_sum_election_time,zk_cnt_election_time,zk_sum_leader_unavailable_time,zk_cnt_leader_unavailable_time; Also introduce related leader-oriented metrics for Keeper only:KeeperLastLeaderElectionTime,KeeperLastLeaderUnavailableTime. #113334 (Maxim Orlovsky). - Support ALTER TABLE … MODIFY PROJECTION to change projection-level settings (e.g. index_granularity) of an existing projection without rebuilding it. The new settings apply lazily via merges. #113343 (Diego Gomes Tomé).
- Added a
finish_timecolumn tosystem.mutationsthat records when a mutation was completed. Unfinished mutations and mutations whose completion time is unknown report zero. #113474 (Nikita Mikhaylov). - Added a new
private previewfeature tier betweenexperimentalandbeta, so feature tiers are now orderedexperimental < private preview < beta < production. The server settingallow_feature_tiergains a level:0allows all tiers,1excludes experimental,2additionally excludes private preview, and3allows production settings only. Configurations that previously pinnedallow_feature_tier = 2to allow production settings only must now use3. Closes #113481. #113581 (Groene AI). - The built-in Web SQL UI (
/play) can now sort a result by its columns, filter it by their values, and page through it, without editing the query. Sorting arrows and a filter input appear in every column header, a selected cell offers the comparisons that fit its value, and a pager with an adjustable page size appears under a result that does not fit on one screen. It is all performed by the server, using theorder,filter,limitandpagequery-construction settings, so the whole result is shaped rather than the rows that happen to be displayed; the chosen sort, filters and page travel in the page URL, so a shared link reproduces the result. #115540 (Alexey Milovidov). chdigv26.8.1: ratatui, tmux panes, tmuxinator sessions, sharing logs with colors, feature tour. #115216 (Azat Khuzhin).
Experimental Feature
- Added an experimental Cascades cost-based optimizer for distributed query plans, enabled by
enable_cascades_optimizer = 1together withmake_distributed_plan = 1. It chooses between shuffle, broadcast, replicated, and local join strategies, two-phase, shuffle, and local aggregation, two-stage distributed top-N, and parallel and replicated reads by estimated cost, inserting exchange operators as needed. #86353 (Alexander Gololobov). - Added an experimental
MergeTreesettingenable_adaptive_codec_selection. When enabled, merges and mutations pick the smallest-output codec per block for columns that use the default codec. #111834 (Raufs Dunamalijevs). * Adaptive codec selection now compresses with each candidate codec at most once per block instead of measuring all candidates and then recompressing the winner. #113511 (Raufs Dunamalijevs). - The
clickhousebinary builds for WebAssembly (wasm64, via Emscripten), andclickhouse localruns queries, includingMergeTreetables, under Node.js ≥ 24 and in the browser. A newBuild (wasm64)CI job pins the build and the Node.js execution path (the browser path is not covered by CI yet) and provides the WebAssembly module as an artifact. #113404 (Alexey Milovidov). parallel_replicas_plan_basednow chooses the local/remote boundary by optimizing the query plan, can parallelize queries over views with aUNIONwithoutparallel_replicas_allow_view_over_mergetree, falls back to the local plan forIN (subquery)queries instead of failing, and now also distributes eligibleJOINs (INNER,LEFT,RIGHT, includingSEMI/ANTI). #111063 (Igor Nikonov). #112268 (Igor Nikonov). #112443 (Igor Nikonov).- Distributed query plans (
make_distributed_plan) now also support queries whose source is known at planning time to produce no rows, such as reads from an emptyMergeTreetable. #111941 (Groene AI). - Added the
use_projection_index_in_read_poolssetting, disabled by default. When enabled, ranges fully filtered out by a projection or skip index are dropped insideMergeTreeread pools before read tasks are created for them, instead of being skipped granule by granule during reading. This avoids creating read tasks and setting up readers for data that will not be read. #110291 (Nikolai Kochetov). #112296 (Anton Popov). - PromQL: fixed operations on instant vectors without tags, e.g.
vector(1) + vector(2),topk(1, vector(1)),label_replace(vector(1), ...)and binary operators withon(), which failed with a type error. #111872 (Valery Petrov). - PromQL: implemented the
changesandresetsfunctions. #112352 (Valery Petrov). - Report the error that cancelled a distributed query (
make_distributed_plan = 1) instead of a bareQUERY_WAS_CANCELLED. A failing worker task’s real error was previously visible only in the server log. #112590 (Alexander Gololobov). - When
make_distributed_plan = 1, ClickHouse now disables features that distributed query plans do not support yet instead of letting them fail later. Closes #109476. #112463 (alesapin). - Distributed query plans (
make_distributed_plan) now use lazy materialization forORDER BY ... LIMIT kqueries. #113111 (Shankar Iyer). - Support non-partitioned window functions (
OVER (ORDER BY ...)) in distributed query plans (make_distributed_plan). Previously any query with a window function failed becauseWindowStepcould not be serialized for remote execution; windows withPARTITION BYare still rejected for now. #109802 (Vighnesh Pathrikar). - Added the setting
use_query_condition_cache_for_top_k, which gates the query condition cache forORDER BY ... LIMIT n(TopK) queries. #111492 (Alexey Milovidov). The query condition cache is now enabled by default for queries that use theORDER BY <column> LIMIT n(TopK) optimization. It can be turned off again with the settinguse_query_condition_cache_for_top_k. #114539 (Alexey Milovidov). - Added static partition-to-shard affinity for
StorageKafka2via thekafka_partition_shard_numandkafka_shard_countsettings, allowing multiple ClickHouse shards to deterministically consume disjoint subsets of Kafka partitions. #108886 (johnjing). - Harden the experimental AI functions: deny insecure (
http) endpoints to remote hosts by default (new settingai_function_allow_insecure_endpoint), bound outbound API calls per query by default (ai_function_max_api_calls_per_querynow defaults to1000), and sanitize provider error responses written to the logs. #111286 (George Larionov). - PromQL:
quantilewith a quantile level outside [0, 1] now returns -Inf/+Inf/NaN like Prometheus instead of throwing an error, andhistogram_quantilenow ignores input series whoselelabel is missing or unparsable, like Prometheus. #111871 (Valery Petrov). - Allow multi-component identifiers in TimeSeries tables. #112799 (Vitaly Baranov).
- Added
TimeSeriessettingssamples_index_granularityandtags_inner_granularityto control the index granularity of inner tables. #113075 (Vitaly Baranov). - PromQL: added the
derivfunction and fixed a bug where its backing aggregate function returned values 1000x too small with millisecond-resolution timestamps. #112360 (Valery Petrov). - PromQL: reject invalid cross-delimiter escapes in strings and invalid Unicode surrogate code points. #113587 (Minh Vu). #113203 (Minh Vu).
- PromQL: preserve finite values when using modulo with an infinite divisor. #113746 (Minh Vu).
- PromQL: date/time functions
hour,minute,month,year,day_of_week,day_of_month,day_of_year, anddays_in_monthcan now be called without arguments, defaulting tovector(time())as in Prometheus. #111869 (Valery Petrov). - PromQL now supports the Prometheus HTTP API
lookback_deltaparameter for instant and range queries. #113971 (Minh Vu). - Distributed query plans (
make_distributed_plan) now supportIN (subquery)without rewriting it to aJOIN: the set is built once on the initiator and its values are shipped with the worker tasks. The forcedrewrite_in_to_joinoverride is removed; the rewrite remains available as an explicit setting. #113826 (Alexander Gololobov). - Streaming queries support watermarks. #106169 (Mikhail Artemenko).
- Added a read-through filesystem cache to the experimental
ReaderExecutorread path (use_reader_executor, disabled by default). #110029 (Sema Checherinda). - PromQL: implemented functions
clamp,clamp_min,clamp_max, andround. #111870 (Valery Petrov). - Correctly collect insert stats and queries through the Prometheus remote-write endpoint. #112825 (James Cunningham).
- PromQL aggregation operators now accept mixed letter casing, matching Prometheus. #114076 (Minh Vu).
- TimeSeries: store all tags in the
tagscolumn. #114300 (Vitaly Baranov). - Apply the read-in-order optimization to
ORDER BYqueries whenparallel_replicas_plan_basedis enabled: the sort is now shipped to the replicas and merged on the initiator, so each replica reads in the sorting key order. Also fixesUnknown function __topKFilterforORDER BYon a non-primary-key column with this setting enabled. #114315 (Igor Nikonov). - Reject literal line feeds in ordinary quoted PromQL strings. #114381 (Minh Vu).
- Fix duplicated
GROUP BYkeys in the partial aggregation strategy ofmake_distributed_plan, and allow this strategy for aggregations over a distributed read. #114523 (Alexander Gololobov). - Throw exception on violating the allowlist of hypothetical index types for WHATIF. #114646 (Yarik Briukhovetskyi).
- Restores quantized sub-column read for vector search (introduced in 26.7). #114763 (Shankar Iyer).
- The experimental
TimeSeriestable engine no longer applies theGorillacodec to auto-createdvaluecolumns of the samples inner table; they now default toCODEC(ZSTD(1)). Explicitly declared columns keep whatever codecs the user wrote. Thetimestampcolumn default is unchanged (CODEC(DoubleDelta, ZSTD(1))). #114790 (Nikita Mikhaylov). - A distributed plan query (
make_distributed_plan) now stops its upstream stages when aLIMITis satisfied, instead of computing the full result and discarding it. #114806 (Alexander Gololobov). - Added a userspace page cache tier to the experimental
ReaderExecutorread path (use_reader_executor, off by default). On a miss the executor now populates the userspace page cache and serves subsequent reads from it, zero-copy. #114890 (Sema Checherinda). - Support
ROLLUP,CUBE,GROUPING SETSand thegroupingfunction in queries executed withmake_distributed_plan = 1. #114950 (Alexander Gololobov). - Fix the error
Illegal type Decimal(18, 0) of argument of function toIntervalNanosecondwhen a PromQL query usesoffsetinside a range selector, e.g.rate(m[2m] offset 5m). #114997 (Nikita Mikhaylov). - A very large
distributed_plan_workers_numno longer makes the server abort with astd::length_errorwhen the experimentalmake_distributed_planandenable_cascades_optimizerare enabled. Such a node count is now rejected withINVALID_SETTING_VALUE. #115398 (Groene AI). - Support
GROUPING SETSaggregation in distributed plans built by the Cascades optimizer (make_distributed_plan = 1, enable_cascades_optimizer = 1). #115426 (Alexander Gololobov). TimeSeriestables can now keep a “recent samples” table: when the new engine settingrecent_samples_ttl_secondsis non-zero, the engine creates a TTL’d copy of the samples table (partitioned byrecent_samples_partition_by, by day by default) written on every insert, and PromQL queries whose time range fits in the TTL window automatically read from it, making alert/recording rules and short-range dashboards several times faster on large tables. The preference can be disabled with the new query-level settingtime_series_prefer_recent_samples_table. #115441 (Nikita Mikhaylov).- Implement SELECT query from TimeSeries. #115622 (Vitaly Baranov).
- Implement the
/api/v1/seriesendpoint of the Prometheus HTTP API forTimeSeriestables:match[]series selectors (repeated values are a union), an optionalstart/endtime range, and an optionallimitparameter. #115676 (Nikita Mikhaylov). - Distributed query plans (
make_distributed_plan) now stop idle upstream stages promptly after a satisfiedLIMIT: an idle exchange sink readsNoMoreDataNeededas soon as it arrives, and an idle exchange source notices its closed output and forwards the stop upstream. Previously such stages kept reading and computing data that nobody consumes. #115690 (Alexander Gololobov). - Automatic parallel replicas can now collect runtime statistics and enable parallel replicas for supported queries when
parallel_replicas_plan_basedis enabled. #115788 (Igor Nikonov). - Register an external recent samples table of a TimeSeries table as a referential dependency. #115944 (Groene AI).
Performance Improvement
- New adaptive algorithm for parallel
GROUP BY(controlled via settingenable_adaptive_aggregator, enabled by default): each thread aggregates into its own hash table until it holdsadaptive_aggregator_freeze_thresholdkeys and then freezes it, so frequent keys keep updating the small cache-resident tables with no coordination, while rare keys are routed by their hash into per-bucket backlogs and aggregated exactly once, inside the bucket-parallel merge. #111459 (Nihal Z. Miaji). - Reduced memory usage of
MergeTreetables with many data parts by sharing the schema-derived per-part metadata (column list, column descriptions, serializations, and columns substreams) across parts of a table instead of copying it into every part. The effect is largest for wide tables with many small parts. #109816 (Raúl Marín). - Optimize
GROUP BY ... ORDER BY ... LIMITandGROUP BY ... LIMITqueries by maintaining a bounded heap during aggregation to prune groups that cannot appear in the result, significantly reducing memory usage and execution time for high-cardinality grouping. Controlled by theenable_group_by_top_k_optimizationsetting. Based on the initial implementation by Dmitriy Terenichev (#78553). #96630 (Konstantin Bogdanov). - Reduce hash-table cell size for single-
Stringaggregation keys, improving string-heavyGROUP BYworkloads. The newenable_packed_string_keys_in_aggregationsetting is enabled by default; disabling it, or settingcompatibilitybelow26.8, restores the legacyStringHashTablemethod, which can still be faster for very low-cardinality aggregation with keys longer than 11 bytes. #110573 (Harikrishnan Prabakaran). #112089 (Harikrishnan Prabakaran). - Parallelize the final merge of single-level aggregation hash tables with the new
enable_parallel_single_level_mergesetting, enabled by default. This speeds upGROUP BYqueries whose per-thread hash tables stay below the two-level threshold but whose merge dominates the runtime. #110395 (Nihal Z. Miaji). - Improve performance of
DISTINCTwhen the input stream is sorted by a prefix of the distinct columns, for exampleSELECT DISTINCT a, b FROM table ORDER BY a. Such queries run up to 2.4 times faster. #110170 (Nihal Z. Miaji). - Speed up and reduce the memory usage of
DISTINCTqueries on partitionedMergeTreetables by keeping each partition’s rows within a single stream, so each stream’s preliminaryDISTINCTworks on a disjoint set of keys, instead of the same set of keys appearing in multiple preliminaryDISTINCTs. This applies when the partition expression is a deterministic function of theDISTINCTcolumns, and is gated by a cost heuristic on partition count and skew (which can be toggled by settingforce_distinct_partitions_independently, disabled by default). The same per-partition disjointness is propagated throughExpression,FilterandARRAY JOINsteps to the finalDISTINCT,LIMIT BYandGROUP BYconsumers so they can skip their merge too. Controlled by the new settingsallow_distinct_partitions_independently(enabled by default) andmax_number_of_partitions_for_independent_distinctto tune the heuristic. #108326 (Nihal Z. Miaji). - Optimized functions
uniq,uniqExact, anduniqHLL12in aggregation without key. #110150 (Anton Popov). - The
ParquetV3 reader can now skip whole row groups using the dictionary page, in addition to min/max statistics and bloom filters, for equality andINconditions when a column chunk is fully dictionary-encoded. Controlled by the newinput_format_parquet_dictionary_filter_push_downsetting. #106952 (Alexey Milovidov). #110567 (Alexey Milovidov). - Lazy materialization for reading
Parquetfiles from object storage, includingIcebergtables: forORDER BY ... LIMIT nqueries, the columns that are not needed for sorting and filtering are read only for thenrows that survive theLIMIT. On a 200 MBParquetfile onS3,SELECT k, s ... ORDER BY k DESC LIMIT 10reads 3.3 MB instead of 171 MB (51x less I/O, 8x faster). Controlled by the new settingquery_plan_optimize_lazy_materialization_for_object_storage(enabled by default, and also requiresquery_plan_optimize_lazy_materialization). #110970 (Alexey Milovidov). * Lazy materialization forORDER BY ... LIMIT nqueries (#110970) now also applies to local Parquet files read with thefiletable function and theFiletable engine: the columns that are not needed for sorting and filtering are read only for thenrows that survive theLIMIT. The second read of a surviving file fails close with the newFILE_CHANGED_DURING_READerror if the file was modified between the two passes. Controlled by the new settingquery_plan_optimize_lazy_materialization_for_file(enabled by default). Also fixes lazy materialization for object storage failing withNot found column or subcolumn ... in blockwhen a requested subcolumn (e.g. of aJSONcolumn) is deferred. #114262 (Alexey Milovidov). - Column statistics are now materialized on
INSERTby default when the table’s current active size plus the written block size is at most the newmaterialize_statistics_on_insert_max_table_sizesetting (default 25 GiB); the check is per written block, so a first bulk load into an empty table may still materialize statistics for each written block. This gives the cost-based join optimizer accurate estimates for freshly-loaded dimension tables and avoids pathological join orders (for example, TPC-H Q5 and Q8 no longer time out at scale factor 40), while large established fact tables keep materializing statistics during merges. #109454 (Alexey Milovidov). - Speed up window functions on partitioned
MergeTreetables by reading each partition through its own stream and evaluating the windows per partition, skipping the hash scatter that ordinarily reshuffles every row across threads before the window sort. This applies when the table partition expression is a deterministic function of the windowPARTITION BYcolumns and is gated by the same cost heuristic as per-partitionGROUP BY/DISTINCT(enough partitions relative tomax_threads, no dominant partition). Controlled by the new settingsallow_window_partitions_independently(enabled by default),force_window_partitions_independently, andmax_number_of_partitions_for_independent_window. #114783 (Nihal Z. Miaji). - Reduce memory usage when writing packed parts by streaming the final archive directly into the destination file instead of holding a second full copy in memory during part commit. #111995 (Alexey Milovidov).
- Added a new
join_algorithmvalueparallel_full_sorting_merge: for hash-compatible equality joins, it shards a full sorting merge join by the hash of the join keys into independent per-shard merge joins running on all threads. It keeps the low, streaming memory usage of a merge join while parallelizing it (in a benchmark, ~2.4x faster and ~3.3x less memory thanparallel_hash).ASOFjoins fall back to a singlefull_sorting_merge; hash-incompatible key types (floating-point,JSON,Object,Dynamic) skip only the hash-scatter rewrite and can still be sharded at the source by primary-key ranges whenquery_plan_join_shard_by_pk_rangesis enabled. The result is not ordered. #109005 (Alexey Milovidov). - Add GeoParquet spatial pruning at row-group and page levels to the
Parquetreader. Row-group pruning skips entire row groups whose bounding box does not overlap the query geometry. Page-level pruning uses thecovering.bboxcolumn index to skip irrelevant pages within row groups, and spatial predicate pushdown now also applies duringParquetrow reading. #104435 (Vasily Chekalkin). - Parquet filter push-down (row group pruning and column index) supports more type conversions:
DateTime64(x) <-> DateTime64(y),Decimal(x) <-> Decimal(y),Float32 <-> Float64. #110457 (Michael Kolupaev). - Reduce duplicated read requests on remote disks when mark ranges are fragmented, for example by primary or skip indexes. #113584 (Anton Popov).
- Speed up execution of
INover clustered (e.g. sorted by primary key) columns by reusing the previous row’s result for equal consecutive rows. #114853 (Nikita Mikhaylov). - An aggregation without
GROUP BYkeys no longer fans its single-row output out tomax_threadsstreams, so queries whose plan continues after such an aggregation get a much smaller pipeline (fewer processors to create, schedule and profile) without losing any parallelism. #115170 (Nikita Mikhaylov). - Keeper now reads changelog entries with less lock contention: catch-up reads plan under a shared lock and do disk I/O lock-free, and both follower catch-up and the commit path can pre-decode entries in a background thread pool, reducing redundant disk reads and CPU decoding on the leader. #108473 (Antonio Andelic).
- Speed up Keeper startup by reading multiple changelog files concurrently instead of serially, controlled by new settings
log_startup_read_max_streamsandlog_startup_read_buffer_size. #109881 (Antonio Andelic). - Add a new
bucketedschema type forsystem.metric_log, which stores all metrics in a singleMap(Enum16(...), Int64)column using the bucketedMapserialization with 128 buckets, plus a per-metricALIAScolumn for compatibility: the table consists of a few columns instead of thousands, zero values are not stored, and reading a single metric reads only one of the 128 buckets. In addition, aMapwithEnumkeys can now be indexed by the string name of the enum value, e.g.map['name']. #115380 (Alexey Milovidov). - Added a query plan optimization that pushes volume-reducing functions (
length,lengthUTF8,empty,notEmpty) below theSortingandFiltersteps, replacing the wideString/FixedStringargument with the fixed-size result, so it is neither buffered by a sort nor copied by a filter. Controlled by the new settingquery_plan_push_down_volume_reducing_functions, enabled by default. #106199 (Peng). - Enable
read_in_order_use_virtual_rowby default. When reading in order of the primary key (e.g.ORDER BY primary_key LIMIT n) over a table with many parts, only the parts that can actually contribute to the result are read (plus a read-ahead window of at mostmax_threadsparts that keeps reading parallel), which significantly reduces peak memory consumption. #106215 (Alexey Milovidov). - Aggregation queries without aggregate functions now use
HashSet-based methods instead ofHashMap(for supported key types). Speedups up to 1.8x times were observed. #108862 (Nikita Taranov). - Avoid
JOINruntime-filter overhead when the probe side is estimated to be small. The threshold is controlled by the newjoin_runtime_filter_min_probe_rowssetting (default1000). #104860 (Vladimir Cherkasov). - Queries with predicates like
nullIf(key, sentinel) = constcan now use primary-key, partition, and skip-index pruning. #107308 (Aditya Kumar). - Added the
jemalloc_merge_tree_arenasserver setting to control dedicated jemalloc arena(s) forMergeTreepart and table metadata. On many-core servers, a per-CPU pool can reduce allocator lock contention between concurrent merges, and the dedicated arena now only holds long-lived metadata. #109490 (Raúl Marín). - Sped up ZSTD decompression on
x86_64for columns with small match offsets, such as fixed-width integer columns, by vectorizing short-offset overlapping copies with SSSE3pshufb. For example, decompression of aUInt64column is up to ~1.2x faster on AMD Zen 5. #110909 (Konstantin Bogdanov). - Speed up
groupUniqArrayfor numeric types by up to 3x by using CRC32 hashing, as inuniqExact, and by inlining per-row insertion. #110917 (Manuel). - Faster
estimateCompressionRatiowith theNONEcodec. #111107 (Raufs Dunamalijevs). - Lowered the default
max_snapshot_commit_thread_pool_sizeto16, matchingbackup_threads, to reduce CFS throttling when committing snapshots for tables with many parts. #111417 (Han Fei). - Reduce CPU usage when committing snapshots for tables with huge numbers of files. #112297 (Han Fei).
- Skip async-insert deduplication hash prewarming when deduplication is disabled. #111549 (Sema Checherinda).
- A
JOINwhoseONcondition is always false, for exampleON 1 = 2,ON NULL, ora.t = 'A' AND a.t = 'B', no longer reads the non-contributing side. Controlled by thequery_plan_short_circuit_constant_false_joinsetting (enabled by default). #110234 (Groene AI). - Speed up reading of
Icebergtables by prefetching the next manifest file while the current manifest is being parsed, overlapping I/O with CPU work. #108543 (Asya Shneerson). - Queries with
FINALthat read in primary-key order with a smallLIMITno longer usesplit_intersecting_parts_ranges_into_layers_final. #110431 (Nikolai Kochetov). - Improve performance of
RIGHTandFULL JOINwith theparallel_hashalgorithm when the right side containsNULLjoin keys or rows filtered by theONexpression, by avoiding null-map rebuilding. #111258 (Hechem Selmi). - Speed up
countSubstringsCaseInsensitiveUTF8by fixing quadratic complexity that could make the function take minutes on a haystack of a few megabytes with many matches. #112003 (Groene AI). - The Prometheus query API (
/api/v1/query,/api/v1/query_range) of the experimentalTimeSeriesengine now executes queries in parallel instead of on a single thread. #112108 (Nikita Mikhaylov). - Auto-created
timestampandvaluecolumns of theTimeSeriessamples inner table now default toCODEC(DoubleDelta, ZSTD(1))andCODEC(Gorilla, ZSTD(1))respectively. #112110 (Nikita Mikhaylov). - Fix a performance regression in
system.query_logingestion. Building theSettingsandasynchronous_read_countersmap columns was about six times slower than before, which could makeSYSTEM FLUSH LOGS query_logexceed its 180-second timeout on servers that log many queries with many changed settings. Closes #112191. #112210 (Groene AI). - Improve performance of RIGHT and FULL hash JOIN with multiple
ORdisjuncts in the ON section, and of RIGHT/FULL JOIN with residual (inequality) conditions. #111590 (Hechem Selmi). - Reduce memory usage of
UNLOCK SNAPSHOTby not loading per-data-part metadata that the unlock path does not use, avoiding out-of-memory for snapshots with a very large number of parts. #111849 (Julia Kartseva). - Restore memory pre-allocation for dynamic paths of a
JSONcolumn during asynchronousINSERTflushes, avoiding repeated reallocations while batched rows are appended. #112222 (Groene AI). - Re-enable the consecutive-keys optimization for
TTL ... GROUP BYaggregation during merges. It had been accidentally disabled on that path, so results stayed correct but merges did more work than necessary. #112314 (Groene AI). - Speed up reading
Nestedcolumns from binary-encoded types such asNativeandRowBinarywheninput_format_binary_decode_types_in_binary_formatis enabled, and report malformed nestedTupletype names as a syntax error instead of spending exponential time parsing them. #112560 (Alexey Milovidov). - Improved performance of squashing and merging
DynamicandObjectcolumns with many dynamic variants or JSON paths. #110583 (Christoph Viebig). - Speed up
minandmaxon 128-bit and 256-bit types (Int128,UInt128,Int256,UInt256,Decimal128,Decimal256). Up to 1.8x faster for wide integers and up to 3.4x faster for wide decimals. #111965 (Manuel). - Enabled by default (and promoted to beta) two on-disk features: 1)
packed_skip_index_max_bytes = '1M': skip-index substreams up to 1 MiB are now written into a singleskp_idx.packedarchive per part, reducing object count and write requests on object storage. Compatibility: only newly written parts are affected and they stay fully readable on older versions; versions before 26.6 simply do not use the packed indices for pruning (they are treated as not materialized). Setpacked_skip_index_max_bytes = 0to keep the standalone per-file layout. 2)compute_exact_num_defaults_for_sparse_columnsplusoptimize_trivial_count_with_sparsity_filter: exact per-columnnum_defaultscounters are persisted and used to answerSELECT count() FROM t WHERE <pred>without a data scan when the predicate splits rows into defaults vs non-defaults. Compatibility: theexact_num_defaultsflag inserialization.jsonis ignored by older versions, so parts remain fully readable after a downgrade; the count rewrite only applies to parts that carry exact counters, so results stay correct on tables with mixed parts. #111816 (Raúl Marín). - Add optional caching for tokens missing from text indexes. #112742 (Rory Shanks).
- Fixed quadratic reallocation when replicating an
Arraywhose elements holdJSONvalues in shared data, for example a constantArray(JSON)passed to an aggregate function. Such queries copied a number of bytes that grew quadratically with the row count. #112897 (Groene AI). - Use the primary key index for
pointInPolygonwhen the point argument is a whole key column of typePoint(or anotherTupleof two numeric elements), e.g.pointInPolygon(coord, [...])for a table ordered bycoord. Previously only thepointInPolygon((x, y), [...])form with two scalar key columns was analyzed. Closes #54805. #112956 (Alexey Milovidov). - Skip the data-reading step entirely for
TTLDropmerges to reduce memory usage, especially for read and prefetch buffers. Closes #105639. #105859 (Pavel Kruglov). - Reduce memory allocations when reading backup metadata by moving file entries into in-memory maps instead of copying them. #111718 (Julia Kartseva).
- Use the text index when its expression contains an empty-string comparison such as
arrayFilter(s -> s != '', ...), even whenoptimize_empty_string_comparisons = 1rewrites it tonotEmpty. Closes #111788. #112115 (Jimmy Aguilar Mena). - Restore query condition cache pruning after a
lightweight DELETE: repeated selective queries over a table that had ever been touched by alightweight DELETEno longer fall back to reading every mark. #112947 (Nikita Fomichev). - Higher-order functions no longer physically copy captured columns for every array element when
enable_lazy_columns_replicationis enabled, reducing memory usage and copying time for lambdas that capture large columns. #111581 (Diego Gomes Tomé). - Fixed a ~1.5x performance regression introduced in 26.5 in
GROUP BYoverDynamickeys andJSONpath subcolumns. #112316 (Utkal Singh). text_index_posting_list_apply_modenow defaults tolazy, so text index queries decode posting lists on demand at packed-block granularity with a cursor instead of eagerly materializing them into bitmaps for text indexes withposting_list_codecset. #113521 (Anton Popov).- Speed up PromQL queries over
TimeSeriestables:timeSeriesIdToGroupnow reuses the previous row’s group when consecutive rows carry the same series id, skipping the per-row id serialization and hash lookup. #113580 (Nikita Mikhaylov). - PromQL aggregation operators
topk,bottomk, andlimitknow use a streaming, parallel execution plan with bounded memory instead of collecting all series into a single row. Queries over high-cardinality metrics that previously failed withMEMORY_LIMIT_EXCEEDEDnow run in bounded memory. #113656 (Nikita Mikhaylov). #114409 (Alexey Milovidov). - Speed up division of 256-bit integers (
Int256,UInt256, andDecimal256), affectingintDiv,modulo,Decimal256arithmetic, and conversion of these types to text. #112477 (Konstantin Bogdanov). - Improve
MergeTreeread performance forJSONsubcolumns by reusing resolved subcolumn metadata during required conversions. #113008 (Rory Shanks). - Speed up building text and bloom-filter-based skip indexes with the
sparseGramstokenizer. #110541 (UnamedRus). - Snapshot creation now uses a dedicated thread pool, so a heavy concurrent
BACKUPno longer starves it. #113509 (Han Fei). - Evaluate PromQL subexpressions shared by multiple plan steps (the
topk/bottomk/limitkoperand, the left side ofor) once instead of twice: the SQL generated from PromQL now materializes shared subqueries. This removes a duplicated scan of the samples table;topkoverrategets ~2x faster cold, and kubernetes-mixin rule queries improve by 10-29%. #113772 (Nikita Mikhaylov). - You can now enable early short-circuit folding for builtin
andandorduring analysis with theenable_function_early_short_circuitsetting. This can skip executing dead single-rowcount()scalar subqueries while preserving normal type inference and semantic validation. Resolves #83017. #83505 (fhw12345). - Combine I/O cost with selectivity in
PREWHEREcondition ordering. This fixes a performance regression ofPREWHEREexecution in some cases introduced after #101275. Part of #110462. #110695 (Pavel Kruglov). - Improved the performance of
levenshteinDistance(andeditDistance) for medium-length strings on ARM by avoiding per-row heap allocations in the blocked Myers code path. #108185 (Groene AI). - Add the
merge_use_batch_sorting_queueMergeTreesetting to optionally use the batch sorting queue for ordinaryMergeTreemerges, reducing CPU and wall-clock time for merge workloads where sorted merging is a significant cost. #108468 (Rory Shanks). - Added the
merge_tree_min_bytes_per_read_streamsetting to reduce excessive read streams and pipeline overhead for ordinary local unordered narrow-columnMergeTreescans on high core-count servers. #109035 (Jiebin Sun). - Speed up function
toStartOfInterval(aliasestime_bucket,date_bin) by up to 5x forSECOND,MINUTEandHOURintervals. #109729 (Manuel). - The native protocol now sends
Stringcolumns as a separate stream of cumulative byte offsets (the same layoutArrayuses for its offsets) followed by the concatenated data, instead of a per-value varint length prefix, once both peers are on protocol revision 54489 or newer. A client can then readStringcolumns with exact buffer preallocation and a single bulk copy, about 4 times faster than the per-value layout. Old clients and servers are unaffected: the layout is negotiated through the protocol revision. The same layout is available in theNativeandBuffersformats through the new settingsoutput_format_native_write_string_with_size_stream/input_format_native_read_string_with_size_stream(off by default, so the formats stay portable). #110320 (vahid-sohrabloo). - Avoid eager JSON serialization of Iceberg manifest entries when iceberg_metadata_log_level is below the call site’s threshold. #110437 (Andy Bradshaw).
- Improve full sorting merge join performance up to 1.5-3x times on sparse scenarios. #111200 (Vladimir Cherkasov).
- Improve efficiency of minmax and basic column statistics for floating point columns. #111221 (Christoph Viebig).
- Enable
join_runtime_filter_from_fixed_hash_tablewhen the probe and build join key types differ (for example, a Nullable probe key with a non-Nullable build key). #111244 (Hechem Selmi). - Returns
COUNT()queries directly from the text index cardinality metadata. #111494 (Elmi Ahmadov). - Sped up row-wise hashing of JSON/
Objectcolumn values stored in shared data (used e.g. byuniq/uniqExactover a JSON column and by hashedGROUP BY/DISTINCTkeys) by avoiding a per-valueColumnDynamicreconstruction. Hash values are unchanged. #111501 (Valery Petrov). - Functions
mapContainsKeyLike,mapContainsValueLike,mapExtractKeyLike, andmapExtractValueLikewith a non-constant pattern use less memory and time when enable_lazy_columns_replication is enabled. The pattern is no longer eagerly copied per map entry at capture time; the copy is deferred to the execution of the internal lambda and is freed sooner, so one fewer expanded copy of the pattern exists at peak. #111749 (Diego Gomes Tomé). - Speed up sorting and other comparison-based operations over
JSONcolumns whose paths are stored in shared data. Previously each value comparison materialized a temporaryDynamiccolumn and ran a full binary deserialization for both sides, makingORDER BYover such columns pathologically slow. #111894 (Groene AI). clickhouse-clientno longer pings the server before every query, which removes a network round trip per query. It also no longer re-establishes the connection - silently starting a new session, and so losing temporary tables, the current database and session settings - just because the server was too slow to answer a ping. #111990 (Alexey Milovidov).- Use the transitive conditions optimization more wisely: the additional filter created by transitivity is now used only for index analysis where the whole filter cannot be applied. See the
optimize_and_compare_chainsetting. #112076 (Yarik Briukhovetskyi). - Added two settings,
shrink_over_allocated_columns_min_waste_ratioandshrink_over_allocated_columns_min_waste_bytes, that make INSERTs shrink over-allocated columns (whose reserved memory exceeds used memory due to power-of-two growth of variable-length columns) to fit before materialization and part writing, reducing peak memory usage. Disabled by default.. #112161 (Pavel Kruglov). - Lazy column replication for
ARRAY JOINis no longer lost when a query plan is serialized. Withserialize_query_plan = 1, the node executing a remote plan fragment used to ignoreenable_lazy_columns_replicationand always materialize every replicated copy, even though the setting defaults to enabled. #112330 (Groene AI). - Formatting
Decimalvalues as text is much faster — up to 190 times for aDecimal256with a large scale, and about 1.6 times for aDecimal64. On processors with AVX-512 IFMA, converting 64-bit integers to text is about 1.4 times faster. Also fixed the rounding oftoDecimalString, which dropped a carry out of the fractional part:toDecimalString(toDecimal64('9.995', 3), 2)returned9.00and now returns10.00. #112457 (Konstantin Bogdanov). - A
WHEREequality is now merged into theJOINcondition when its operands have different types but a common supertype, such asInt32andNullable(Int32). This allows a CROSS join to be converted to an INNER Join. #112630 (Hechem Selmi). - Queries on Iceberg tables with many delete files now start faster. ClickHouse reads and decodes the delete manifest files concurrently instead of one at a time, so their storage reads overlap. The new setting
iceberg_delete_manifest_decode_concurrency(default4) controls how many are decoded at the same time. #112679 (Asya Shneerson). - Asynchronous logging now uses a bounded lock-free queue: threads writing log messages never block on a mutex or wake up the logging threads. #112803 (Alexey Milovidov).
randomHadamardTransformof a constant vector is now evaluated once instead of once per row. This speeds up vector search queries that rotate the query vector withrandomHadamardTransformbefore comparing it against aQBitcolumn. #112921 (Alexey Milovidov).- Restores set sharing between the part tasks of one mutation filtering on
IN (subquery)over a primary key column.enable_sharing_sets_for_mutationsis on by default, but the set built for primary key analysis stopped participating in the shared cache, so a table with N parts materialized the same set N times. #112941 (Groene AI). - Fixed cubic complexity of query planning for a JOIN with a
Mergetable over many tables with different structures. Such queries could previously spend minutes in query planning without responding tomax_execution_timeorKILL QUERY. #113140 (Alexey Milovidov). - The bucket-region cache of the
S3client now also works for data lake catalogs; previously every request to them resolved the region again. #113330 (Konstantin Vedernikov). - Fixed a performance regression where an aggregation without
GROUP BYkeys serialized its whole input plan subtree, including the full contents of constant-folded literals, on every execution to compute a hash-table-size cache key it can never use. A query such asSELECT quantileMerge(arrayJoin(arrayMap(x -> state, range(5000000))))spent about 63 ms per execution in query-plan optimization and now spends 0.15 ms. #113333 (Groene AI). - Add opt-in Parquet serialization of UInt128/UInt256/Int128/Int256 as DECIMAL to enable row group and page pruning. #113347 (Ivan Babrou).
- Speed up query planning when
uniq_v2column statistics are used. The estimated number of distinct values is now cached instead of being recomputed on every request, which query planning issues many times per query. (issue #113038). #113357 (Groene AI). - Do not prefetch unneeded substreams when reading a whole JSON path from advanced shared data. #113380 (Pavel Kruglov).
- Filter pushdown now works for
Tuplesubcolumns in Parquet and ORC files. A predicate such asWHERE tup.1 = 555555overfile,s3orurlnow prunes row groups and row index strides using the tuple element’s own statistics instead of reading the whole file. #113383 (Groene AI). - Replaced the per-bucket hash map inside the
timeSeries*ToGridaggregate functions with a flat sorted array of samples: sample ingestion becomes an O(1) append for in-order inputs (the overwhelmingly common case) and the per-bucket copy-and-sort at finalization is gone. #113681 (Nikita Mikhaylov). - Improve PromQL query performance over the TimeSeries engine: the internal selector SQL now reads the samples-table primary-key columns directly (without no-op casts) and checks the timestamp range before the series-id set, which makes cold selector-heavy queries 30-44% faster. #113768 (Nikita Mikhaylov).
- Use typed id maps in the time-series tags collector. #113839 (Vitaly Baranov).
- Skip the redundant sortedness scan when writing MergeTree parts whose sorting keys are all constant. #113899 (Perfloop Agent).
- PromQL selectors that match all series of one metric now filter the samples table of a
TimeSeriestable with a continuous primary-key range onidduring index analysis instead of a largeid IN <set>condition, when the id layout is a two-component tuple with the canonical id generator. Removes the dominant single-threaded index-analysis cost of selector-heavy PromQL queries: up to −45% cold latency on dashboard and rule query shapes, −11% cold geomean over the full suite on a 62-billion-sample table. #114131 (Nikita Mikhaylov). - Speed up vectorized TimeSeries tag transformations by replacing hash-based remapping with direct indexing when tag-group IDs occupy a compact range. #114244 (Minh Vu).
- The Prometheus HTTP API endpoints
/api/v1/queryand/api/v1/query_rangenow evaluate a PromQL subquery shared by several plan steps once, as theprometheusQueryandprometheusQueryRangetable functions already did. Previously a request made withenable_analyzer = 0, or by a user whose profile sets it, rescanned the shared subquery once per referencing step. #114261 (Groene AI). - Bounded the cost of estimating the selectivity of
col IN (...)from column statistics, which could add hundreds of milliseconds to the planning of a single query. The estimator no longer runs the subquery behindcol IN (subquery)to fill a set it only needs one selectivity number from — an unbuilt set is skipped instead. For a set larger than the newstatistics_max_set_size_for_exact_selectivity_estimationsetting (default 10000), the selectivity is now derived from the size of the set and its bounding range. #114389 (Nikita Taranov). - Parsing an HTTP request that carries many query parameters or headers with the same name (for example thousands of repeated
role=parameters) no longer takes quadratic time. #114410 (James). - Fixed a regression in 26.7: for a
MergeTreetable ordered bytoUnixTimestamp(or another integer conversion) of aDateTime64column, a plain range filter on that column no longer used the primary key and read all granules of the matched parts. Additionally, a filter liketoInt64(ts) >= cover a table ordered by the rawDateTime64column now uses the primary key. #114413 (Alexey Milovidov). - The heavy consistency check in
ColumnArrayis now performed only in debug builds. #114469 (Anton Popov). - Do not merge-sort a distributed gather whose sort description is all-constant. #114626 (Groene AI).
- Speed up set building for
IN (subquery)on partitionedMergeTreetables by keeping each partition’s rows within a single stream and deduplicating each stream independently, so the single set-filling transform — previously hashing every row serially — only sees unique rows. This applies when the partition expression is a deterministic function of the subquery’s output columns. The optimization is not applied when the largest partition holds more than twice the rows of the average partition; the new settingforce_creating_set_partitions_independently(disabled by default) bypasses this check. Controlled by the new settingallow_creating_set_partitions_independently(enabled by default). #114645 (Nihal Z. Miaji). - Parallelize the single-level to two-level conversion of per-thread aggregation states before merging. This fixes a 2-3x regression of short
GROUP BYqueries with heavy aggregate states (e.g.COUNT(DISTINCT ...), ClickBench Q10/Q11) on machines with very many cores, introduced in 26.7 development builds when the aggregation memory accounting was made accurate. #114691 (Alexey Milovidov). - Speed up the
timeSeries*ToGridaggregate functions: per-sample bucket math now avoids Int128 division, and consecutive samples in the same bucket skip the hash-map lookup. #114889 (Nikita Mikhaylov). - Appending to a system log queue no longer deep-copies the whole queue when it grows. #115030 (Groene AI).
- Process samples of the
timeSeries*ToGridaggregate functions in runs of consecutive samples falling into one grid bucket, speeding up the sample-ingestion stage oftimeSeriesRateToGridand related functions by 1.2-2x on sorted time series data. #115041 (Nikita Mikhaylov). - Use compact presence masks for PromQL set operators. #115224 (Minh Vu).
- Faster evaluation of PromQL instant queries: the
timeSeries*ToGridaggregate functions use the vectorized sample-classification path for single-point grids, andtimeSeriesIdToGroupfills its result column directly. #115267 (Nikita Mikhaylov). - A
JOINwhoseONsection has severalOR-ed equalities no longer materializes the right-hand key columns that the query does not select. #115465 (Nikita Taranov). - Naming a
DateTimeorDateTime64type no longer builds a UTC time zone lookup table that nothing reads, which makes constructing these types — and therefore starting upclickhouse localandclickhouse client— faster. #115488 (Konstantin Bogdanov). - Attaching the system tables no longer copies each table’s metadata, including its full column description, twice just to set the table comment. #115490 (Konstantin Bogdanov).
- The client hostname is now resolved when it is first reported instead of on every
clickhouse clientandclickhouse localinvocation. #115491 (Konstantin Bogdanov). - Fixed quadratic time when the functions
h3kRing,h3ToChildren,h3PolygonToCellsandh3PolygonToCellsWithContainmentbuild their result over many rows. A query over 196 000 rows spent 838 seconds copying memory in a CI stress run; it now takes about 5 seconds. #115773 (Groene AI). - Speed up duplicate-series checks for all-zero PromQL condition vectors. #115822 (Minh Vu).
- Speeds up
GROUP BYwithout aggregate functions overString,FixedStringandLowCardinalitykeys: the query no longer rewrites an unused placeholder into the hash table for every row, only for the rows that add a new key. #115834 (Nikita Taranov). - Speed up
toUTCTimestamp/to_utc_timestampandfromUTCTimestamp/from_utc_timestamponDateTime64arguments, restoring the throughput they had before the overflow fix in #109738. Results are unchanged. Closes #115802. #115838 (Groene AI). - Reduced memory usage and query-plan optimization time for keyed aggregations over large constant-folded literals. The aggregation hash-table-statistics cache key is now hashed as it is serialized instead of being accumulated in memory first, so a plan carrying a large literal no longer holds a copy of it during optimization. For an 80 MB literal, peak memory drops by about 250 MB and optimization time by about 2.5x. The computed key is unchanged. #115847 (Groene AI).
Improvement
- Outgoing OpenAI-format HTTP requests are now tagged with the SQL name of the calling AI function for upstream endpoint identification. #110449 (George Larionov).
- Reduce cancellation latency for positive forms of
LIMIT BY:KILL QUERYand Ctrl+C now interrupt within a single chunk instead of waiting for the whole step to finish. #106070 (Roman Vasin). - When an
INSERTfails because a materialized view’sTOtarget table rejects the write while the insert pipeline is being built, the error message now names the materialized view and its target table instead of only reporting the bare storage error. #107234 (Groene AI). - With
input_format_protobuf_oneof_presence, ClickHouse no longer requires theoneofpresence enum to list exactly the tags declared in the Protobuf schema: extra tags without matching columns in the target table are now allowed, which makes schema changes easier. #109174 (Ilya Golshtein). - The transposed distance functions over
QBit(L2DistanceTransposed,cosineDistanceTransposed,dotProductTransposed, and their quantized variants) now accept a reference vector longer than the number of searched dimensions, ignoring the extra trailing elements. This allows reusing a full-size query vector for a reduced-dimension Matryoshka search without slicing it first. #109388 (Alexey Milovidov). - The
basicstatisticsNullCountsub-statistic is renamed toDefaultCountand now counts rows equal to the column type’s default value, not onlyNULLrows ofNullablecolumns. #109977 (Han Fei). - Support concurrent writes to
Icebergtables on a local disk:LocalObjectStoragenow implements conditional writes, so the compare-and-swap that publishes a new snapshot throughversion-hint.textworks there and concurrent writers cannot lose each other’s updates. #112556 (Alexey Milovidov). ALTER TABLE ... MOVE/REPLACE PARTITIONbetween twoMergeTreetables with incompatible granularity now throwsBAD_ARGUMENTSinstead ofLOGICAL_ERROR. #110535 (Groene AI).- The
Valuesformat no longer records false parse errors insystem.errorsandsystem.error_logwhen streaming parsing successfully falls back to SQL expression parsing. #111141 (Pablo Marcos). - Added the
DuplicationDataHashComputationsProfileEvent, which counts column-wise data-hash computations performed while deduplicatingINSERTblocks into*MergeTreetables. #111173 (Valery Petrov). - Highlight the
./clickhouseandsudo ./clickhouse installcommands in the universal installation script output. #111514 (Alexey Milovidov). - Cartesian joins and analyzer-planned constant-predicate joins no longer fail because of an incompatible
join_algorithmsetting when the analyzer is used. #108289 (János Benjamin Antal). bitmaskToArrayandbitmaskToListnow supportInt128,UInt128,Int256, andUInt256arguments.bitPositionsToArrayis also faster for big-integer arguments because it now scales with the number of set bits rather than the highest set-bit position. #110743 (Manuel).- Fix a crash in JIT-compiled expressions on native from-source macOS/aarch64 builds by using the correct LLVM host triple for the host OS. #111591 (Raúl Marín).
- Fix
JSON_EXISTS,JSON_VALUE, andJSON_QUERYonDynamicinput when tuple path arguments containLowCardinalityelements, avoidingLOGICAL_ERRORexceptions. Closes #110345. #109944 (Groene AI). - Corrupt
ORCfiles whose type tree declares more columns than the stripe footer now fail schema inference withCANNOT_EXTRACT_TABLE_STRUCTUREinstead of aborting in debug/sanitizer builds. #110967 (Groene AI). - Rotated system log tables, such as
system.metric_log, can now be markedtable_readonlyeven when their metadata exceedsmax_query_size, so rotation no longer logsQUERY_IS_TOO_LARGEand continues normally. #111703 (Alexey Milovidov). - In Play, added a button to close all tabs except the current one. #111835 (Mikhail Artemenko). Fixed keyboard focus after activating it with Enter or Space when the button hides itself. #111899 (Alexey Milovidov).
- In Play, holding
Ctrl(Cmdon Mac) while hovering over a table cell whose value is an image URL now shows an image preview. #109347 (Alexey Milovidov). - On Linux, ClickHouse now adds a
system.warningsentry at startup whenrseqis unavailable, because per-CPU profile counters then fall back to a slowersched_getcpupath. #109283 (Azat Khuzhin). COUNT(*)over thefiletable function no longer throws an exception when schema inference wraps columns inNullable. Closes #102044. #102509 (Rory Shanks).- Functions
L1Normalize,L2Normalize,LinfNormalize, andLpNormalize(and their aliases) now work forArrayarguments, not onlyTuplearguments, consistently withL2Normand the distance functions. #110052 (Alexey Milovidov). - Removed the legacy Apache Arrow-based
ORCreader. TheORCinput format now always uses the native ClickHouse decoder, which was already the default. Theinput_format_orc_use_fast_decodersetting is obsolete and has no effect. #110074 (Alexey Milovidov). - Made commonly used
clickhouse-clientarguments configurable from XML (<hints/>,<highlight/>,<echo/>,<echo_query_id/>,<echo_formatted/>,<print-profile-events/>), and preserved client-config values when the corresponding defaulted CLI flags are omitted, for settings such ashistory_max_entries,suggestion_limit,progress,progress-table,enable_progress_table_toggle,print-memory-to-stderr,chime-threshold-seconds, andprofile-events-delay-ms. #110607 (Larry Snizek). - Added the
analyzer_compatibility_apply_final_to_all_joined_tablessetting to restore the old behavior whereFINALon the left-most table of aJOINalso applies to the other joined tables. The setting is registered in the settings changes history, socompatibilitywith versions before 26.6 restores the old semantics automatically. #111589 (Nikita Fomichev). - In Play, the
+(new tab) button now renders at the correct height in Firefox. #109524 (Alexey Milovidov). - A nested correlated
EXISTSsubquery that references a column from a scope beyond its immediate outer query now fails withNOT_IMPLEMENTEDinstead of the internalNOT_FOUND_COLUMN_IN_BLOCKexception. #110310 (Groene AI). - Formatting an
EXECUTE ASquery after AST rewrites no longer throws a client-side exception, for example in the AST fuzzer. #111725 (Groene AI). - Improve
DESCRIBEquery support for parameterized views, and support parameterized views in scalar expressions in the new analyzer. Closes #66307. Closes #69598. #68978 (Dmitry Novik). - Malformed
CREATE INDEXandCREATE HYPOTHETICAL INDEXexpressions that cannot survive a format-parse-format round trip now report an exception instead of hitting anInconsistent AST formattinglogical error in debug and sanitizer builds. #109175 (Groene AI). - Web UI: fix the user/password field staying red even when the credentials are correct and the server is reachable, and re-check credentials after editing the connection so a correct value turns green. #109414 (Alexey Milovidov).
- Added the
text_index_max_processed_tokens_before_flushandtext_index_max_memory_usage_before_flushsettings to control when text index builders flush temporary segments. #111573 (Rory Shanks). - Added the
system_cache_extensionssetting to control which file extensions are stored in the system cache whenuse_split_cacheis enabled. #111575 (Kirill). - Error messages on musl-based builds now show the human-readable
strerrortext instead of an empty or numeric value such asstrerror: 0. #111620 (Konstantin Bogdanov). - The effective named collections storage type is now available as
named_collections_storage.typeinsystem.server_settingsand viagetServerSetting('named_collections_storage_type'). #111806 (Pablo Marcos). - Relaxes an overly strict permutation size check in
ColumnReplicated::permuteso that it follows the generalIColumn::permutecontract, which allows a permutation shorter than the column when a limit is set. #109897 (Groene AI). - Improve planning of streaming queries by unifying the internal streaming read plan, which avoids double-optimizing direct text-index reads. #111821 (Mikhail Artemenko).
- Web UI: the gap between the
Run oneandRun allbuttons now matches the left margin before the first button. #111988 (Alexey Milovidov). - Memory reservation scheduling (experimental) no longer evicts an allocation when a pending memory release would free the room needed by an over-limit reservation increase: the eviction decision now waits for in-flight decreases to be applied, avoiding unnecessary query kills under memory pressure. #112299 (Sergei Trifonov).
- Iceberg v2 requires
sequence_numberin manifest files, but other engines such as BigQuery can write manifest files without it. ClickHouse can now read such tables. #112431 (Konstantin Vedernikov). - Show warning when statistics for join reordering are missing. #107666 (Vladimir Cherkasov).
- Added MySQL-compatibility columns to
INFORMATION_SCHEMAviews:SCHEMATA.DEFAULT_COLLATION_NAMEandDEFAULT_ENCRYPTION;TABLES.ENGINEand related MySQL columns; andCOLUMNS.COLUMN_KEY,PRIVILEGES,GENERATION_EXPRESSION,SRS_ID. This lets MySQL-aware clients run their catalog introspection queries without hittingUNKNOWN_IDENTIFIER. #109351 (Alexey Milovidov). - An unqualified reference to an
INNER JOINkey that is equated in theONcondition (e.g.SELECT id FROM a INNER JOIN b ON a.id = b.id) is no longer reported as an ambiguous identifier, since both sides are guaranteed to carry the same value. #109366 (Alexey Milovidov). - Return HTTP code
403 Forbidden(instead of500 Internal Server Error) forACCESS_DENIEDexceptions over the HTTP interface. #111043 (Schum). - Write the UNIQUE KEY index SST directly into part storage instead of staging it in a local temporary file, removing the dependency on a local temporary volume and avoiding an extra copy. #111189 (johnjing).
UTMToGeonow accepts the MGRS latitude band letter returned bygeoToUTMas its fourth argument (in addition to the integer hemisphere flag), so ageoToUTMresult round-trips throughUTMToGeodirectly. #111521 (Alexey Milovidov).- Fix a
LOGICAL_ERROR(“Part level Min-Max index was constructed from unexpected columns set”) that could abort a background merge in debug/sanitizer builds afterpart_minmax_index_columnswas lowered (for example fromwith_block_number_offsetback topartition_key_only). #111511 (Groene AI). - Fixes
ProfileEvents['JoinResultRowCount']under-reporting the result size of aJOINthat spills to disk. Rows emitted from delayed buckets were counted only inJoinDelayedJoinedTransformRowCountand were missing from the total. Query results were always correct; only the profile event was wrong. #112673 (Groene AI). SYSTEM DISABLE FAILPOINTnow rejects a fail point name that does not exist, raisingBAD_ARGUMENTSlikeSYSTEM ENABLE FAILPOINTalready did. Previously a mistyped name reported success while leaving the intended fail point enabled, with no indication that nothing had been disabled. #112680 (Groene AI).- Added a new column
skipping_indices_typesto thesystem.tablestable. It contains the distinct types of data-skipping indices defined for each table. #106388 (Anton Popov). - Added a sanity check that a distributed query always carries a known client version, throwing a logical error instead of silently forwarding a zero version to remote shards. Server-initiated queries (background flushes, streaming consumers, dictionary reloads, asynchronous insert flushes) now report the server’s own version as the initiator version. #109408 (Alexey Milovidov).
- Reduced the verbosity of the per-part primary-key binary-search diagnostics in
MergeTreeby lowering them from trace logging to test logging. #110324 (Alexey Milovidov). - The hive partitioning sample path for object storage tables (e.g.
S3) is resolved on the first use of the table instead ofCREATE/ATTACH, so an unreachable endpoint no longer blocks table creation and server startup. #111842 (Nikolay Degterinsky). - Fixed
ReadBufferFromPocoSocketBase::setReceiveTimeoutapplying its argument as seconds rather than microseconds, and fixed builds configured with-DENABLE_LIBFIU=OFF, which did not compile. In builds without libfiu,SYSTEM ENABLE FAILPOINTand related commands now throw an exception instead of silently doing nothing. #112767 (Alexey Milovidov). - Fix
clickhouse-localunder-reportingrows_readand the other progress counters in thestatisticsof theJSON/XMLoutput and in the progress bar: a progress increment that arrived while the progress packet was being assembled was discarded. #112958 (Alexey Milovidov). - Fixed the error reported when an asynchronous
INSERTinto aDistributedtable needs a queue directory whose name exceeds the 255-byte filesystem limit (reachable withuse_compact_format_in_distributed_parts_names = 0). It was aLOGICAL_ERRORfor a shard withinternal_replicationand an unattributedCode: 1001. std::exceptionotherwise; both now reportARGUMENT_OUT_OF_BOUNDnaming the table, the cluster and the limit. #113083 (Groene AI). - Reject out-of-range
execution_timequota limits withBAD_ARGUMENTSinstead of relying on undefined behavior when scaling them to internal nanoseconds. #113178 (Alexey Milovidov). - Automatic parallel replicas now support
JOINqueries. #106073 (Nikita Taranov). - Support refresh-token authentication for the
OneLakecatalog. #110413 (alesapin). - The
write_snapshot_versionKeepersetting is now hot-reloadable. #112150 (alesapin). - Parallelize
SYSTEM DROP FILESYSTEM CACHE. #112532 (Kseniia Sumarokova). - Unsupported nesting of a
SQL SECURITY DEFINERorSQL SECURITY NONEview overs3Cluster,urlCluster, orfileClusteris now rejected with a normal query error instead of hitting aLOGICAL_ERRORin debug and sanitizer builds. #113371 (Groene AI). - Added the setting
analyzer_compatibility_multiple_joins_qualify_column_names(defaultfalse). When enabled and theFROMclause of a query contains two or moreJOINs, result column names produced by the analyzer mimic the old analyzer’s multiple-joins rewrite: columns expanded from*are named<alias-or-table>.<column>, and an unaliased column reference in theSELECTlist keeps its name exactly as written. This makes outer queries that reference such qualified names, likeSELECT ll.Date FROM (SELECT * FROM t AS ll JOIN t1 ON ... JOIN t2 ON ...), work as they did with the old analyzer. It also fixes the analyzer losing qualified result column names for columns expanded from*whengroup_by_use_nullsis combined withROLLUP,CUBE, orGROUPING SETS, which produced duplicate result column names and broke outer references to those columns. #110746 (Dmitry Novik). - Renamed
allow_experimental_delta_kernel_rstoallow_delta_kernel_rs. The old name is kept as an alias. #113476 (Kseniia Sumarokova). - When the
remote/remoteSecuretable functions or theRemote/RemoteSecuretable engines are given a missing named collection together with akey = valueoverride, ClickHouse now reports the missing named collection instead of reparsing the call positionally and reporting an unrelated error. #113510 (Groene AI). - Shell startup with
clickhouse-bootstrapcompletion no longer dumps environment variables when the completion is loaded from the user completion hook. #113694 (Azat Khuzhin). - Added the
sainte_laguevalue forshared_merge_tree_merge_coordinator_distribution_algorithmand made it the default instead ofwater_filling. #113442 (Mikhail Artemenko). - Added the
filesystem_cache_wait_for_concurrent_download_timeout_millisecondssetting to bound how long a read waits for another query’s filesystem-cache download of a single chunk (about 1 MiB), not a whole file segment. #113322 (Kseniia Sumarokova). - Added the Keeper setting
min_time_between_fsyncs_ms(default5ms), which batches changelog appends that arrive shortly after the previous flush instead of starting another flush immediately. #113749 (Michael Kolupaev). - Kafka tables with Keeper-stored offsets (
kafka_keeper_path) now throwABORTEDinstead ofLOGICAL_ERRORwhen the table becomes inactive after a Keeper session loss, for example during a direct read or materialized-view streaming. #113913 (Alexey Milovidov). - Fixed inconsistent AST formatting of
viewIfPermitted: the table function form no longer formats an operator such asnotincorrectly in itsELSEbranch, and the expression formviewIfPermitted(...)no longer gets a spuriousELSE. #113652 (Alexey Milovidov). - Fixed a spurious
Failed to drop temporary table after refresh. Table ... is left behind and requires manual cleanup.error logged when a refreshable materialized view refresh is cancelled (for example by server shutdown) whiledatabase_atomic_wait_for_drop_and_detach_synchronouslyis enabled. The temporary table was in fact dropped, so no manual cleanup was needed. #113957 (Groene AI). - The server now throws
UNKNOWN_ELEMENT_IN_CONFIGon unknown configuration options in the server config, helping catch typos and misconfigured options early. The check can be disabled with<skip_check_for_incorrect_settings>. #100332 (Alexey Milovidov). - In the Web UI, the browser history and the URL are no longer updated on every keypress; they are recorded when a query is successfully run or on a tab change. #113596 (Alexey Milovidov).
- ClickHouse now reports a stack overflow instead of dying silently: the fatal signal handlers run on the alternative signal stack, so
SIGSEGV,SIGABRT,SIGILL,SIGBUS,SIGSYS,SIGFPE, andSIGTRAPproduce a stack trace even when the faulting thread has exhausted its stack. #113927 (Groene AI). ALTER TABLE ... MODIFY COLUMN <col> Tuple(...)on a namedTupleis now metadata-only when only adding subfields, matching the speed of top-levelADD COLUMN. Gated behindSETallow_metadata_only_named_tuple_alter= 1. #107305 (Amos Bird).- Add
input_format_json_max_object_sizesetting to limit JSON object size on parsing. Closes #106704. #107669 (Pavel Kruglov). - Avoid logging
sasl.kerberos.kinit.cmd configuration parameter is ignored.forKafkaengine configurations that do not use Kerberos keytab authentication. #108235 (Ivan Shelestov). - Add system.s3(azure)_queue_metadata. #108522 (Kseniia Sumarokova).
- Log tolerated connection failures to remote MySQL/PostgreSQL databases as warnings instead of errors. #109472 (Shaohua Wang).
- When neither
portnorsecureis specified,clickhouse-clienttries both the default port 9000 and the secure port 9440 concurrently and uses the one that answers first, soclickhouse-client --host play.clickhouse.com --user playconnects over TLS without--secure, even though the plain port of that server is silently dropped rather than refused. If the port that answered turns out to be unusable — a secure port with an untrusted certificate, for example — the client falls back to the other one, because the protocol was not requested explicitly. #110130 (Alexey Milovidov). - Clicking the cloud logo in the Playground now opens the ClickHouse website in a new tab, so you don’t lose progress while queries are running. #110422 (William Hatcher).
- Add STREAM BOUNDED modifier, which read only the first snapshot of a streaming query, then finish instead of subscribing for updates. #110653 (Smita Kulkarni).
- Add information of internal state of joins to
EXPLAIN ANALYZE. #110892 (Kirill Kopnev). - When an
RWLockImpl::getLock()re-entrancy assertion fires (RWLock is already locked in exclusive mode/Cannot acquire exclusive lock while RWLock is already locked), the error message now names the otherquery_ids currently owning the lock and how many locks the requestingquery_idalready holds, to make such lock-ordering errors diagnosable. #110971 (Groene AI). - ClickHouse Keeper now logs the “Client has not sent any data” event at
Informationlevel instead ofWarning, matching the server’s TCP handler. This avoids spurious warnings from TCP health-check probes (for example KubernetestcpSocketliveness probes) that open and immediately close a connection to the Keeper client port. #111217 (Zeynel). MaterializedPostgreSQLnow preserves unchanged PostgreSQLTOASTvalues during updates instead of replacing them with default values. #111552 (OrpheusAgent).- keeper: Increase default
write_snapshot_versionto 8 and make it hot-reloadable. #111715 (Michael Kolupaev). - Add STREAM UNORDERED modifier: skip the per-snapshot commit-order sort. #111794 (Smita Kulkarni).
- Added a new MergeTree setting
text_index_versionthat controls the on-disk format version of text indexes:v0_initial,v1_with_codec, orv2_with_positions. During a rolling upgrade or before a downgrade, set it to an older version so that newer servers keep writing text index parts in a format older servers can still read; the compatibility setting automatically adjusts it. #111803 (Anton Popov). - AI text functions (
aiGenerate,aiClassify,aiExtract,aiTranslate) now reject truncated or otherwise incomplete provider responses (e.g. when the model hits themax_tokenslimit) instead of silently returning partial output. Behavior follows theai_function_throw_on_errorsetting. #111830 (George Larionov). - Improve reduced-precision
L2DistanceTransposedQuantized,cosineDistanceTransposedQuantized, anddotProductTransposedQuantizedby reconstructingp < 8QBit(Int8)codes with Gaussian conditional-mean prefix centroids. Full precision (p = 8) remains bit-exact; reduced-precision approximate distances may change, and recall/latency gains are workload-dependent. #111867 (Sergey Kuznetsov). - Fixed the query condition cache not being populated for granules eliminated by any but the last conjunct of a
WHEREclause with multipleANDconditions. #112083 (Shankar Iyer). - Added a new setting
input_format_json_max_string_column_growth_stepthat caps the power-of-two growth of internal String buffers when building a JSON column, reducing peak memory when inserting large JSON documents. Disabled by default. #112159 (Pavel Kruglov). - Reduced peak memory when writing JSON columns with bucketed shared data serialization (
map_with_bucketsand advanced) by splitting the shared data into buckets one at a time on write instead of materializing all buckets simultaneously. This is mostly beneficial for Array(JSON) columns: for scalar JSON the shared data is split per granule (bounded by index_granularity_bytes), so the saving is small, whereas a single Array(JSON) granule can hold many nested rows and thus a large amount of shared data, where the one-bucket-at-a-time split significantly lowers peak memory. #112172 (Pavel Kruglov). - The documentation of a setting in
system.documentation— shown by the built-in/docspage and by thehelpcommand — now includes the history of the changes of its default value: the version in which the setting was introduced and every later change of its default, with the previous value, the new value and the reason for the change. #112177 (Alexey Milovidov). EXPLAIN ANALYZEnow works for streaming queries. #112445 (Kirill Kopnev).- The modifiers of a column declaration -
COMMENT,CODEC,STATISTICS,TTL,COLLATE,PRIMARY KEYand per-columnSETTINGS- can now be written in any order inCREATE TABLE, and each of them at most once. Previously only one fixed order was accepted, and, for example,x UInt64 CODEC(ZSTD) COMMENT 'text'was a syntax error. InALTER TABLE ... ADD COLUMN/MODIFY COLUMN, the supported modifiers -COMMENT,CODEC,STATISTICS,TTLand per-columnSETTINGS- can also be written in any order; per-columnSETTINGSinADD COLUMNand a declaredSTATISTICSinADD COLUMN/MODIFY COLUMNare now applied instead of being silently dropped, andCOLLATEandPRIMARY KEYin theseALTERcommands now throw an exception instead of being silently ignored. #112788 (Alexey Milovidov). - The
pread_threadpoolread method needs thepreadv2system call with theRWF_NOWAITflag to read the data that is already in the page cache without handing the read off to a thread pool. It is now checked at start time whether that system call can be used, and if it cannot - the Linux kernel is older than 5.11, or aseccompprofile of a container runtime rejects the system call - the default value oflocal_filesystem_read_methodis switched topread, and the reason is reported in the server log. Previously, every read paid for a thread pool hand-off on such systems, and aseccompprofile that answersEPERMmade queries fail withCANNOT_READ_FROM_FILE_DESCRIPTOR. #112945 (Alexey Milovidov). - Report malformed Parquet thrift metadata as INCORRECT_DATA. #113311 (Groene AI).
- Fixed GCD codec handling of signed fixed-width values with negative numbers. Previously it computed the divisor from signed values directly, which could miss the common divisor and significantly reduce compression efficiency for signed integer and decimal columns. It now computes the divisor from magnitudes for signed types while preserving existing behavior for unsigned types and decompression. #113798 (Kirill Shcherbatov).
- Add settings
enable_alp_codec,enable_sz3_codec,enable_zxc_codec, andenable_quantized_codecto enable each experimental compression codec individually. #113824 (Raufs Dunamalijevs). - Allow
ALTER TABLE ... MODIFY COLUMNof a column whose subcolumns are used in the primary or partition key, as long as the subcolumns used in the key keep an on-disk-compatible type. Previously any such ALTER was forbidden. #113862 (Pavel Kruglov). - Add
Filesystem cachedashboard tosystem.dashboards. #113884 (Kseniia Sumarokova). - Put the per-buffer-refill cache logs behind
filesystem_cache_verbose_logging. #113885 (Groene AI). - When a column’s declared type and its data diverge during a
MergeTreeread (mixed type provenance, e.g. after anALTER TABLE ... MODIFY COLUMNwhose mutation has not finished), the server now reports a clear exception naming the column and both structures, instead of an unchecked cast: debug and sanitizer builds previously aborted with a bareBad cast from type A to Bnaming no column, and release builds walked mismatched memory silently. #114087 (Alexey Milovidov). - A window function with
PARTITION BYnow works undermake_distributed_plan. When the plan shape allows, the window runs in parallel across buckets that each receive complete partitions. #114111 (Vighnesh Pathrikar). - Web UI: the hourglass loading indicator in the databases panel is animated again. #114187 (Alexey Milovidov).
- 64-bit hash function is used now for external nullable fixed-width aggregation methods (avoids collision disaster for very high cardinality aggregation). #114210 (Nikita Taranov).
DistributedandBuffertables that omit their column list now always infer the structure under the creating user’s access rights. #114211 (Pedro Ferreira).x IN (subquery)over aLowCardinalitycolumn now returnsLowCardinality(UInt8)— the same type asx IN (literal list). Previously the two forms returned different types, and distributed plans with such anINneeded a special case in the plan type check. #114229 (Alexander Gololobov).- Enabled
ie_joinby default: the default value ofjoin_algorithmis nowdirect,parallel_hash,hash,ie_join. AJOINwhoseONsection has only inequality conditions (two comparisons<,<=,>,>=between expressions of the joined tables) is now executed with the sort-based IEJoin algorithm instead of aCROSS JOINwith a filter, andLEFT/RIGHT/FULL/SEMI/ANTIjoins with such conditions are supported. Sinceie_joinis last in the list, it is used only when the other algorithms do not apply. #114327 (Vladimir Cherkasov). - Fixed charts in the Web UI showing the data of a mirrored point in the hover balloon for a result ordered by
xdescending.Date,Date32,DateTimeandDateTime64columns can now be plotted; previously only integer Unix timestamps worked. Dates on the axes and in the balloons are rendered in ISO 8601, and quantities with theK/M/G/… suffixes, the same way the advanced dashboard does. #114349 (Alexey Milovidov). - Support parsing integers that exceed the 64-bit range in the
JSONdata type,JSONExtract, andisValidJSON. Such values are read into wide integer types such asInt128/UInt256instead of causing the whole document to be rejected. #114379 (Pavel Kruglov). - QueryRunner tables now start worker threads on demand and release them once idle, instead of occupying threads for the table’s whole lifetime. #114522 (Miсhael Stetsyuk).
- Added observability for the stacks of fibers, which are used for asynchronous communication with remote replicas: profile events
FiberStackAllocs,FiberStackAllocBytes,FiberStackAllocNanoseconds,FiberStackFreeNanoseconds, and metricsFiberStacks,FiberStackBytes. #114541 (Alexey Milovidov). - PromQL: support
@ start()and@ end()timestamp modifiers. #114558 (Minh Vu). - Propagate the OpenTelemetry trace context into the fibers used for asynchronous connection establishment and remote query execution (hedged requests,
async_socket_for_remote,async_query_sending_for_remote). Spans of remote queries in a distributed query are now correctly parented under the initiator’sConnection::sendQueryspan instead of being attached directly to the client-supplied trace context, and each asynchronous task execution produces its own span. #114813 (Diego Gomes Tomé). - With this change, while using the WHATIF indices, the projection-served baseline reports per-candidate
not_applicableinstead of failing the statement. #114846 (Yarik Briukhovetskyi). DROP DATABASEnow drops tables in reverse topological order of both loading and referential dependencies (previously only loading dependencies), so a crash in the middle ofDROP DATABASEcannot leave a table whose dependencies were already dropped. #114952 (Alexey Milovidov).- In the Web UI dashboards, the global error screen is replaced by a note above the dashboards, so a failing chart no longer hides the whole page. #115019 (Mikhail Artemenko).
- Spill the adaptive aggregator’s learning-phase tables under memory pressure. #115038 (Groene AI).
clickhouse-localnow answers CORS preflight requests with the same permissive headers asclickhouse-server, so the HTTP interface opened bySYSTEM START LISTEN HTTPcan be used from a browser out of the box, including the Web UI opened from afile://URL. #115045 (Alexey Milovidov).- Support PostgreSQL-style regular expression match operators:
~(an alias for thematchfunction),~*(case-insensitive match),!~and!~*(negations). The\d,\dt,\dvcommands ofpsqlnow work when connected to ClickHouse over the PostgreSQL compatibility protocol, and a failed query no longer terminates the connection. #115066 (Alexey Milovidov). clickhouse-clientno longer prints theConnecting to ...message twice when it asks for a password interactively. #115081 (Alexey Milovidov).EXPLAIN WHATIFnow says why the empirical estimate was skipped, in a newempirical_reasonline shown whenempirical_statusisunsupported. #115140 (Yarik Briukhovetskyi).- When no join algorithm enabled by the
join_algorithmsetting can execute aJOIN, the error message now names the algorithms that were tried and the strictness and kind of the JOIN that failed, instead of reporting only that none of them worked. #115226 (Alexey Elkin). - Vector search queries can now use the vector similarity index when the reference vector is an integer array literal, e.g.
ORDER BY L2Distance(vec, [1, 2]). Previously, such queries silently fell back to a brute-force scan. #115255 (Robert Schulze). - Azure client-side network failures (connection reset/refused, DNS and TLS errors) are now retried as transport errors instead of surfacing as a synthetic
500, matching the S3 client. #115269 (Arsen Muk). - The documentation of all SQL statements (e.g. name, syntax, description, examples) can now be retrieved from system table
system.statements. #115341 (Robert Schulze). BACKUPno longer leaves a lock file behind in its destination when the attempt that created it fails before writing anything — whether it fails while claiming the destination or while opening an archive. No later backup could match such a lock, so every retry to the same destination failed until the file was deleted by hand. Backups toS3andAzuredestinations also create the lock exclusively, and a lock that belongs to another backup is reported as a concurrent backup rather than as whatever error the storage returned. #115387 (Julia Kartseva).- Support bearer-token authentication in BuilderRWBufferFromHTTP (attempt 2). #115400 (Sergei Trifonov).
- Add some dimensional metrics for S3Queue. #115422 (Bharat Nallan).
- Added
keywordas an alias for text index tokenizerarrayfor improved compatibilty with OpenSearch, Elasticsearch, SolR, and Lucene. #115507 (Robert Schulze). - Allow to create own s3 tables. #115652 (Konstantin Vedernikov).
- Do not log per-thread untracked memory on non-server wide MEMORY_LIMIT_EXCEEDED errors. #115658 (Azat Khuzhin).
- The Prometheus remote-write protocol now supports asynchronous inserts: data from multiple concurrent remote-write requests is batched before forming parts, following the
async_insertsetting (enabled by default; addasync_insert=0to the handler URL to keep the synchronous behavior). A request is acknowledged only after the data is flushed to all inner tables of the targetTimeSeriestable. #115688 (Nikita Mikhaylov). - Makes all
timeSeries*aggregate functions handle duplicate timestamps by one rule (the greatest value wins, NaN loses to any other value), fixing the order-dependent results oftimeSeriesInstantRateToGrid,timeSeriesInstantDeltaToGrid,timeSeriesLastTwoSamplesandtimeSeriesResampleToGridWithStalenesswhen some values at a shared timestamp are NaN. The rule is now documented and tested. #115920 (Vitaly Baranov).
Bug Fix (user-visible misbehavior in an official stable release)
- Fix column-name corruption and
BAD_ARGUMENTSexceptions withinject_random_order_for_select_without_order_by: multi-columnSELECTqueries no longer fail, and output column names forCREATE TABLE AS SELECT,CREATE VIEW AS SELECT, and named formats such asJSONEachRoware preserved instead of being replaced with internal__subquery_column_<UUID>aliases. Closes #102812. Closes #101107. #105896 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKin the nativeParquetV3 reader when aPREWHEREhas conjuncts that share a common intermediate expression. #107059 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKfor queries that use the_part_starting_offsetor_part_offsetvirtual columns inWHEREtogether with lazy materialization. #108287 (Vladimir Cherkasov). - Fix
Not found column or subcolumn c.null in blockwhen runningWHERE col IS NULLorIS NOT NULLon a schema-evolvedIcebergcolumn that was added after older data files were written, withoptimize_functions_to_subcolumns = 1(the default). #109515 (Groene AI). - Fix false
ICEBERG_SPECIFICATION_VIOLATIONerrors when reading anIcebergtable whose decimal or other parameterized primitive type is serialized with different whitespace across metadata files, such asdecimal(20,0)in the table metadata anddecimal(20, 0)in the manifest. #109676 (Groene AI). - Fix deferred
PREWHEREwithoptimize_move_to_prewhere = 1whenPREWHEREis applied afterFINAL:WHEREconditions are no longer moved ahead of a deferred row policy, which could change query results. #109703 (Yarik Briukhovetskyi). - Fix
BAD_GETwhen comparing anArray(String)column with an array literal such asarr = ['x']and the column has atext,tokenbf_v1, orngrambf_v1skip index. Such comparisons now fall back to a full scan instead of failing the query. #110057 (Groene AI). - Fix wrong results for
has,mapContainsKey, andmapContainsValuewith an empty needle when a text index is present. #110246 (Robert Schulze). - Fix
Host is empty in S3 URIwhen a scalar subquery is used as the URL argument of thes3table function, or as an argument of any other table function, inCREATE TABLE ... AS SELECTqueries. #110254 (Sema Checherinda). - Fix
ON CLUSTERprivilege checks forSYSTEM STOP/START CLEANUPandSYSTEM STOP/START VIRTUAL PARTS UPDATE: they no longer requireSYSTEM PULLING REPLICATION LOGand now useSYSTEM CLEANUPorSYSTEM VIRTUAL PARTS UPDATE. #110289 (Groene AI). - Fix a read-only object-storage replica, with
read_only = true, not discovering new parts viarefresh_parts_interval, andtable_disk = truefailing on such a disk withtable_disk is not supported for non-ObjectStorage disks. #110460 (Julia Kartseva). - Fix writes through data-lake table functions such as
INSERT INTO FUNCTION icebergS3(...)producingParquetfiles whose string columns lost theStringtype annotation, making the written data unreadable for external readers such as Spark. #110465 (Shaohua Wang). - Fix schema inference failing with
Map cannot have a key of type LowCardinality(Nullable(String))when readingORCfiles whose map keys are dictionary-encoded, including files written by Spark and files written by ClickHouse itself withoutput_format_orc_dictionary_key_size_thresholdenabled. #110492 (Shaohua Wang). - Fix wrong
IS NULL/IS NOT NULL/count()results withoptimize_functions_to_subcolumnson a column madeNullableby a metadata-onlyALTER MODIFY COLUMN TtoNullable(T). For parts written before the conversion, the.nullsubcolumn is now derived from the physically present parent column instead of the storage-type default. #110584 (Groene AI). - Fix wrong query results from the
optimize_and_compare_chainoptimization when transitive conditions mix types with different comparison semantics, such asEnumwithString,DecimalwithFloat64, orFixedStringvalues of different widths. #110621 (Yarik Briukhovetskyi). - Fix wrong results for some read-in-order queries when the optimizer widens the sort-key prefix. #110725 (Groene AI).
- Fix
CREATEstatements with aCOMMENTclause to raise a syntax error when the comment string literal is missing, instead of silently accepting a misparsed query. For example,CREATE VIEW v COMMENT AS SELECT 1no longer creates a view without a comment. #111159 (Shaohua Wang). - Fix wrong results from
SummingMergeTreeandCoalescingMergeTreewithFINALwhenoptimize_move_to_prewhere_if_final = 1and theWHEREclause is an implicit-boolean condition on a sorting-key column, such asWHERE k. #111342 (Groene AI). - Fix spurious
Directory '...' was created concurrently with remote path '...'exceptions for metadata-only operations on object-storage-backed databases and tables, such asDROP DATABASE. #111353 (Mikhail Artemenko). - Data-lake REST catalogs now report stale credentials with the proper exception instead of silently treating them as a missing table or returning
UNKNOWN_TABLE. #111379 (alesapin). - Fix
SQL SECURITY DEFINERandSQL SECURITY NONEnot being honored for parameterized views when the analyzer is disabled (enable_analyzer = 0). Previously, selecting from such a view as a user without privileges on the underlying table failed withACCESS_DENIED, even though the same view works with the analyzer enabled. #111458 (Groene AI). - Reject a
Nullable(Nothing)column, or any other type not allowed in tables, atCREATE TABLEtime when the schema is inferred from the storage, for example in a columnlessremote,Remote, orDistributedtable over a view that doesSELECT NULL, instead of persisting metadata that fails to load on the next server restart and blocks loading of unrelated tables. #111487 (Groene AI). - Fix
std::bad_variant_accessand incorrectIcebergschema evolution for nestedArray(Map(...))columns whose innerStructis altered. #111489 (Konstantin Vedernikov). - Fix
ALTER MODIFY COLUMNfailing when converting aNullablecolumn to a different type with aDEFAULT, for example fromNullable(UInt8)toString,LowCardinality(String), orArray(UInt8). #102156 (DQ). - Fix
BAD_ARGUMENTS(Dictionary not found) fromdictGetafterDETACH DICTIONARY ... PERMANENTLYis rejected withHAVE_DEPENDENT_OBJECTS; the dictionary now remains usable when the detach is rejected. #105259 (Groene AI). - ClickHouse-written data files for
Icebergtables now embedIcebergfield IDs inAvroandORC,ORCStringcolumns are written asstringinstead of binary, and optional complexORCfields (Array,Map,Tuple) now preserve the correcticeberg.requiredmetadata. This fixes silentNULLresults after column renames and restores compatibility with spec-compliant readers such as Spark andiceberg-java. #109994 (Groene AI). #111775 (Groene AI). - Fix reading files on
plain_rewritabledisks after an existing path is rewritten with content of a different size: stale in-memory metadata could otherwise triggerUNEXPECTED_END_OF_FILE. #110304 (Konstantin Bogdanov). - Fix drift of the per-user memory tracker caused by system log records such as
query_logandquery_views_log, which could otherwise trigger a falsemax_memory_usage_for_userlimit for users with continuous workloads. #110708 (Raúl Marín). - Fix a rare race where a comment-only or settings-only
ALTERon aReplicatedMergeTreetable could silently drop a column added by a concurrentALTER ... ADD COLUMN, leaving a replica with outdated table metadata. #111029 (Shaohua Wang). - Fix incorrect primary-key pruning on tables with a descending sorting-key suffix, such as
ORDER BY (g, r DESC), which could drop matching rows. #111059 (Nihal Z. Miaji). - Fix a peer-certificate memory leak on every TLS handshake when certificate verification is enabled. #111425 (Konstantin Bogdanov).
- Fix mutations with a query parameter as the partition in
ALTER TABLE ... UPDATE/DELETE ... IN PARTITION {param:Type}: the serialized partition value can now be parsed back correctly, so theALTERno longer writes mutation entries that break table loading. #111518 (Michael Kolupaev). - Fix a macOS/aarch64 crash when a stack trace is captured on a coroutine or fiber stack, for example by the memory profiler. #111656 (Raúl Marín).
- Fix server crash when reading
Protobufdata withinput_format_allow_errors_num > 0and a valid message precedes a bad but skippable message in the same block. #107739 (Andrey Tsarevskiy | Андрей Царевский ). - Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen a query over aDistributedtable uses_shard_numorshardNumthat becomesNullable, for example underFULL JOINwithjoin_use_nulls = 1, together withORDER BYand the analyzer. #109798 (Groene AI). - Fix wrong results and
UNKNOWN_ELEMENT_OF_ENUMexceptions inLEFT/RIGHT/FULL/ASOF JOINwithjoin_algorithm = 'full_sorting_merge', where non-joined rows could be filled with0instead of the column type default. #111197 (Groene AI). - Fix a
LOGICAL_ERRORexception when a higher-order function’s lambda body is a constant-conditioniformultiIfthat mixes aBoolliteral branch with aUInt8comparison branch, for examplearrayFilter(p -> multiIf(false, true, p = 'ALL'), ['ALL']). #111245 (Groene AI). - A
{_partition_id}placeholder in the path ofS3,AzureBlobStorage,URL, and similar file-like engines without an explicitpartition_strategynow implies thewildcardstrategy again, restoring compatibility for pre-26.6 DDL that started failing withBAD_ARGUMENTS. #111279 (Nikita Fomichev). - Fix
NUMBER_OF_COLUMNS_DOESNT_MATCHforGROUP BYqueries over aMergetable wrapping aDistributedtable when the grouping key is a function of a column and an aggregate reads the same column. #111334 (Groene AI). GRANT role TO roleon the same role is now rejected withBAD_ARGUMENTSinstead of silently creating a self-referential entry insystem.role_grants. #103315 (zxuhan7).- Fix writes to
Icebergtables when the metadata file has norefssection. #106896 (Aleksandr Musorin). - Fixed
system.session_logbecoming unreadable after an Arrow Flight login: theinterfacecolumn is anEnum8, but theArrowFlightvalue was missing from its enumeration, so a login over the Arrow Flight protocol wrote the raw value10and anySELECTreading such a row threw theUnexpected value 10 in enumexception. #110758 (Alexey Milovidov). - Fixed a signed integer overflow in
toStartOfIntervalwith subsecond intervals: forDateTime64values within one interval of the lower bound ofInt64, the rounded result silently wrapped to a positive garbage value; now the function throws aDECIMAL_OVERFLOWexception. #111370 (Alexey Milovidov). - Fix
readWKTPointandreadWKTreturning uninitialized (scalar) or previous-row (vectorized) coordinates for a dimension-tagged empty point such asPOINT M EMPTY. Such inputs are now rejected withCANNOT_PARSE_TEXT, consistent withPOINT EMPTY. #111517 (Groene AI). - Fix
Unexpected number of columns in result sample blockexceptions forRIGHTandFULL JOINwhen the left side carries a duplicated same-named column, for example1 AS b, 1 AS b, that survives throughUNION ALL. #111554 (Groene AI). - Fixed
CANNOT_CONVERT_TYPEandLOGICAL_ERRORexceptions in distributed queries using the-Tuplecombinator with aRESPECT NULLSorIGNORE NULLSmodifier under nested combinators, for exampleanyRespectNullsStateTuple(...) IGNORE NULLS. #111570 (Alexey Milovidov). - Fixed SQL syntax highlighting in Play on iPhone, where iOS Safari’s automatic text inflation could misalign the highlight overlay. #111683 (Alexey Milovidov).
- Fixed
UNKNOWN_QUERY_PARAMETERwhen a parameterized view is called with a subquery-valued argument whose type isArray,Tuple, orLowCardinality, for exampleSELECT * FROM v(param = (SELECT groupArray(x) FROM t)). #111790 (Groene AI). - Fix
TYPE_MISMATCH(Key type for complex key ... does not match) when aJOINonto a dictionary uses aNullable,LowCardinality, orLowCardinality(Nullable)join key while the dictionary key is not wrapped. The direct-join dictionary lookup now normalizes the key to the dictionary’s declared key type, asdictGetanddictHasalready do, and aNULLkey never matches. #111857 (Groene AI). - With
fsync_part_directory = 1, renaming a part directory from its temporary to its final name is now itself made durable by fsyncing the parent directory, and for moves across parents the source parent too. Previously only the moved directory was fsynced, so a power loss right after a part was committed could leave the part missing on disk and lose rows despite the setting being enabled. #111861 (Groene AI). - Fixed hangs in
randChiSquared,randStudentT,randFisherF, andrandBinomialwith extreme parameters. Such queries could not be interrupted bymax_execution_timeorKILL QUERY. These parameters are now rejected even whenmax_rand_distribution_parameterormax_rand_distribution_trialsis set to0, andmax_rand_distribution_trialscan no longer be raised above its default of10^9forrandBinomial. #111909 (Alexey Milovidov). - Fixed wrong results when the analyzer rewrites comparison chains such as
x = c1 OR x = c2 OR ...,x != c1 AND x != c2 AND ..., orhas(const_array, x)toINandNOT IN. It also fixesIllegal type ... of argument of function inexceptions for expressions withDynamic,Array(Dynamic), orJSONstructure. #111924 (Groene AI). - Fixed wrong results and
LOGICAL_ERRORwhen selecting aNullable(Tuple(...))column together with one of its null-carrying element subcolumns (Variant,Dynamic, orLowCardinality) from aMergeTreetable. #111949 (Groene AI). - Reject native-protocol handshakes that use
USER_INTERSERVER_MARKERfor an unknown cluster, or for a cluster configured without a<secret>element. Previously such handshakes could enter interserver mode before authentication and read information about local tables. #99675 (Dan Anderson). - Fix
JOINagainstEmbeddedRocksDB,Redis, andKeeperMaptables that could silently return zero rows whenDirectKeyValueJoinis used withStringorNullable(String)keys. #105253 (Vladimir Cherkasov). - Fix coordinated refreshable materialized views in a
Replicateddatabase getting stuck after re-attach on a Keeper without theMULTI_READfeature flag; the view now stops cleanly with statusDisabledinstead of loggingUnexpected exception in refresh schedulingforever. #108890 (Groene AI). - Fix the ZooKeeper client sending an overflowed
int32length prefix for requests larger thanINT32_MAXbytes. Oversized requests are now rejected on the client side. The limit is configurable viamax_request_sizeunder<zookeeper>and is otherwise learned from Keeper. Closes #109165. #109190 (Arsen Muk). - Fix
S3Queue/AzureQueueordered mode with persistent processing nodes: bucket locks are now refreshed during streaming, so TTL cleanup controlled bypersistent_processing_node_ttl_secondsdoes not remove locks of a live processor. If lock ownership is nevertheless lost, it is detected and reported, and streaming recovers with a fresh file iterator. #110292 (Kseniia Sumarokova). - Fix wrong data and possible out-of-bounds reads when reading
Stringcolumns withstring_serialization_version = 'with_size_stream'after skipping leading rows, and when reading sub-objects ofJSONcolumns stored withobject_shared_data_serialization_version = 'map'. #110471 (Alexey Milovidov). - Fix
CREATE TABLEandALTER TABLEwith the analyzer accepting aDEFAULTorMATERIALIZEDexpression that references a virtual column such as_tableor_database. These expressions are now rejected at definition time instead of failing later on insert withNOT_FOUND_COLUMN_IN_BLOCK. #111776 (Groene AI). - Fix a race in executable UDFs, the
executabletable engine, and executable dictionaries where anfcntlon an already-closed file descriptor could corrupt an unrelated descriptor of a concurrent query and make queries hang indefinitely. #111779 (Raúl Marín). - Creating deprecated
minmaxstatistics now emits a warning instead of throwing an exception. #111785 (Han Fei). - Fix
Icebergtables written by ClickHouse being unreadable by external readers such as PyIceberg and Spark. Manifest-list and manifestAvroschemas now include the requiredIcebergfield-idproperties. #111786 (Groene AI). - Regenerate materialized-into-part
block_numberandblock_offsetcolumns during part attach/detach/move/clone operations, so they no longer become stale after part manipulation. #111801 (Mikhail Artemenko). - Fix the
query_plan_split_filteroptimization leaving an internal__split_filtercolumn in one branch ofINTERSECTorUNION, which could cause aBlock structure mismatch in IntersectOrExceptStep stream: different number of columnsexception. #111930 (Groene AI). - Fix
AMBIGUOUS_COLUMN_NAMEfor queries that repeat aJOIN ONcondition inWHEREwithjoin_use_nulls = 1; such queries now return their result instead of failing. #112007 (Groene AI). - Fix DLF authentication in the
PaimonREST catalog: every request after the first no longer fails with HTTP 401, and table-existence checks now detect HTTP 404 correctly. #112015 (JIaQi Tang). - Fix
LOGICAL_ERRORduring concurrentKafkatable cleanup in Keeper; creation or removal no longer fails if the table’s Keeper path disappears after session expiry. #112078 (Groene AI). - Fix merges and mutations when the part-level min-max index is enabled for
_block_numberand_block_offsetcolumns. #109281 (Mikhail Artemenko). - Fix failed
INSERTintoDeltaLakeLocalordeltaLaketables leaving an unfinalized data file after writing had already started. #109328 (Groene AI). - Fix credential leaks in
SHOW CREATE,system.query_log, server logs, andEXPLAINoutput fors3/s3Cluster, theS3-backed engines,BACKUP ... TO S3, and secret arguments ofencrypt,decrypt, and HMAC functions built by expressions or SQL UDFs. #109768 (Raúl Marín). - Fix reading large
Parquetfiles from uncompressedSTOREDzip entries vias3andfile. #110495 (Eva Wuuu). - Fix
EXPLAIN ANALYZEhanging on queries with a streamingFROM ... STREAMread hidden in a subquery, CTE, or view. Such queries are now rejected withNOT_IMPLEMENTED, like top-level streaming reads already are. #110935 (Groene AI). - Reject vectors whose squared magnitude overflows to infinity when using a
vector_similarityindex withi8quantization. Previously, such vectors produced silent garbage. #111085 (Groene AI). - Fsync the text index files of a merged or materialized part when
min_rows_to_fsync_after_merge,min_compressed_bytes_to_fsync_after_merge, orfsync_part_directoryare set. Previously, these files were the only ones in the part left unsynced, so a power loss right after a merge could leave a committed but broken part and cause data loss. #111335 (Groene AI). - Fix path validation against
user_files. #111442 (Alexander Tokmakov). - Fix
SYSTEM REFRESHon a stoppedRabbitMQtable sometimes failing to consume the queued backlog. The refresh operation now waits for the AMQP delivery loop to start before it spends its one out-of-order streaming cycle. #111480 (Groene AI). - Restrict local object access to the
user_filespath. #111483 (Konstantin Vedernikov). - Fix a segfault due to out-of-bounds memory access when deserializing a malformed aggregate function state containing a
Stringvalue. Such states are now validated and rejected. #111606 (Miсhael Stetsyuk). - Fix integer overflow while parsing
system.zookeeper_info. #111629 (Kseniia Sumarokova). - Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen aFINALquery filters on a sorting-key column that is not in theSELECTlist and the filter is moved toPREWHERE, for exampleSELECT s FROM t FINAL WHERE k GROUP BY swithoptimize_move_to_prewhere_if_final = 1. #111721 (Groene AI). - Fix partitioned
INSERTintoDeltaLakewithallow_experimental_delta_lake_writes = 1corrupting partition values that contain path characters and rejectingNULLpartition values. Partition values are now percent-encoded into a single path segment, andNULLor empty-string values are written as__HIVE_DEFAULT_PARTITION__with a nullpartitionValuesentry. #111793 (Groene AI). - Fix an exception and silently skipped data when reading a dynamic subcolumn through a
Buffertable. #111948 (Alexey Milovidov). - Fix
clickhouse-clientlosing the current database afterUSE {db:Identifier}. If the client had to reconnect later, it silently switched the session to thedefaultdatabase. #111982 (Alexey Milovidov). - Fix a
LOGICAL_ERRORexception (Type mismatch when building statistics for column) duringMergeTreemutations after a metadata-onlyALTER MODIFY COLUMNchanges a column type while the column carries statistics. Columns actually rewritten by the mutation now have their statistics recomputed, and untouched columns keep their existing statistics. #112009 (Groene AI). - Fix
Paimontable reads that could fail while the mutablesnapshot/LATESThint was being replaced concurrently. Invalid or stale hints are now ignored, and the snapshot is loaded from the catalog instead. #112010 (JIaQi Tang). - Fix reading
GeoParquet,Arrow, andArrowStreamfiles whose WKT-encoded geometry column uses a non-uppercase type keyword such aspoint(1 2)or an empty container such asLINESTRING EMPTYorPOLYGON(). This also fixes reading back files that store the output ofwktfor an empty geometry. #112020 (Groene AI). - Fix query-level settings overrides not being applied to Azure native copy. #112037 (Smita Kulkarni).
- Fix
query_masking_rulesrewriting the type of anEPHEMERALcolumn, which could makeCREATE TABLEstore the wrong type or fail. #112048 (Alexey Milovidov). - Table function parameters no longer accept aggregate states, which previously triggered a logical error because such parameters are unsupported. Closes #112085. #112087 (Pedro Ferreira).
- Fix wrong results for a
JOINwhoseONexpression contains a constant conjunct, for exampleON l.id = r.id AND CAST(NULL AS Nullable(UInt8)). #112155 (Vladimir Cherkasov). - Fix wrong results for
hasAllTokensand other multi-token text-index searches on builds that do not usesimdcomp, such asaarch64, whentext_index_posting_list_apply_mode = 'lazy'. #112178 (Groene AI). - Fix wrong results when a parameterized view is called with an argument that is not a
parameter = valueassignment. Such calls are now rejected withUNKNOWN_QUERY_PARAMETERon both execution paths. #112194 (Groene AI). - Fix parameterized views whose
SELECTbody usesINTERSECT,EXCEPT, or aUNIONchain that mixesUNION DISTINCTwithUNION ALLbeing misclassified as ordinary views, which made their metadata unloadable. #112211 (Groene AI). - Fix schema inference for the
TSVfamily inferringStringfor decimal values written with a leading zero, such as0.0or0.5, and consuming such a first row as a header. Also fixTSKVinferring a numeric type for an escape-encoded value such asx=1\x2E5. Closes #112105. #112226 (Groene AI). - Fix
system.s3_queue_settingsreporting incorrect values forbucketing_mode,partitioning_mode,partition_regex, andpartition_component. #112300 (Bharat Nallan). - Fix wrong results, wrongly ordered
ORDER BYoutput, andBAD_TYPE_OF_FIELDexceptions when the primary key is anArrayorTupleand the query appliesplus,minus,multiply,divide, orintDivto it. #112339 (Groene AI). - Fix remote execution of queries containing
PASTE JOIN, for example through aDistributedtable or a*Clustertable function. ClickHouse no longer formats the query as the invalid syntaxALL PASTE JOIN. #112404 (Groene AI). - Fix a
LOGICAL_ERROR(Invalid number of rows in Chunk) inJoiningTransformfor aLEFT JOINwith unique right keys, a mixedONcondition, and a smallmax_joined_block_size_rows. #106928 (Groene AI). - Fixed the
_tagsvirtual column for theS3Queuetable engine: it was declared but never populated, soSELECT _tagsalways returned an empty map. It now returns the object tags, like theS3engine and thes3table function. #108676 (Groene AI). - Fix data loss of a column with no default expression when a merge runs concurrently with
ALTER TABLE... RENAME COLUMN, or when the column’s only values come from a lightweightUPDATE. The column could be dropped from the merged part, so all of its values read back as NULL. #109356 (Groene AI). - Fix skip indices being dropped from a data part (or
CHECK TABLEfailing withUNEXPECTED_FILE_IN_DATA_PART) after a full-part-rewrite mutation, such asALTER TABLE... DROP COLUMNof aMATERIALIZEDcolumn, on aWidepart. #109616 (Groene AI). - Fixed two bugs on the
DateTime64path oftoUTCTimestamp/fromUTCTimestamp(and theirto_utc_timestamp/from_utc_timestampaliases) andtoTime64. First, a signed integer overflow near theInt64boundary (now computed inInt128and clamped to the representable range). Second, a wrong result for negative fractional values near a timezone-offset boundary: the seconds split truncated toward zero, sotimezoneOffset()inspected the next second and could pick the wrong side of a DST/offset change. #109738 (Groene AI). - Fix a logical error (“Cannot determine row level filter; 0 columns deleted, 0 columns added”) when reading from a
Mergetable whose child table has a row policy whose filter is a bare existing column (for exampleCREATE ROW POLICY... USING flag). #109843 (Groene AI). - Fixed two errors raised when a query with
GROUP BY GROUPING SETS(or a scalar or mutation subquery containing one) runs withforce_aggregation_in_order = 1:Trying to get name of not a column: ExpressionListunder the old analyzer (enable_analyzer = 0), andMemory bound merging of aggregated results is not supported for grouping sets.for a distributed query withenable_memory_bound_merging_of_aggregation_results = 1under the analyzer. #109862 (Groene AI). - Fix parsing of numeric
1/0asBoolvalues inside container types (e.g.Array(Bool),Tuple(Bool,...)). Previously[1,0]failed withCANNOT_READ_ARRAY_FROM_TEXTwhile[true,false]worked. #109976 (Groene AI). - Fixed a spurious
ILLEGAL_COLUMNerror fromALTER TABLE... ADD COLUMN IF NOT EXISTSwhen the column already exists at apply time. This happened when the same column was added twice withIF NOT EXISTSin one statement, or when a concurrentALTERadded the column between the prepare and apply phases. #110080 (Groene AI). - Fixed a wrong result where
length(and the QBit dimension) on aFixedStringcolumn returned0instead of the fixed sizeNunder parallel replicas when the query had a selective filter. #110427 (Groene AI). - Fixed
flipCoordinateslosing theGeometrytype: for aGeometryargument the result is now typedGeometryagain instead of the underlyingVariant(...), so it can be passed directly to functions likeareaCartesian. #110694 (Groene AI). - Fixed
optimize_injective_functions_in_group_bychanging query results forGROUP BY GROUPING SETSandGROUP BY... WITH TOTALS. The setting is documented as result-preserving, but eliminating an injective function of a grouping key produced a wrong value (or dropped a row) for rows where that key is absent from the aggregated set (aGROUPING SETSnon-member set) or for theWITH TOTALSrow. The wrong value could coincide with a genuine key value, making a super-aggregate row indistinguishable from a real group in the same result set. #110721 (Groene AI). - Numeric
1/0in JSONBoolparsing now honors theallow_special_bool_valuessetting. Previously JSON input such as{"v":1}forVariant(Bool, UInt32)was read asBooleven withallow_special_bool_values_inside_variant = 0, because the JSONBoolparsers ignored the setting andBoolhas a higherVariantdeserialize priority than integer types. #110835 (Groene AI). - Fix a logical error
block.rows() == getRows()(an out-of-bounds read and broken insert deduplication in release builds) when anINSERTflows through a dependent materialized view whose target is anAliasand whose inner query changes the number of rows, with a deduplicating table reachable behind the alias hop. #111103 (Alexey Milovidov). - Fixed a logical error
Block structure mismatch(in debug and sanitizer builds) and anIllegal types of argumentserror for set operations over compatible aggregate-state columns (e.g.quantileStateandquantilesState(0.9)) nested inside container columns such asTuple,Array,Map,Nullable, orVariant. #111191 (Alexey Milovidov). - Fixed
DISTINCTwith an orderedLIMIT/OFFSETreturning wrong rows when the DISTINCT early-stop limit hint could not bound the head of the result: a negativeLIMIT(returned the head instead of the tail), a fractionalLIMIT/OFFSET(the fraction is only resolved after a full read), and a bareOFFSETwith noLIMIT(the tail after the offset was dropped). For exampleSELECT DISTINCT intDiv(x, 100) FROM t ORDER BY intDiv(x, 100) LIMIT -1over a multi-part table returned the smallest distinct value instead of the largest. #111326 (Groene AI). - Fixed wrong results when a query has a
setskip index and a predicate of the shape(x AND <null-value>) OR y, where the NULL is produced by a function (e.g.toInt64OrNull('x'),nullIf(1, 1),CAST(NULL AS Nullable(Int64))). Such a value was wrapped by__bitWrapperFuncand propagatedNULLinstead of the “unknown” mask, so the set index could prune granules that actually match and the query returned fewer rows than it should. #111604 (Groene AI). - Fix
DELETE/UPDATEon an Iceberg table silently removing the wrong rows (or throwingNOT_FOUND_COLUMN_IN_BLOCK) when the table contains data files written both before and afterALTER TABLE... ADD COLUMNandoptimize_move_to_prewhereis enabled. #111693 (Groene AI). - Fixed a
LOGICAL_ERROR(“Invalid number of rows in Chunk”) — and, under hardened builds, a related out-of-bounds abort — forORDER BY ... WITH FILL ... INTERPOLATEover aDistributedtable with two or more shards, overclusterAllReplicas, or over custom-key parallel replicas, including on empty results.WITH FILLis now applied only on the node producing the final result, which also fixes duplication of the generated fill rows across shards/replicas. #111919 (Yakov Olkhovskiy). - Keep
randBinomialusable with the degenerate probabilities0and1for any number of trials. #112021 (Alexey Milovidov). - Fixes wrong results caused by a vector-search query poisoning the query condition cache. A
SELECT... WHERE <condition> ORDER BY <distance function> LIMIT nquery over a table with avector_similarityindex could record granules as not matching<condition>, so a later ordinarySELECT... WHERE <condition>on the same table silently returned fewer rows. Vector-search reads no longer write to the query condition cache. #112086 (Groene AI). - Fixes a bug where a
CREATE VIEWorCREATE FUNCTIONwhose definition callssubstr,midorbyteSlicein a form thesubstringgrammar cannot re-parse is accepted, but the metadata ClickHouse writes for it is not valid SQL. Reading that definition afterwards fails withSYNTAX_ERROR, and at server startup it aborts metadata loading, so the server cannot start at all. Such definitions now round-trip, and existing metadata files of the formsubstring(x, a, b, c)become readable again, so an affected server starts up without manual intervention. #112195 (Groene AI). - Fixes a
TimeSeriestable whose local metadata diverged from Keeper making replica recovery in aReplicateddatabase hang forever, so the replica never served the database again and stayed broken across restarts. The inner tables of such a table are now dropped while the recovery metadata transaction is still available, instead of being deferred to a background task that could not execute theDROPat all. #112218 (Groene AI). - Fixed reading a subcolumn of a
Nullable(Tuple(...))column whose element is a non-nullableLowCardinality(T)when the same query also reads the parent subcolumn. On a Compact part the parent returned wrong values, or the query failed withUnexpected return type from assumeNotNull, or the server was killed by astring_viewhardening assertion, because the extracted subcolumn was deserialized into aLowCardinality(Nullable(T))buffer whose substreams were then shared with the parent’s read. #112232 (Groene AI). - Fixed a permanent server hang on macOS caused by
pthread_rwlocklosing wakeups when the sampling query profiler is enabled (Apple bug FB24027930):pthread_rwlockis now replaced with a signal-robust implementation on Darwin. #112267 (Raúl Marín). - Fix
max_execution_timeandKILL QUERYbeing ignored while a query evaluatesgeohashesInBox,arrayFold,sleep,base58Decode,h3PolygonToCells, orh3PolygonToCellsWithContainment. Such queries could keep running for minutes after cancellation. This now also covers evaluations inside expressions stored in table metadata, such as sorting keys, skip indexes, andPARTITION BYkeys. #112273 (Groene AI). #113456 (Groene AI). - Fixes a logical error
Cannot add step Expression to QueryPlan because it has incompatible header with root step JoinLazyColumnsStepfor a query withFINAL, aPREWHEREfilter, a smallLIMITandmake_distributed_plan = 1, when the selected columns are listed in an order that differs from the table’s column order. Lazy materialization replaced a plan node without preserving that node’s output header, which made the query plan inconsistent. #112303 (Groene AI). - Fixes writing Iceberg tables whose schema contains a tuple nested inside a tuple. The published table metadata replaced the inner tuple’s field names with positional names
1,2,…, so with the defaultParquetformat theINSERTfailed withINCORRECT_DATAand withAvrothe column could not be read back. #112480 (Groene AI). - Fix
ATTEMPT_TO_READ_AFTER_EOFerror when merging parts with a text index if one of the merged parts was empty, for example after a mutation that deleted all rows of the part. #112490 (Anton Popov). - Fixes wrong results and a logical error when an argument that must be constant, such as the scale of
toDecimal32or the timezone oftoDateTime, comes from a scalar subquery and the old analyzer is used. Such an argument was analyzed as if its value were zero or empty, so the declared result type disagreed with the computed value, andCREATE VIEWandCREATE MATERIALIZED VIEWpersisted a wrong column type. #112492 (Groene AI). - Fixes a
LOGICAL_ERROR(“Part… contains column… that is absent in table…”) when aReplicatedMergeTreereplica mutates a part it fetched from another replica before applying its own pendingALTER... ADD COLUMN. Such a mutation is now postponed until the metadata change is applied. #112510 (Groene AI). - Fixed incorrect query results when using GROUP BY with ORDER BY and
arrayJoinin the projection. #101775 (Yash ). - Fix a server crash (out-of-bounds access) in
S3Queue/AzureQueuewithenable_hash_ring_filtering = 1when a batch contained a non-processable file and the Keeper request to set the batch as processing failed at the same time. #108977 (Groene AI). - Fix a logical error
Stream <col>.variant_discr... is not found(server abort in debug and sanitizer builds) whenALTER TABLE... MODIFY COLUMNchanges a column into a type with dynamic subcolumns (for exampleVariantintoDynamic) on a table with Wide parts, and the part is later read or merged. #110204 (Groene AI). - Fix a signed-integer overflow (UBSan) when converting an extreme
DateTime64value (e.g.INT64_MIN) toTime/Time64in a timezone with a negative offset. #110451 (Groene AI). - Fixed a MergeTree table with a
_part_offsetor commit-order projection becoming permanently unattachable afterallow_part_offset_column_in_projectionsorallow_commit_order_projectionwas disabled and the table was detached or the server restarted. These two settings are CREATE-time gates, so they are no longer re-checked on ATTACH. #110570 (Groene AI). - With
analyzer_compatibility_join_using_top_level_identifier = 1, an identifier inJOIN... USINGcan now be resolved from an alias defined on a subexpression inside the SELECT list (for example,SELECT uniqExact(lower(x) AS id) FROM t1 JOIN t2 USING (id)), matching the old analyzer behavior. Previously only top-level projection aliases were considered, and such queries failed with anUNKNOWN_IDENTIFIERexception even with the setting enabled. The error hint suggesting the setting is now also produced when the matching alias is nested. #110739 (Dmitry Novik). - Fixes an issue where unauthenticated requests could cause ClickHouse to resolve hostnames supplied in forwarded client-address headers. ClickHouse now accepts only numeric IP addresses from these headers. Invalid values are ignored for forwarded-address quota attribution without DNS resolution. When
auth_use_forwarded_addressis enabled, invalid forwarded addresses are rejected during authentication. Rejections are logged at debug level. #111060 (Dmitriy Borisenko). - Fix
NOT_FOUND_COLUMN_IN_BLOCKwhen a row policy andadditional_table_filtersreference the same column that is not otherwise selected by the query. #111099 (Groene AI). - Fix
UNKNOWN_IDENTIFIERerror for columns qualified by CTE name (cte_name.column) in queries stored in views when the analyzer is enabled. #111386 (Dmitry Novik). - Fix a
LOGICAL_ERROR(Got read request from replica N for unknown stream...) that could abort the server when reading with parallel replicas and the query is fully answered by a projection optimization (exact-count, minmax-count, or a stored aggregate/normal projection selecting no ranges) on the initiator. #111689 (Groene AI). - Fixed a signed integer overflow in the three-argument overload of
toStartOfInterval: for anoriginargument near the lower bound ofInt64the function returned a wrapped-around value instead of reporting an error. #112045 (Alexey Milovidov). - Fixes a
LOGICAL_ERRORexception (Block structure mismatch in joined block stream) on a multi-table join whose two sub-joins both produce no output columns, for exampleSELECT count() FROM t1, t2, t3, t4 WHERE (t1.b = t2.b) AND (t3.a = t4.a)withquery_plan_optimize_join_order_limitset to0or1. #112205 (Groene AI). - Fixed the
valuestable function rendering a non-literalBoolconstant (e.g.CAST(true, 'Nullable(Bool)')) inserted into aString/textual column as1/0instead oftrue/false. #112308 (Yakov Olkhovskiy). - Fix a
LOGICAL_ERROR(partitions_count > 0) when partitioningIcebergdata chunks emptied by position deletes, e.g. during compaction of a partitionedIcebergtable with fully deleted data files. #112432 (Pedro Ferreira). - Fixed schema inference proposing a numeric type for text values the value parser cannot read back. Inference accepted a dangling exponent (
1e+), a missing mantissa (.) or a repeated sign (++inf), whichreadFloatTextPrecisethen rejected withCANNOT_PARSE_NUMBERwhen reading the inferred schema; on aDynamiccolumn this was an error at INSERT time. Inference now validates the number with the parser the reader actually uses. This also removes a case where the inferred type depended onmax_read_buffer_size, and lets valid leading-zero exponent forms such as0e5inferFloat64in TSV as they already do in CSV. Follows #112226 and closes the exponent half of #112105. #112453 (Groene AI). - Report the correct position for errors in PromQL queries. #112494 (Minh Vu).
- Fixes a
LOGICAL_ERROR(Cannot add transform Resize to Pipes because it has no outputs) when a query aggregating over a cluster runs withserialize_query_plan = 1and plan-based parallel replicas, caused by the merge step resizing the pipeline to zero streams. #112506 (Groene AI). - Fixes an unsigned underflow in the table name length check that allowed creating a table which could never be dropped. When the escaped database name reached 214 bytes, the limit computed for the
metadata_droppedfilename wrapped around, soCREATE TABLEwas accepted and the subsequentDROP TABLEorDROP DATABASEfailed withFile name too long. Such a name is now rejected withARGUMENT_OUT_OF_BOUND, the same error already returned just below that boundary. #112527 (Groene AI). - Fix the
Context has expiredexception whengetClientHTTPHeaderis used inside a subquery. #112533 (Alexey Milovidov). - Fixed
s3_allow_server_credentials_in_user_queriesincorrectly rejecting a query-suppliedextra_credentials(role_arn = '...'). STS assume-role with an explicit role is now always allowed: it does not expose the server’s own credentials to the query, and it is the documented way to grant access to a private S3 bucket. #112603 (Raúl Marín). - Fixes the read counters (
read_rows,read_bytes,ProfileEvents['SelectedRows'],ProfileEvents['SelectedBytes']) and theREAD_ROWSandREAD_BYTESquotas being over-charged for queries whoseORDER BYspills to disk. Rows re-read from the external sort temporary files were counted again as source reads, so a spilling query over-reported what it read and could be rejected withQUOTA_EXCEEDEDeven though it stayed within its quota. #112645 (Groene AI). - Fixes an Iceberg table whose write format is
Avroserializing a field declared"required": falsewhose type is alist,maporstructas required, with no["null", T]union, so that the data file’s own schema disagreed with the table metadata and other Iceberg readers saw a required field. Such a field is now written as the["null", T]union the Iceberg spec uses for an optional one. #112648 (Groene AI). - Fixes
DeltaLaketables returning too few rows when theWHEREpredicate contains a sub-expression the delta-kernel predicate translator cannot handle, positioned under aNOT. Such a sub-expression is now reported to delta-kernel as an explicit unknown predicate instead of as the end of the child iterator, which used to silently truncate the enclosing conjunction. #112652 (Groene AI). - Fixes heap corruption, which could crash the server at shutdown, caused by the
constmethodAccessRights::getFiltersmodifying an access-rights tree shared by concurrent queries. #112692 (Groene AI). - Fixes a logical error in query formatting when an
ARRAY JOINclause carries no expressions. Such a clause is now rejected while parsing withSYNTAX_ERROR, consistent with an emptyUSING, instead of being accepted and formatted into text that cannot be parsed back. #112699 (Groene AI). - Fix a query hang in local execution of distributed query plans (
distributed_plan_execute_locally = 1): the in-memory exchange reader could block the only pipeline thread before the sources producing its data were started. #111762 (Alexander Gololobov). - Fix
Icebergfields declared with"required": falsewhose type islist,map, orstructbeing written asREQUIREDin theParquetfooter. Such fields are now written asOPTIONAL, matching the publishedIcebergschema and other readers. #112669 (Groene AI). - Fixed a heap-use-after-free in the pipeline executor that could crash the server when a query removes processors at runtime (for example
FINALwith lazy reads or external sort), found by the AST fuzzer. #111017 (Groene AI). - Fix a use-after-free (segmentation fault) when a query with a shared storage snapshot (setting
enable_shared_storage_snapshot_in_query) strips data parts from the snapshot — e.g. a streaming subquery reading the sameMergeTreetable that another part of the query reads concurrently. #111192 (Alexey Milovidov). - Reject unsupported uses of
AggregateFunctioncolumns in TTL expressions atCREATE TABLEtime (e.g.TTL toDateTime(state)) instead of failing later during TTL execution withILLEGAL_TYPE_OF_ARGUMENT. This also covers states carried insideVariantalternatives andDynamicvalues. Valid state-aware consumers such asfinalizeAggregationare still accepted. #107366 (Ria Khatoniar). - Fix a
LOGICAL_ERROR(CTE '...' does not have query tree, but was not planned yet) when aMATERIALIZEDCTE is referenced from more than one join-tree position (for example two joined subqueries, or a joined subquery plus a scalar subquery inWHERE) in a query over aDistributedtable. The query now executes instead of raising the exception (it aborted the server in debug/sanitizer builds). #108924 (Groene AI). - Preserve original key order in bucketed Map serialization to fix comparison operations that depend on it. #109178 (Pavel Kruglov).
- Fixed
made_current_atinsystem.iceberg_historybecoming1970-01-01for a retained snapshot afterALTER TABLE... EXECUTE expire_snapshotson an Iceberg table. Also fixedsystem.iceberg_historyreturning no rows for a table whose metadata has nosnapshot-log. #111781 (Groene AI). - Fixes a
FixedStringtext try-parse that leaves partially appended bytes in the column when parsing fails, which can cause aSizes of nested column and null map of Nullable column are not equallogical error during serialization ofVariant/Array/Nullablecolumns, or silently shifted result bytes. #111908 (Groene AI). - Fixes
replaceOne,replaceAll,replaceRegexpOneandreplaceRegexpAllignoringmax_execution_timeandKILL QUERY. A single call now checks for cancellation while it works, so a long-running replacement over a large value or a large number of rows stops instead of holding a server thread until it finishes. Such a call has no partial result to return, so undertimeout_overflow_mode = 'break'it raises the deadline as an error: always when constant-folded, and in the pipeline whenever this checkpoint is reached before the executor’s between-block check, which still stops the query silently. #112483 (Groene AI). - Fixes a logical error and a wrong dependency record when an ordinary
VIEWbody references a table or dictionary through a query parameter, as inCREATE VIEW v AS SELECT x FROM {db:Identifier}.t. Such a view no longer records a referential dependency on a same-named table of the current database, so unrelated tables can be dropped again. #112704 (Groene AI). - Fixes a wrongly typed read of a
Nestedelement subcolumn whose column was dropped and re-added. Selecting such a subcolumn together with its own parent column returned the whole element in the subcolumn’s slot while the block still declared the element type, which produced arbitrary values in release builds and a logical error in debug and sanitizer builds. #112769 (Groene AI). - Fixed
Cannot read all data of type FixedStringwhen reading theproduct_quantization_codebooksubcolumn of a column with aQuantized('product',...)codec. The per-part codebook is written after the data of all granules, so it is not delimited by marks, and a read whose mark range ended before the part’s final mark could read it short. #112818 (Alexey Milovidov). - Fixes a segfault and silent data corruption when an
INSERTinto theFileengine or thefiletable function appends to a non-empty file in a format that does not support appending, such asAvro. Writing through a file descriptor or a partitioned path bypassed the existing check, so the format prefix was suppressed and a second header was written after the existing bytes, leaving the file unreadable. Such anINSERTis now rejected withCANNOT_APPEND_TO_FILE, as it already is for a plain path. #112839 (Groene AI). - Fix
connectionIdraisingContext has expiredwhen it is used inside a subquery by capturing the client’s connection id when the function is built. Closes #112533. #112870 (ClickGap AI Bot). - Fixed parsing of integers that do not fit into the target type in
Poco::NumberParser, which is used to read JSON numbers. Such a number was silently parsed as a wrong value (for example,18446744073709551617became1) instead of being rejected, and aUInt64number above theInt64maximum did not survive an AST JSON round trip. #112904 (Alexey Milovidov). - Fix
IS DISTINCT FROMforArrayandMapvalues compared withNULL. Closes #103042. #103162 (yanglongwei). - Prevent exhausted retries for leader-executed replicated distributed DDL from permanently blocking subsequent
ON CLUSTERDDL queries. #108505 (Ahaan Limaye). - Fix a
LOGICAL_ERROR(“Trying to extract chunk from ChunkBuffer before all inputs are finished”) when a set operation (INTERSECT/UNION ALL/EXCEPT) combines branches that use correlated subqueries andcorrelated_subqueries_default_join_kind = 'left'. #108554 (Groene AI). - Conversion of out-of-range floating-point values (
BFloat16,Float32,Float64) and ofUInt64values aboveInt64::max()toDateTimeandTimenow reliably saturates to the range boundaries on all architectures (previously the result of an out-of-range conversion was architecture-dependent and could wrap around on x86-64), and non-finite values (NaN,inf) now throw an exception instead of producing an arbitrary result. The same fix is applied to the float-to-Dateconversion path oftoDateand to the conversions ofUInt64and of wide integers ((U)Int128,(U)Int256) toDateandDate32, which could return a pre-epoch day instead of saturating. Conversion of a number toTimenow saturates to the range of the type for every numeric source type (previously values from narrow unsigned or wide integer sources were stored unclamped and clamped only when printed), and the accurate cast toTimeno longer rejects the negative values thatTimesupports, nor silently saturates the values that do not fit into it. The accurate cast of a number toDate32(accurateCast,accurateCastOrNull) no longer silently saturates an out-of-range or non-finite value, but throws or returnsNULLas it already did forDateandDateTime, and theOrDefaultflavours return the default value ofDate32for such an input. The accurate cast of a non-integral floating-point number toDate,Date32,DateTimeorTimeis now rejected instead of being silently truncated. Also fixed thetoDateTime32function documentation, which mistakenly showedtoDateTime64examples and described theDateTime64value range. #110459 (Alexey Milovidov). ALTER TABLE... DETACH PARTITION/PARTnow fsyncs the clone it creates underdetached/(the part subtree plus the directory chain up to the disk root) when the table’sfsync_part_directorysetting is enabled, for both Full (directory) and Packed part storage. Previously the clone was never fsynced while the empty covering part that removes the rows from the active set was, so a power loss right after the acknowledgement could destroy the detached data on btrfs (the un-synced clone directory entries roll back, leavingdetached/empty and nothing toATTACH). Gated on the existingfsync_part_directorysetting; default behavior is unchanged. #111426 (Groene AI).- Fix
CREATE OR REPLACEleaving the replaced object behind under an internal name when the caller lacks the drop privilege on it. #111466 (Nikolay Degterinsky). - Fixed a crash when running a
STREAMread (enable_streaming_queries = 1) over a table with more than one partition and a row policy defined on it. In debug and sanitizer builds it failed with theFilter column... not found in DAG outputslogical error; in release builds it could segfault. #111572 (Groene AI). - Fix
count()on Iceberg tables whose snapshot summary is inaccurate or corrupted: the trivial count optimization now derives exact row counts from the manifest files, and falls back to a real scan when row-level deletes make metadata counts inexact. Also fix IcebergOPTIMIZE TABLEwriting incorrect manifest-list counts and lineage, and maketotalBytesmetadata robust against corrupted summaries. #111617 (Melvyn Peignon). - Fix a DEFAULT column missing in a part being filled with the type default instead of the DEFAULT expression when the PREWHERE condition was split into multiple read steps. Closes #111757. #111795 (Yarik Briukhovetskyi).
- Fixed
Expected UInt64 column for __grouping_set, got BLOBandColumnBLOB should be converted to a regular column before usagelogical errors on a distributed query executed on a shard withenable_parallel_blocks_marshalling(enabled by default), for example withGROUP BY GROUPING SETSover a cluster that has a local replica, or when reading aMergetable that spans a local and a distributed table.BlocksMarshallingStepis no longer added to plans whose blocks are consumed in the same process. #111997 (Groene AI). - Operations now fail when corrupt MergeTree statistics are loaded instead of ignoring the error. #112201 (Sergey Kuznetsov).
- Fixes a logical error when PREWHERE is used on a Merge table over another Merge table or a materialized view whose column type differs. Also fixes a row policy being silently ignored on tables that read from remote servers (a Distributed table, or a table wrapping one), which could expose rows the policy was meant to hide; such queries are now rejected with an ILLEGAL_PREWHERE error. Define these policies on the underlying local tables on each remote server instead; note that such a policy is still not applied to reads shipped with
serialize_query_plan = 1, which is a separate, pre-existing bug. #112326 (Pedro Ferreira). - Fixes
connection_pool_max_wait_msso that its documented and default value0means an infinite timeout. A query that found the connection pool full used to retry in a tight loop, consuming CPU and loggingNo free connections in pool. Waiting 0 ms.on every iteration. It now waits until a connection is returned to the pool. Closes #112053. #112380 (Groene AI). - Fixes silent loss of acknowledged Iceberg writes on HDFS: an Iceberg commit publishes each new metadata file with a conditional write, but
HDFSObjectStoragedropped the condition and performed a plain overwrite, so concurrent writers were all acknowledged while one writer’s snapshot became unreachable. HDFS now refuses a conditional write instead, so storage-managed Iceberg writes on HDFS,CREATE TABLE... ENGINE = IcebergHDFS(...)with an explicit column list included, now fail. Reads are unaffected. #112437 (Groene AI). - Fix an out-of-bounds read (a crash in release builds) in insert deduplication when an
INSERTflows through a materialized view whose inner query changes the number of rows and the deduplicating target table is partitioned.DeduplicationInfo::filterToPartitionattributed each deduplication token to partitions by walking the token’s source-row range over a partition selector sized to the (smaller) view-output block, reading past its bounds. It now keeps every token in every partition for any materialized-view target — where the source-row-to-partition mapping no longer exists after the row count changed — instead of the out-of-bounds walk (and instead of theNOT_IMPLEMENTEDthat a later guard raised for the same insert). #112649 (Sema Checherinda). - Fixes a logical error (which aborts in debug and sanitizer builds) when
finalizeAggregationis applied to a column whose aggregate states come from different functions that share a state representation but finalize to different types — for examplequantileStateandquantilesState(0.9)brought together by aUNIONor produced viaarrayReduce. Such queries now raise a normal error instead of crashing. #112662 (Zain Ul Abidin). - Fix
DELETEonKeeperMaptables deleting only the firstmax_block_sizematched rows while reporting the mutation as successfully completed. Also fixDELETEwithkeeper_map_strict_mode = 1not being atomic: it could fall back to unversioned removals and delete rows that were concurrently updated, and it applied the matched rows block by block so a conflict could leave the delete partially applied. #112777 (Alexey Milovidov). - Fix
ALTERonMergeTreetables being applied while an incompleteRENAME COLUMNalter-mutation is still in progress. That could update the storage metadata incompatibly and block later mutations completely. #112783 (Mikhail Artemenko). - Fixed server startup and
ATTACHfailing withWITH RECURSIVE is not supported with the old analyzerfor a view with a recursive CTE whenenable_analyzer = 0is the server default. #112784 (Nikolay Degterinsky). - Fixes a logical error when a
Jointable engine is used on the right side of a JOIN whoseONsection contains a condition referencing columns of both tables, for exampleON (t.key = j.key) AND (t.a < j.a). Such a query is now rejected with a clear exception instead of raisingrequired columns:... but not found any in left tableorstd::bad_variant_access. #112815 (Groene AI). - Fixes wrong results for a
JOINwhoseONclause carries a mixed condition, that is a cross-side non-equi residual such asON (t1.key = t2.key) AND (t1.a * 10 < t2.a). Only the hash family evaluates such a condition, butfull_sorting_merge,partial_mergeand the direct key-value join claimed they could run these joins and then silently ignored the residual, returning extra rows. They now decline, so a hash algorithm is used instead. #112831 (Groene AI). - Fix
ReadBufferFromEncryptedFile: Wrong file positionlogical error when reading aCompactpart from anencrypteddisk with direct I/O, which made merges get stuck insystem.replication_queue. #112943 (Alexey Milovidov). - Fix a quadratic slowdown when parsing a PromQL query with a long tail of unrecognized characters (e.g. a
FixedStringvalue padded with NUL bytes): the parse of a megabyte-sized invalid input used to keep a thread busy for tens of minutes and was uncancellable, because it happens during query analysis. Now the parser stops at the first error. #112944 (Alexey Milovidov). - Reject PromQL durations whose units are repeated or not ordered from longest to shortest. #112954 (Minh Vu).
- Fix a hang when writing
Parquetwithoutput_format_parquet_parallel_encodingenabled (the default) andmax_threadsgreater than 1. If the encoder failed to schedule an additional thread, its live-thread counter underflowed and the write could stop making progress permanently instead of finishing or reporting an error. #112959 (Groene AI). #113170 (Alexey Milovidov). - Fixed
geohashesInBoxspending an unbounded amount of time on a box of zero area, such asgeohashesInBox(0., 0., 180., 0., 12). Such a query returned the correct single geohash but burned roughly 5e8 empty loop iterations per row and ignored bothmax_execution_timeandKILL QUERY. #112976 (Groene AI). - Fixed undefined behavior (null pointer passed to
memcpy) inreplaceRegexpOne/replaceRegexpAllwhen the replacement string substitutes a capturing group that did not participate in the match, e.g.replaceRegexpAll('abc', '(a)|(b)', '\\2'). #113012 (Alexey Milovidov). - Reject a
SETTINGSchange marked as written without a value when it carries a value other thantrue, and never elide the value of such a change when formatting a query. Previously a crafted AST JSON payload could execute aBoolsetting withfalsewhilesystem.query_logandformatQueryFromJSONshowed the valueless form. #113025 (Alexey Milovidov). - Fixed undefined behavior and a silent scheduling error when a background task is scheduled with a very large delay, for example by a refreshable materialized view with a huge
REFRESH AFTERperiod. Delays are now bounded to the largest representable value instead of overflowing. #113041 (Groene AI). - Fixed an out-of-bounds write when reading a
ParquetDECIMALcolumn whose physical type is wider than the type its declared precision maps to, for exampleDECIMAL(9, 2)stored as physicalINT64. Such files are validParquetand other writers produce them, but the reader sized the destination column from the declared precision while the decoder wrote the physical width, corrupting memory. Reading such a file now also raisesDECIMAL_OVERFLOWwhen a value does not fit the declared precision, instead of returning corrupted data, and reads losslessly with a type hint at least as wide as the physical type. #113046 (Groene AI). - Fixed
intDivon a non-constant column with the constant divisor -1 silently wrapping the division of the minimal signed number (e.g.intDiv(-9223372036854775808, -1)) instead of throwing theILLEGAL_DIVISIONexception like the other execution paths do. The silent wrap could also produce wrongORDER BY/DISTINCTresults, because the read-in-order optimization correctly treatsintDivby a negative constant as monotonic, and the wrapped value violated the resulting sort order. #113048 (Alexey Milovidov). - Fix an incompatibility that text indexes created in ClickHouse 26.3 with
unicode_wordtokenizer cannot be loaded in later versions. #113061 (Robert Schulze). - Fixed a
Pipeline stucklogical error in queries that scatter data by partition, such as a window function withPARTITION BYor a join withjoin_algorithm = 'parallel_full_sorting_merge', when one shard’s downstream finished while a block was only partially distributed. #113190 (Groene AI). - Fixed wrong results when a hash join has a single
LowCardinalitykey of a type wider than 8 bytes (UInt128,Int128,UInt256,Int256, and theirNullablevariants). Such a join silently returned rows whose key values are not equal. #113230 (Groene AI). - Fix
ALTER TABLE ... ADD PROJECTIONover a table-levelALIAScolumn leaving the table unusable, with subsequentINSERTfailing withUNKNOWN_IDENTIFIER(Missing columns), when the session hadoptimize_respect_aliases = 0. #109091 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKandLOGICAL_ERRORexceptions in adirectJOINover aMergeTreeright table, and related aborts in debug and sanitizer builds. #109932 (Groene AI). - Fix comparisons that previously threw
ILLEGAL_TYPE_OF_ARGUMENTwhen the operands have no least common supertype. Arrays such asArray(Int64)vsArray(UInt64)andArray(Int256)vsArray(UInt256)can now be compared lexicographically with=,!=,<,<=,>,>=,IS DISTINCT FROM, andIS NOT DISTINCT FROM.isDistinctFromandisNotDistinctFromnow also compare supported non-array numeric and decimal pairs by value instead of throwing, and equality comparison for arrays nested insideTuple(Nullable(...))is also fixed. Closes #33897. #110245 (Diego Gomes Tomé). - Fix a
LOGICAL_ERROR(Bad cast from ColumnString to ColumnLowCardinality) during primary-key index analysis when aLowCardinalitykey column is wrapped in a nestedCASTchain that re-introducesLowCardinality, e.g.WHERE CAST(CAST(s, 'LowCardinality(String)'), 'String') < '5'. In debug and sanitizer builds this aborted the server; in release it failed the query. #111050 (Groene AI). - Fix wrong results for a
FULL JOINon aJoinengine table withUSINGwhen the left key isNullableand the storage key is not: an unmatched left row with aNULLkey returned0instead ofNULL. #111371 (Groene AI). - Fix stale and deleted row versions being visible when a
MaterializedPostgreSQLdatabase is read through aMergetable. Such reads now go through theMaterializedPostgreSQLwrapper, with the sameFINALand_sign = 1filtering as direct reads. #112382 (Alexey Milovidov). - Fix
Bad cast from ColumnNullable to ColumnStringwhen a mutation that rewrites the whole part runs on a part whose column type is older than the one in the table metadata, for example afterALTER TABLE ... MODIFY COLUMNfollowed byALTER TABLE ... MATERIALIZE PROJECTION. #112501 (Alexey Milovidov). - Fix row-based input formats ignoring
KILL QUERYandmax_execution_timefor minutes while parsing a block. They now check for cancellation every 8192 rows, so a killedINSERT(including a background async-insert flush) stops promptly instead of running to the end of the block. #112646 (Groene AI). - Fix
RENAME TABLEchecking the maximum table name length against the source database instead of the destination one. Renaming a table into a database with a long name could produce a table thatDROP TABLEcould not remove, and renaming a table out of such a database was wrongly rejected. #113019 (Groene AI). - Fix
UNKNOWN_IDENTIFIERwhen selecting from aVIEWwhose declared column types differ from the types its inner query produces, for exampleSELECT sum(length(arr)) FROM vwherevdeclaresarr Array(UInt8)over aStringcolumn. With the defaultoptimize_functions_to_subcolumns = 1, the optimizer rewrotelength(arr)into a read of thearr.size0subcolumn and forwarded that name into the inner query, which has no such subcolumn. #113057 (Groene AI). - Fixed an exception (in release builds, an error that prevents the server from starting) when a mutation predicate uses the
mergetable function without an explicit database name. The database of the mutated table is now used, the same way as for table names. #113185 (Alexey Milovidov). - Fix wrong results and a
LOGICAL_ERRORwhen reading a subcolumn of a dropped-and-re-addedNestedmember together with a present member of the same group, on aMergeTreetable withshare_nested_offsets = 1. The present members returned values from a later block whenever the read spanned more than one block. #113225 (Groene AI). - Fix a hang of
ALTER,OPTIMIZE,TRUNCATE, and partition-manipulation statements withalter_sync = 2onReplicatedMergeTreewhen the table starts shutting down while the statement waits for another replica, for example because of a concurrentDROP DATABASE ... SYNC. Such a statement now fails withUNFINISHEDand also honorsmax_execution_timeandKILL QUERY. #113228 (Groene AI). - Do not write ANSI escape sequences to
INTO OUTFILEwhenstdoutis a TTY. #113252 (Azat Khuzhin). - Fix a rare use-after-free in the async insert queue when different entries have identical deadlines. #113363 (Miсhael Stetsyuk).
- Fix silently empty tables when more than one
ENGINE = Backupdatabase is created from the same backup, or when such a database is recreated under a different name. The storage policy that backs aBackupdatabase is now identified by a name that also covers the local database name, so each database gets the disk built for its own data path. #113378 (Groene AI). - Fix rows never being deleted when a
MergeTreetable has two or moreTTL ... DELETE WHERErules whose time expression is identical and which differ only in theWHEREcondition. After a TTL delete merge, the part’srows_where_ttl_infowas reset to zero, so no further TTL merge was ever scheduled for it and the expired rows were retained indefinitely with no error or log message. Closes #113116. #113384 (Groene AI). - A query over a
Mergetable (or themergetable function) that matches many tables now reacts toKILL QUERYandmax_execution_timewhile the per-table query plans are being built, instead of only after the planning of all children has finished. Withtimeout_overflow_mode = 'break', it now also stops building query plans for the remaining matched tables and returns the partial result without an error, as that mode documents. #113415 (Alexey Milovidov). #113642 (Groene AI). - Fix
clickhouse-clientexiting with code139instead of0after cancelling a query with Ctrl+C, or after anINSERTthat reads data from stdin. #113431 (Groene AI). - Allow the
preprocessorandpostprocessorexpressions of a text index to referenceALIAScolumns. #110014 (Jimmy Aguilar Mena). - Fixed several cases where parallel replicas returned duplicated rows:
distributed_aggregation_memory_efficientwas ignored by plan-based parallel replicas, so the buckets of the memory-efficient merge arrived out of order and were merged twice; and a shard was read from all of its replicas although the data was not split between them, when parallel replicas were not applicable to the query or whenparallel_replicas_moderequested custom-key filtering withoutparallel_replicas_custom_key. #112942 (Nikita Taranov). - Fixed
CREATE TABLE ... AS SELECTbecoming unkillable when its populatingSELECTfailed anddatabase_atomic_wait_for_drop_and_detach_synchronouslywas enabled: the internal cleanupDROPof the temporary table waited for the background drop queue and ignored bothKILL QUERYandmax_execution_time. #113504 (Groene AI). - Fixed
ALTER TABLE ... EXECUTE remove_orphan_filesdeleting a livemetadata/version-hint.textfile of anIcebergtable. Its reachable-set entry was built by string concatenation assuming a trailing slash on a value that never has one, so the real hint file was never recognized as reachable and was removed once older than theolder_thanthreshold. Withiceberg_use_version_hint = 1, the table then failed to read at all. #113548 (Groene AI). - Fixed a parameterized view losing its database when a query referencing it without qualification was sent to a shard, so the shard resolved the name against its own default database. Depending on what that database contained, the query either failed with
UNKNOWN_FUNCTIONor silently returned rows from a different view. AffectsIN,JOIN, andremotethrough aDistributedtable. #113550 (Groene AI). - Fixed a
LOGICAL_ERRORwhen a query filterssystem.databaseson thenamecolumn with a subquery insideindexHint, for exampleSELECT count() FROM system.databases WHERE indexHint(name IN (SELECT 'foo')). #113556 (Groene AI). - Fixed an endless loop in background merges and
OPTIMIZEwhenmerge_max_block_size_byteswas set below thebyteSize()of an empty column. An emptyLowCardinalitycolumn still carries its dictionary, so the byte limit could be reached before a single row was merged; the merge then produced empty blocks forever, burning 100% of a CPU core and never releasing its background-pool slot. #113585 (Groene AI). - Fixed a query over a
Variantcolumn ignoringmax_execution_timeandKILL QUERY. Calling a function with severalVariantarguments resolved the function once per alternative of every argument, and neither of the two loops doing that work checked for cancellation, so such a query could not be stopped until it finished. #113612 (Groene AI). - Fixed
Unknown compression methodfor theautoandnonecompression hints when written in any letter case other than all-lowercase, for examplefile('data.csv.gz', 'CSV', 'x String', 'AUTO'). Codec names such asGZIPwere already accepted case-insensitively; the two special hints now behave the same way. #113631 (Groene AI). - Fix constant folding under the new analyzer changing the type of a constant
Geometryvalue.Geometryis a namedVariantwhose alternatives can share the same storage layout (LineString/Ring,MultiLineString/Polygon, and empties), so two folded constants that differed only in their alternative could collapse into one, e.g.MULTIPOLYGON EMPTYbecameLINESTRING(). #110709 (Groene AI). - Fix an exception (
Cannot calculate columns sizes when columns or checksums are not initialized) during a merge of a single-columnMergeTreetable whose only column has a fully expiring columnTTL, withmin_bytes_for_wide_part = 1. #111169 (Groene AI). - Failing to start a background schedule pool (for example the
icebergpool under global thread-pool exhaustion) no longer aborts the server: the error is now a recoverable exception. Readingsystem.background_schedule_poolalso no longer creates those pools as a side effect. #111209 (Groene AI). - Fix an out-of-bounds read in the native protocol on corrupted index data. #112331 (Pavel Kruglov).
- Fix a deadlock that permanently hangs a
FilesystemorHDFSdatabase when two queries resolve the same table name at the same time. Every later query against that database blocks forever and cannot be interrupted, so the server needs a restart to recover. #112495 (Groene AI). - Fix
max_execution_timeandKILL QUERYbeing silently ineffective for a distributed query that is establishing connections to replicas. Such a query now stops at the next connection attempt instead of working through every remaining replica and retry. #112689 (Groene AI). - Fix
DROP TABLEandSYSTEM STOP VIEWhanging when a refreshable materialized view is blocked while planning its refresh query. #113188 (Nikolay Degterinsky). - Fixed
CREATE TABLEwithENGINE = Distributed(...)orENGINE = Buffer(...)and no column list revealing the structure of a referenced table the creating user is not allowed to see. For a localCREATE, the structure is now inferred under the user’s own context, soSHOW COLUMNSon the referenced table is required. ACREATEreplayed from the DDL queue (ON CLUSTER, or inside aReplicateddatabase) is not covered. #113220 (Groene AI). #113372 (Groene AI). - Fixed reading the internal
_temporary_and_external_tablesdatabase through themergetable function and theMergetable engine, which allowed one session to read the temporary tables of other sessions and other users. A database regexp now skips that database, and naming it explicitly is denied, the same way as direct access to it is. #113224 (Alexey Milovidov). - Fixed
countSubstrings,countSubstringsCaseInsensitive,countSubstringsCaseInsensitiveUTF8,countMatches, andcountMatchesCaseInsensitiveignoringKILL QUERYandmax_execution_time: a call over many rows, many matches, or one large value could run for minutes after the query was cancelled. #113369 (Groene AI). #113886 (Groene AI). - Fixed a mutation of a Compact part producing a different result depending on whether the part’s serialization info was still in memory or had been reloaded from
serialization.json, when the table usesserialization_info_version = 'basic'. OnReplicatedMergeTree, this made two replicas holding a byte-identical source part write different mutated parts, and the mutation failed withCHECKSUM_DOESNT_MATCH. Closes #113500. #113588 (Groene AI). - Fixed
made_current_atinsystem.iceberg_historyreporting the earliest time a snapshot became current instead of the latest one, when the samesnapshot-idappears more than once in theIcebergsnapshot-log(as a rollback leaves it). #113598 (Groene AI). - Fix wrong values for virtual columns such as
_tableor_databaseselected from the right side of aJOINagainst a key-value source such asEmbeddedRocksDB,KeeperMap,Redis, or a dictionary. The query could return a data-column value instead, or fail with aLOGICAL_ERRORexception. #113698 (Groene AI). - Fix
EXPLAIN ANALYZEover aMergetable with several children, a bare-columnPREWHERE, and a separateWHEREfailing withRequired output position N is out of range for pass-through inputs. Closes #113621. #113725 (Groene AI). - Fixed
clickhouse-disks moveof a directory failing withDIRECTORY_ALREADY_EXISTSon disks withmetadata_type = plain_rewritable(for examples3_plain_rewritable), which also left an empty destination directory behind. #113727 (Groene AI). - Fix
Mergetable reads failing withNo set is registered for key ...when a child declares anALIAScolumn containingINand the children disagree about that column’s default. #113757 (Groene AI). - Fixed
UNKNOWN_IDENTIFIERwithenable_analyzer = 0when aWHERErefers to a column produced byuntupleinside a subquery, for exampleSELECT t.keys FROM (SELECT untuple(arrayJoin(m)) AS t FROM ...) WHERE t.values > 0. Theenable_optimize_predicate_expressionrewrite pushed such a predicate into the subquery as aHAVING, where the name does not yet exist. #113760 (Groene AI). - Fix
ALTER TABLE ... MODIFY COLUMNfailing withCannot specify codec for column type ALIASwhen one statement both turns anALIAScolumn into a physical one (DEFAULTorMATERIALIZED) and specifies aCODEC. Closes #113693. #113853 (Groene AI). - Fix
ORDER BY ALLandGROUP BY ALLover a joinedMergetable under the old analyzer (allow_experimental_analyzer = 0). The query no longer fails with an internal exception, and debug and sanitizer builds no longer abort. #109139 (Groene AI). - Fix a sporadic
Cannot parse string ... as UInt64 ... While executing ValuesBlockInputFormatexception that could occur when inserting values whose expressions contain a numeric cast, such asinitializeAggregation('sumState', 0::UInt64). #110637 (Groene AI). - Fixed the periodic local disk check reporting failures for a healthy disk. When a server runs an embedded Keeper alongside a
localdisk, two check threads could probe the same file, transiently logFILE_DOESNT_EXIST,CANNOT_READ_ALL_DATA, orCANNOT_UNLINK, and temporarily count the disk in theBrokenDisksmetric. #110773 (Groene AI). - Fixed wrong results and a logical error
Cannot serialize FutureSetFromSubquery with no query planfor queries overMergetables and themergetable function when plan-based parallel replicas were enabled. #112849 (Alexey Milovidov). - A table in the
URLdatabase engine no longer discloses whether a local file exists to a user without the read source grant. BothEXISTS TABLE, which requires only theSHOW TABLESprivilege, and table-name resolution now wait for the grant check before probing the filesystem. #113029 (Alexey Milovidov). - Fixed a TTL expression becoming unusable when constant folding pruned the columns it refers to, for example
TTL d + INTERVAL 1 DAY DELETE WHERE isNull(x)over a non-Nullablex, which made everyINSERTinto the table fail withMissing columns. Also fixed the server failing to start when a table had a TTL expression over aVariantcolumn created withvariant_throw_on_type_mismatch = 0. #113042 (Alexey Milovidov). - Fixed cancellation of
postgresqltable function andPostgreSQLtable engine reads. Cancelling while the read was still starting up could race on the transaction pointer and be lost, leaving the query running until PostgreSQL finished it. #113150 (Groene AI). UNDROP TABLEcan now be interrupted byKILL QUERYwhile it waits for running queries to release the dropped table. #113263 (Alexey Milovidov).- Fix a memory leak of the whole XML parser when a
PocoXML handler throws mid-parse, for example onPoco::XML::NamePooloverflow while parsing a document with many unique element names. #113348 (Alexey Milovidov). - Fixed writes to the
HDFSdisk: they no longer fail withParent directory doesn't existwhen the generated object key contains nested directory prefixes, because the missing parent directories are now created. #113396 (Alexey Milovidov). - Fix wrong results and, in builds with assertions enabled, an aborted assertion for a
JOINonto a dictionary whoseONclause has a non-equi condition over both tables, such asON (t.key = d.key) AND (t.a * 10 < d.a), whenjoin_use_nullsis enabled. #113534 (Alexey Milovidov). - Fix a query hanging for up to
receive_timeoutseconds when it finishes very quickly on the initiator. #113551 (Nikita Taranov). - Fix
UPDATEand lightweightDELETEreading the wrong tables when the database of the updated table differs from the session database. Unqualified table names and themergetable function are now resolved against the database of the updated table, so the statement no longer silently updates or deletes rows selected from a different table. #113748 (Groene AI). - Fix a spurious
TOO_MANY_PARTSrejection of a parallelINSERT: whenmax_insert_threadsparallelizes a plainINSERT, the query no longer counts parts committed by its own sibling sinks. Closes #114015. #114016 (Alexey Milovidov). - Fixed
NO_SUCH_COLUMN_IN_TABLEwhen a query with parallel replicas selects anALIAScolumn of a table shipped as aGLOBAL JOINtemporary table,MULTIPLE_EXPRESSIONS_FOR_ALIASwhen both sides of a distributedJOINdeclare anALIAScolumn with the same name, andUNKNOWN_IDENTIFIERwhen aDistributedtable declares anALIAScolumn over anotherALIAScolumn, including as aJOIN USINGkey. #107700 (Yakov Olkhovskiy). - Fixed reading a CSV
Tuplewhose leading element isNULL. Withinput_format_csv_deserialize_separate_columns_into_tupleandinput_format_null_as_defaultenabled, a leading\Nin a row such as\N,1was taken for the whole column beingNULL, so the row was replaced by a default and the remaining element cells caused a parse error. The leadingNULLis now the value of the first element, withinput_format_null_as_defaultapplying to that element. A row that gives a single\Nfield for a whole bareTupleis now short by the remaining elements and is rejected; setinput_format_csv_deserialize_separate_columns_into_tuple = 0to read such a field as the whole column again. #109744 (Groene AI). - Fix a rare
Logical error: 'No more packets are available.'for a valid distributed query with aLIMIT. In debug and sanitizer builds it also aborted the server. #110334 (Groene AI). - Fixed a logical error (
!part.empty()) when aDistributedtable defined with an empty remote database name is used in aJOINwithdistributed_product_mode = 'local'. #110677 (Groene AI). - Fix resolution of fully qualified column names such as
db.table.columnin the analyzer for tables that have the same name as their database. Closes #82084. #110976 (Alexey Milovidov). - Fixed hash joins losing their post-build optimizations (conversion to a fixed hash table, the shared runtime filter, right-table reranging) whenever an automatic spill-to-disk threshold was configured, which has been the default since 26.5. #111972 (Alexey Milovidov).
- Fixed a bug where
ALTER TABLE ... MODIFY COLUMNthat changes aJSONtype hint (withallow_experimental_json_lazy_type_hintsenabled) on a column whose subcolumn is used in the primary/sorting key, partition key, or an explicit skip index could corrupt the on-disk key or index. Ordinary reads masked it via the cached structure, but after it was reloaded (for example on server restart) queries failed withCANNOT_READ_ALL_DATAor returned wrong results. SuchALTERs are now rejected whenever they change the on-disk type of a referencedJSONsubcolumn. Type-hint changes on columns outside those structures, or changes that leave the on-disk type of the referenced subcolumns unchanged (for example adding an unrelated typed path), remain metadata-only. #112302 (Pavel Kruglov). - Fix wrong results when
query_plan_join_swap_tableswaps anANY JOINwhilejoin_any_take_last_row = 1: ClickHouse now keeps the original join side order soANY JOINstill returns the last matching row. Closes #111645. #112458 (Vladimir Cherkasov). - Fixed
listObjectson a prefixed-endpointAzureBlobStoragedisk returning wrong blob names on every page after the first, because pagination bypassed the client wrapper that strips the endpoint prefix. Pagination now re-enters the wrapper via the continuation token so every page’s blob names are correct. #112872 (Arsen Muk). - Fixed unbounded memory allocation when reading a
Parquetfile whose Thrift metadata declares a container or string length larger than the metadata itself. Such a length is now rejected instead of being allocated for. #113212 (Groene AI). - Fixed
Cannot insert element into Set(NOT_IMPLEMENTED) whenread_in_order_use_virtual_rowis enabled and aMergeTreeread-in-order query combinesWITH FILL ... INTERPOLATEwith anINorhasfilter. #113264 (Groene AI). - Fix
optimize_read_in_orderbeing silently skipped for someORDER BYqueries, including queries that use a virtual row ortoString/CAST(..., 'Nullable(String)')over aStringsorting key. Also fix wrong results for filters orORDER BYontoStringofTime,Time64, orDateTimevalues in time zones with daylight saving time. #113291 (Vladimir Cherkasov). - Reject invalid
parallel_replicas_custom_keyexpressions such astuple()or(x, y)withILLEGAL_TYPE_OF_COLUMN_FOR_FILTERinstead of reading past the end of the custom-key type list. #113359 (Nikita Taranov). - Fix a server restart failure after the server is killed during
DROP TABLEof a table that uses a named collection: a laterDROP NAMED COLLECTIONcould succeed, leaving table metadata that references a missing named collection and making the next startup fail withNAMED_COLLECTION_DOESNT_EXIST. #113524 (Alexey Milovidov). - Fixes two cases where an AWS Glue
DataLakeCatalogdatabase reported a table as absent instead of reporting an error.SHOW TABLESandsystem.tablesno longer fail withDATALAKE_DATABASE_ERROR(“Exception calling GetTables … not found”) when a Glue database is absent while its tables are listed, for example because an unrelated database in the same AWS account was dropped concurrently; such a database now contributes no tables instead of aborting the listing.EXISTS TABLEno longer returns0for a table that exists when the underlyingGetTablecall fails for a reason other than the table being absent, such as an authentication, DNS, or 5xx failure. Every other Glue error still propagates in both paths. #113591 (Groene AI). - Fixed a Keeper durability bug where a crash while persisting the Raft state file (storing
termandvoted_for) could leave the node with no valid state and no backup. On restart the node could reset toterm = 0and grant a vote it had already granted in that term, which could cause two leaders and loss of committed data. The previous state is now kept until the new state file is fully written and synced. #113654 (Alexey Bakharew). - Fix a data race when a
MergeTreetable is destroyed while its background statistics-refresh, parts-refresh, or outdated/unexpected-parts-loading tasks are still running. #113722 (Alexey Milovidov). - Fix
ORDER BY ALLin aWINDOW VIEW, andUNKNOWN_IDENTIFIERerrors forINTERPOLATE,WINDOW, andLIMIT BYin a query over aMergeorDistributedtable with a join, with the old analyzer. #113759 (Alexey Milovidov). - Fix a memory leak in the experimental
SZ3compression codec: when compression of poorly compressible or corrupted data failed with an exception, temporary scratch buffers were left allocated. #113916 (Alexey Milovidov). - Fix quadratic complexity of parsing the address argument of the
remote,mysql, and similar table functions: a very long address (for example a megabyte-sized zero-paddedFixedString) made the query hang during analysis, where it could not be cancelled. #113918 (Alexey Milovidov). - Fixed
OPTIMIZE TABLEon anIcebergtable failing withUnsupported snapshot's operation type OVERWRITEwhen the table’s history contained a row delete that removed more than one row per position-delete file. Closes #113745. #113964 (Groene AI). - Do not replicate
ALTER TABLE ATTACH PARTITION FROMfor replicated db. #94835 (MikhailBurdukov). - Invalid Azure upload-size settings (for example
azure_min_upload_part_size = 0orazure_max_blocks_in_multipart_upload = 0) are now rejected early with a clear error instead of triggering an internal exception (second_size > 0) deep in the write path. This applies to both query settings and Azure disk configuration. #103394 (Statxc). - Fixed incorrect SQL literal escaping in
StorageSQLiteandsqlite()table function when pushingWHEREpredicates to SQLite: single quotes and control characters (\n,\r,\t,\) were escaped with backslashes, which SQLite does not interpret, causing syntax errors or wrong query results. Also fixed the escaping of string literals pushed down to PostgreSQL: strings nested insideINlists kept ClickHouse escaping, and control characters were sent as backslash sequences that PostgreSQL reads back as different bytes. #104217 (Shaohua Wang). - Fix
NOT_FOUND_COLUMN_IN_BLOCKexception inINNER JOIN ... ON arrayJoin(...) = ...queries whenquery_plan_convert_join_to_inis enabled and the SELECT references the source array column. #104809 (Shaohua Wang). - Fix IN and NOT IN expressions with non-constant right-hand side operands referencing columns from the current row, and align new analyzer tuple right-hand side handling with existing ClickHouse IN semantics. Under the old analyzer, a bare source column as the right-hand side (
x IN (arr)) still resolves as a table name and stays out of scope. #104993 (Yue Ni). - Fixed the error
Cannot add column ...: column with this name already existsonINSERT SELECTfrom a table function such asfile,s3orinput, when the same source column is selected more than once. #105982 (etienne). - Reject
max_replication_lag_to_enqueue = 0onReplicateddatabases. The value made the post-recovery unsynced check trivially true and aborted the server withLOGICAL_ERRORin debug and sanitizer builds.0is now rejected at parse time withBAD_ARGUMENTSfrom every source (CREATE DATABASE ... SETTINGS,<database_replicated>server-config block,ATTACHreplay, and upgrade-time replay of existing metadata). The smallest valid value is1. Closes #98823. #106006 (Groene AI). - Fix
Logical error: 'Pipeline stuck'in queries that useenable_sharding_aggregator = 1together with aUNION ALLandmax_streams_for_union_stepsmaller than the pipeline width.BufferedShardByHashTransformnow finishes empty-queue output ports as soon as its input is exhausted, and keeps pulling input when a demanded empty port has nothing drainable even if a sibling queue hit the back-pressure cap. #106251 (Groene AI). - Fixed a signed integer overflow when a wait-timeout setting, such as
interactive_delay, was set to a huge value: the wait could time out immediately instead of waiting, and the server could abort under the Undefined Behavior Sanitizer. #106961 (Groene AI). - Exporting
Time/Time64values outside a valid time-of-day (negative or>= 24h) to theArrowformat is now rejected with a clear error instead of writing invalid Arrowtime32/time64data. #107179 (Shaohua Wang). - Fix wrong results for
GROUP BYon aDistributedtable over duplicateALIAScolumns that expand to the same expression (e.g. two columns both defined astoString(x)) under two-level / memory-efficient distributed aggregation. The duplicate keys were collapsed into one on the shards but merged by the full key set on the initiator, so under two-level aggregation equal groups from different shards landed in different buckets and were not merged, returning a group once per shard with a splitcount(). #108855 (Groene AI). - Fixed a spurious
Inconsistent AST formattingerror forALTER TABLE ... MOVE PART ... TO SHARD '<path>'. The query formatter dropped theSHARDkeyword, so the reformatted query could not be parsed back, raising aLOGICAL_ERROR(a handled exception in release builds, an abort in debug and sanitizer builds). #109060 (Groene AI). - Rejects non-monotonic
Arrayoffsets on every read path that decodes them as absolute values, instead of only in theNativeformat. A corruptsetskip index granule previously passed unchecked and was then read out of bounds. #109212 (Groene AI). JSONExtractnow honourscast_string_to_date_time_modewhen converting string JSON values toDateTime/DateTime64, consistently withCAST. Closes #109126. #109252 (Utkal Singh).- Fix possible logical error “Unexpected substream … for column …” during bump of compatibility setting. #109496 (Pavel Kruglov).
- set missing coordination component in system.detached_parts size calculation. #109553 (Den Kalantaevskii).
- Fixed the block-wait timeout of streaming inserts (
input_format_max_block_wait_ms) potentially never expiring while the query profiler is active: the file-descriptor poll restarted with the full timeout after every profiler signal, so a stalled input source could delay the partial-block flush indefinitely instead of flushing when the wait limit is reached. #109602 (Shaohua Wang). - Constant folding during query planning no longer executes a function whose argument type differs from the type the function was resolved for during analysis. Such a mismatch used to raise a
LOGICAL_ERRORwhile the output header was being computed, which is an assertion failure in debug and sanitizer builds. Folding is now skipped instead, and a genuinely invalid query still reports a recoverableILLEGAL_TYPE_OF_ARGUMENTerror from the normal execution path. #109747 (Groene AI). - Fixes a mutation that references the
_sample_factorvirtual column failing mid-execution withUnexpected const virtual column: _sample_factorand leaving the mutation stuck. A mutation now reads it as1, the same value a query withoutSAMPLEreturns. #109813 (Groene AI). - Fix three issues with
use_constant_folding_in_index_analysis: a logical errorInvalid partition key sizethat could abort aSELECTusing a normal projection when the table setspart_minmax_index_columns = 'with_block_number_offset'; wrong results (silently dropped rows) for a filter on a modulo partition key such asPARTITION BY id % 200; and a crash (data race) when atextindex with asparseGramstokenizer is queried with aLIKEpredicate over many partitions withmax_threads > 1. #109896 (Groene AI). - Fix a data race (and rare crash) when a parsing/analysis error is reported while reading a file/object storage table. A parse error raised during lazy
KeyConditioninitialization was shared as a single exception object across reader threads, and two threads could concurrently append(in file/uri ...)to its message, racing on the exception message string. #109911 (Groene AI). - Fix propagation of query settings in
accurateCastOrDefault, and preserve sourceNULLs encoded byDynamicandVariant. Closes #109943. #109946 (Pavel Kruglov). #114912 (Alexey Milovidov). - Fixed incorrect results from
subBitmap,bitmapSubsetInRangeandbitmapSubsetLimitfor bitmaps still held in the small representation, includingUInt64andInt64element values above2^32, which were truncated to 32 bits. Comparisons in bitmap functions over signed element types now consistently use the unsigned value of the element type, so in anInt8bitmap the element-1is compared as255instead of as the sign-extended4294967295; this also fixesbitmapMin,bitmapMax,bitmapContainsandbitmapTransformon bitmaps that have grown past the small representation. Queries that passed sign-extended thresholds have to be adjusted: over anInt8bitmap,bitmapSubsetInRange(bm, 4294967168, 4294967296)becomesbitmapSubsetInRange(bm, 128, 256). Also fixedgroupNumericIndexedVectorreturning different results forInt8andInt16index columns than for wider index types, andnumericIndexedVectorGetValuereturning0for negative indexes. Corrected the bitmap function documentation, including the subset functions that were described as using 1-based indexing and the signedbitmapBuild/bitmapToArraysupport. #110072 (Rami Darwiche). - Fix
optimize_aggregation_in_orderignoring query cancellation.AggregatingInOrderTransformnow checks for cancellation while aggregating a chunk, so a query stopped byKILL QUERYor bymax_execution_time(in the defaulttimeout_overflow_mode = 'throw') stops promptly instead of running the whole chunk to completion. #110104 (Groene AI). - Fixed a race between
KILL TRANSACTIONandALTER TABLE ... UPDATE/DELETEexecuted inside a transaction: a rollback landing between the mutation’s registration in the transaction and its registration in the table left an orphaned mutation entry, which raised a logical error (Cannot find transaction ... that has started mutation ...) in background jobs and blocked all subsequent mutations of the affected parts until server restart. #110226 (Shaohua Wang). - Fix a
LOGICAL_ERROR(Left and right columns have same names) in the join order optimizer that could be triggered by a comma join over a multi-table view whenquery_plan_merge_expression_into_joinis enabled. #110227 (Groene AI). - Join-order cardinality estimation now composes column statistics over the parts surviving partition/PK pruning instead of all active parts. Previously a query pruned to a small partition was planned against table-wide statistics (observed 2500x row overestimation flipping the hash-join build side), and disabling statistics paradoxically produced a better plan. Also fixed: lazy FINAL was silently disabled for MergeTree relations under a JOIN because the join-order optimizer’s memoized index-analysis result was mistaken for an applied projection. #110283 (Sergey Kuznetsov).
- Fixed wrong results from correlated scalar subqueries when the outer query has duplicate values for the correlated column and the subquery is decorrelated via the CROSS JOIN path. Previously aggregates such as
count()andsum()were multiplied by the duplicate count. This affects the experimentalallow_experimental_correlated_subqueriesfeature. #110311 (Groene AI). - Fix a logical error (
Function node with name '...' is not resolved as ordinary function) that could occur withoptimize_or_like_chainenabled when an aggregate or window function appeared on the left-hand side of aLIKE/ILIKE/matchinside anORchain. #110641 (Groene AI). - Fix a
TTL ... DELETE WHERE <cond>never removing rows that started matching<cond>because of anALTER TABLE ... UPDATEon a column referenced in theWHERE. The mutation now recalculates the row TTL, so the newly matching expired rows are deleted instead of being silently retained. #110648 (Groene AI). - Fix an accounting leak in memory tracking: when an allocation was rejected by a parent memory tracker (for example, the server-wide memory limit), the thread, query, and user level trackers kept the rejected amount. The error accumulated over time, inflating
MemoryTrackingand per-query/per-user memory usage, and could lead to spuriousMEMORY_LIMIT_EXCEEDEDerrors. #110784 (Seva Potapov). - Fixed non-canonical WKB serialization of an empty polygon:
wkb(POLYGON EMPTY)now emitsnumRings = 0instead of a spurious single zero-point ring, so a WKB round-trip of a standard empty polygon is identity-preserving. #110796 (Groene AI). - Fixes a case when using CTE column aliases with
INTERSECTorEXCEPTqueries, e.g.WITH t (a, b) AS (SELECT 1, 2 INTERSECT SELECT 1, 2) SELECT a, b FROM t, the query was failing with UNKNOWN_IDENTIFIER error. Closes #104770. #110885 (Yarik Briukhovetskyi). - Fixed a
std::length_error(LOGICAL_ERROR) when reading a MergeTree table with a pathologicalmax_streams_for_merge_tree_readingvalue (near the maximum ofUInt64) together withallow_asynchronous_read_from_io_pool_for_merge_tree = 1. The setting is now clamped to the same ceiling asmax_threads. #110936 (Groene AI). - Fixes a crash (null pointer dereference during query analysis) when
getSubcolumnis called on aJSONargument with an internal type-hint subcolumn name, that is one starting with a backtick type marker. #110940 (Groene AI). - Fixed
Nested type LineString cannot be inside Nullable type (ILLEGAL_TYPE_OF_ARGUMENT)when reading a nullable MySQL spatial column (LINESTRING,POLYGON,MULTILINESTRING,MULTIPOLYGON,MULTIPOINT, or the genericGEOMETRY) through themysqltable function or theMySQLtable/database engines. Such columns now fall back toNullable(String)holding the value as MySQL returns it (a 4-byte SRID prefix followed by the WKB payload).POINTkeeps mapping toNullable(Point). #110943 (Groene AI). - Fixes
Nativeserialization ofSimpleAggregateFunctionwrappers containing versioned aggregate states for older peers. #110997 (Groene AI). - Fixed a
LOGICAL_ERROR: ReadBuffer is canceled. Can't read from it.that could occur in agrace_hashjoin when reading spilled blocks failed mid-read while multiple threads shared the reader. #111056 (Groene AI). - Each SSH key now counts individually toward the
max_authentication_methods_per_userlimit, so the limit applies consistently regardless of syntax. Previously, multiple keys in a singlessh_keymethod counted as one. #111181 (Yecine Megdiche). - Fix a
LOGICAL_ERROR(Reading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query plan) when a reused materialized CTE (enable_materialized_cte) is read on a branch whoseWITH TOTALSorextremesoutput is discarded, including outer aggregation,INSERT ... SELECT, set operations andEXPLAIN ANALYZE. #111194 (Groene AI). - Fixed
map[key]returning the value of a later duplicate key instead of the first one. When aMapcolumn contained duplicate keys, the result ofmap[key]could depend on preceding rows in the same block and on theoptimize_functions_to_subcolumnssetting, so aSELECTand aWHEREover the same row could disagree. #111246 (Groene AI). - Fix a logical error
!rhs_literal->getValue().isNull()in the logical-expression optimizer when anANDchain compares a column against a NULL-valued constant of a non-Nullabletype (for example a NULL-valuedVariant) withuse_variant_default_implementation_for_comparisons = 0. #111292 (Groene AI). - Fixed
NOT_FOUND_COLUMN_IN_BLOCK/THERE_IS_NO_COLUMNerrors (and, on some releases, silently wrong results) for aRIGHT JOINwhenparallel_replicas_min_number_of_rows_per_replicais set and a left-table column is projected. #111332 (Groene AI). RESTOREnow fsyncs the restored part files when the destination table hasfsync_after_insertenabled, so a restored part is as durable against power loss as an inserted one. Previously restored files were only written and closed (never fsynced), so a power loss right afterRESTOREreturnedRESTOREDcould leave the parts torn and the table empty. #111378 (Groene AI).- Fix a rare Keeper data-loss window on local snapshot disks: the snapshot write path now fsyncs the snapshot directory after removing the
tmp_marker, so a power loss can no longer drop the marker unlink while keeping the snapshot content. Previously such a crash made Keeper treat a good, fully-synced snapshot as incomplete and delete it on restart, losing acknowledged writes even withforce_sync=true. Snapshot disks backed by object storage are not covered. #111397 (Groene AI). - Fix an out-of-bounds read (release) / logical error (debug) in the lazy materialization optimization, and a logical error in
Pipe::unitePipesforMergetables, when the direct-read-from-text-index optimization leaves an unused index virtual column in the read header of aMergeTreetable with multipletextindexes. #111467 (Groene AI). - Fixed the
_timevirtual column of theurl/urlClustertable functions always beingNULLon musl-based builds, caused by non-portable parsing of the HTTPLast-Modifiedheader. #111619 (Konstantin Bogdanov). - Fixed a
LOGICAL_ERROR(Cannot create part with type Compact and storage type Full because table does not support polymorphic parts) raised when aMergeTreetable loads a pre-existingCompactpart while its current settings disable polymorphic parts (non-adaptive granularity). This could happen, for example, when a read-only table shares an on-disk path with another table and reloads its parts viaSYSTEM RESTART DISKor on server startup. In debug and sanitizer builds the exception aborts the server. #111626 (Groene AI). - Fixed
CREATE TABLE ... ENGINE = KeeperMapfailing withCoordination error: No node, path .../metadata/drop_lock_versionwhen another table on the same Keeper path is dropped concurrently. The create now treats the vanished metadata subtree as a completed cleanup and retries, as it already does for the same situation one statement later. #111966 (Groene AI). - Fix a race between a
ReplicatedMergeTreemutation and the removal of old temporary directories that could publish a mutated part with some of its files missing, making reads of that part and all its later mutations fail. #111992 (Alexey Milovidov). - Fix
quantileDeterministic,quantilesDeterministicandmedianDeterministicreturning different results for the same data on every run when the query uses parallel replicas, a distributed table, or external aggregation, or when the states are stored in a table (including inside aDynamicvalue). States written before this version under the unversioned type spelling keep the previous behavior, since their layout cannot change. #112052 (Alexey Milovidov). - Fixes
serialize_string_in_memory_with_zero_bytebeing dropped from the serialized query plan. Withserialize_query_plan = 1, a cluster running with the setting disabled could diverge on the in-memory string representation between the initiator and the node executing the deserialized plan, because the setting was read on deserialization but never written on serialization and therefore always resolved to its default on the executing node. #112131 (Groene AI). - Fixed a stack frame being displayed as
?instead of its function name in fatal log messages and in thetrace_fullcolumn ofsystem.crash_log. It affected frames of ordinary functions that have code attributed to a libc++__functionalheader, which is common in release builds. #112152 (Alexey Milovidov). - Fixes silently missing rows when a query filters on
intDiv(constant, key)ordivide(constant, key). Primary-key and partition analysis reports the wrong direction of monotonicity for a constant divided by a key column, so matching granules are pruned away and the query returns fewer rows with no error. Also fixesintDivwith an unsigned constant dividend whose high bit is set, stops claiming monotonicity when aDecimaloperand makes the division compute in the decimal’s native width, and stops key analysis from raisingCannot compare DB::IPv4 with longfor a valid query that divides anIPv4/IPv6constant by a key column. #112156 (Groene AI). - Fixed
DROP TABLE ... SYNChanging forever when a query oversystem.replicashad been killed before its status requests were processed. #112164 (Nikolay Degterinsky). - Fixed a server abort (
SIGABRT) when aBUFFERED_V1WebAssembly UDF returns an empty result buffer; the query now fails with a catchableWASM_ERRORand the server stays up. #112182 (Nikolai Ovchinnikov). - Fixed a use-after-free when a
JOINwithjoin_algorithm = 'direct'onto a dictionary was given a join key that is stored with sparse serialization.getColumnVectorDatareturned a reference to a temporary column, so the dictionary lookup read freed memory: release builds could return wrong results and debug or sanitizer builds aborted. #112327 (Groene AI). - Fixes cases where row policy was not used for MergeTree Projections during query execution. #112329 (Yarik Briukhovetskyi).
- Fixed data corruption when inserting into an Iceberg table reached through a
MATERIALIZED VIEW. The data file was written against the target’sCREATE-time column types instead of its live Iceberg schema, so aDateTimevalue was stored as a bare Avrointand read back as microseconds, and withDateTime64(0)orDateTime64(9)the file could not be read back at all. As a consequence,INSERT INTO <materialized view>against a target whose Iceberg schema is wider than the view’s declared columns now raisesTYPE_MISMATCHinstead of writing a corrupt row. #112359 (Groene AI). - Keeper no longer refuses a
Setrequest with empty data when it is overmax_memory_usage_soft_limit. Such a request cannot increase the amount of stored data, and refusing it prevented clients from re-establishing their session, which could keep tables read-only for the whole duration of a Keeper memory event. #112386 (Shaohua Wang). - Fixed a Keeper follower dropping out of quorum for a long time, causing mass
Session expirederrors, after it successfully installed a large snapshot: the leader discarded the follower’s acknowledgement whenever applying the snapshot took longer than the snapshot-install timeout, and then walked that follower’s log index backwards one entry per round trip. Also added the Keeper settingnuraft_snapshot_sync_ctx_timeout_msto control that timeout, which previously could only be changed throughraft_limits_response_limitand therefore not without also slowing down dead-peer detection. #112405 (Shaohua Wang). - Fix data races in profile events and memory tracker. #112466 (Miсhael Stetsyuk).
- Security related bugfix. #112479 (Kseniia Sumarokova).
- Fixes reading a stale secondary (skip) index after an
ALTER TABLE ... MODIFY COLUMNtype change whose mutation never ran, for example becauseKILL MUTATIONremoved it: the granules on disk were written with the old type but decoded with the new one, raisingLOGICAL_ERROR, requesting multi-exabyte allocations, or silently returning a wrong result. Also fixes a wrong result from an index over an expression whose meaning changes while every stored byte stays identical, so no mutation is created at all: aMODIFY COLUMNaltering only aDateTimetimezone, or only a custom type name such asUInt8toBool. Such an index is now skipped for the affected part. Closes #112213. #112484 (Groene AI). - Fixed a crash when reading a Parquet file with inconsistent bloom filter metadata. Such files could also silently return fewer rows than they should. #112498 (Shaohua Wang).
- Fix AsynchronousBoundedReadBuffer’s readBigAt data race. Closes #109678. #112573 (Kseniia Sumarokova).
- Fixes a column alias list such as
(SELECT 1) AS t(x)orWITH t(x) AS (SELECT 1)not being visible inside theviewtable function, where a reference tot.xfailed withUNKNOWN_IDENTIFIERalthough the same construct works outsideview. #112690 (Groene AI). - Fixed the logical error
SortingAggregatedTransform already got bucket with number Nthat could occur in multi-layer distributedGROUP BYqueries using two-level aggregation. #112794 (Nikita Taranov). - Fixes a
NATStable withnats_streamset silently consuming nothing after the NATS server is restarted. TheJetStreamsubscription is now re-established automatically instead of requiringDETACH TABLEandATTACH TABLE. #112828 (Groene AI). - Fixed a transient Azure Blob Storage error on the read or merge path — an RBAC permission-propagation
403 Forbidden, a credential authentication failure, or a connect timeout surfaced as408— being misclassified as non-retryable and reported asPOTENTIALLY_BROKEN_DATA_PART(Code 740), raising a false critical alert for a healthy part. These transient failures are now treated as retryable, and a genuinely persistent one surfaces as a plain Azure error instead of a phantom broken data part. #112871 (Arsen Muk). - Fixed Azure batch object deletion recording no
system.blob_storage_logDelete events when the batch request itself failed, leaving the whole batch unlogged. A Delete event is now recorded for each object on a batch-level failure. #112873 (Arsen Muk). - Fix the per-part minmax index over
_block_numberand_block_offsetbeing lost after a table reload when the part was produced by a mutation that does not rewrite the whole part. #112878 (Alexey Milovidov). - Fixes a logical error and wrong results when a non equi
JOIN ONcondition that is evaluated during the join containsarrayJoin. Ahash,parallel_hashorgrace_hashjoin now rejects such a condition withINVALID_JOIN_ON_EXPRESSION. Where the expansion depends on one side only, move it into anARRAY JOINin a subquery before the join; a condition whosearrayJoinargument reads columns from both sides has to be restructured. #112889 (Groene AI). - Fix wrong results of
ORDER BYwhen reading from aMergetable overDistributedtables: rows could be returned out of order, and rows belonging in the result could be missing whenLIMITwas used. #112931 (Alexey Milovidov). - Fixed a
Boolconstant on the right-hand side ofINbeing converted to aStringleft-hand side as'1'/'0'instead of the canonical'true'/'false'(now consistent withCASTand thevaluestable function). #113051 (Yakov Olkhovskiy). - Fixes
viewscolumn inquery_logfor inserts to anAliastable whose target triggers materialized views, which was always empty. #113076 (Enric Calabuig). - Fixed
LOGICAL_ERRORwhen reading a table with asetskip index defined on an expression and the query repeats that expression with aNullableoperand, for exampleWHERE intDiv(id, (SELECT 1000)) = 3overINDEX b_set intDiv(id, 1000) TYPE set(100). A scalar subquery is enough to trigger it, since it is typedNullable. #113244 (George Larionov). - Fix a logical error (exception)
Chunk info was not set for chunk in MergingAggregatedTransformwhen the settinginject_random_order_for_select_without_order_byis enabled and an aggregation query reads from aMergetable containing aDistributedchild: the randomORDER BY rand()wrapper is no longer injected into queries planned only up to an intermediate stage. #113266 (Alexey Milovidov). - Fixed a query plan optimization stall when a
WHEREclause contains a large string constant with many dots and the table carries abloom_filter,tokenbf_v1,ngrambf_v1ortextskip index. Matching a filter column name againstJSONAllPaths(...)index columns enumerated every dot split of the name, which made skip-index condition building quadratic in the constant’s length. Closes #113003. #113289 (Groene AI). - Fixed
ATTACHof aKafkatable whenkafka_num_consumersexceeds the limit derived from the number of CPU cores. #113390 (Nikolay Degterinsky). - Fixed a permanent
DROP TABLEhang and memory leak after a query using a materialized CTE failed. The table stayed stuck in the drop queue until the server was restarted. #113397 (Shaohua Wang). - Fix a logical error
IDENTIFIER is not a table expressionwhen a remote-family table function with aview(...)argument is used on the left side of aJOIN ... USINGwhose key is aSELECTlist alias, withanalyzer_compatibility_join_using_top_level_identifier = 1. #113400 (Groene AI). - Fixed reading
Paimontables partitioned by aTIMESTAMPcolumn with a precision higher than milliseconds, which failed withscale 6 is not supported, only support scale <= 3. Closes #112768. #113401 (JIaQi Tang). - Fixes a segfault and a
LOGICAL_ERROR(No host found for exchange stream final_result__0_0) when a subquery setsdistributed_plan_execute_locallyin its ownSETTINGSclause undermake_distributed_plan. The distributed plan and the code executing it read the setting from two different contexts and could disagree, so the initiator built a self-contradictory pipeline. #113422 (Groene AI). - Fixed reading Paimon tables that contain a nullable
ARRAYorMAPcolumn. Such a table could not be read at all, because the schema mapper wrapped the composite type inNullable, which ClickHouse forbids, so bothDESCandSELECTfailed withNested type Array(Nullable(Int32)) cannot be inside Nullable type. A nullable composite column is now mapped to a non-Nullablecomposite type and aNULLvalue is read as an empty one. Closes #113337. #113450 (Groene AI). - Fix part and granule pruning for a
JOIN ONcondition involving constant columns of the other side. #113484 (Vladimir Cherkasov). - Stopped writing a part whose
Maplayout contradicts its own metadata, for aMapvalue inside aDynamiccolumn. Tables differing only inmap_serialization_versionshared one cached serialization object, so a part could get thebasicMap layout while its metadata declaredwith_buckets, and reading it later failed withLOGICAL_ERROR: Stream ...buckets_info ... is not found. Parts an earlier version already wrote this way stay unreadable and have to be dropped. #113514 (Groene AI). - Fixed the inferred column type depending on the order of previous queries for a source whose schema is cached. Settings that change an inferred type were missing from the schema inference cache key, so the first query’s value decided the type every later query saw:
input_format_try_infer_exponent_floats,max_parser_depth,input_format_json_infer_array_of_dynamic_from_array_of_different_types, and forParquetalsoinput_format_parquet_local_time_as_utc,input_format_parquet_allow_geoparquet_parser,input_format_parquet_skip_columns_with_unsupported_types_in_schema_inferenceandschema_inference_make_json_columns_nullable. Also registers the missing cache key getter forFormand makes theTemplategetter use its own row format’s escaping rule. #113533 (Groene AI). - Fix a theoretical data race in profile events when using the
trace_profile_events_listsetting to write stack traces of certain profile events tosystem.trace_log. #113553 (Miсhael Stetsyuk). - Fixed
RENAME DATABASEaccepting a target name long enough to make the database’s tables impossible to drop. The table name length check now runs regardless ofcheck_table_dependencies, and it also covers detached tables, which were never checked and so were affected even at default settings. Closes #101747. #113557 (Groene AI). - Fixed the
LOGICAL_ERRORReading from materialized CTE '...' before its materialization completed - DelayedPortsProcessor gate is missing in the query planraised when aMergetable with more than one child reads a materialized CTE that the outer query references. #113558 (Alexey Milovidov). - Fixed a row policy containing a scalar subquery being evaluated only once and then reused forever after the table had been read through a
Mergetable. The parsed policy condition is cached and shared by all queries, and reading it throughMergerewrote the cached expression in place, which also caused a data race between concurrent queries using the same policy. #113563 (Alexey Milovidov). - Fixed
Unsupported JOIN keys of type keys256 in StorageJoinwhen reading aJoin-engine table whose key is composite (several columns) or a single 16/32-byte value such asUUID,Int256orFixedString(4). Such a table could be created, written and joined against, but never read back withSELECT. Closes #74362 and #77394. #113578 (Groene AI). - In the Web UI, opening a link with
run=1no longer makes other tabs’ URLs auto-run their queries on the next page reload. #113595 (Alexey Milovidov). - Fix a logical error comparing arrays whose element type is Nothing. #113609 (Groene AI).
- Backups now report the underlying lock-file access error instead of incorrectly reporting a concurrent backup when the destination storage cannot read the .lock file. #113637 (Kirill Shokhin).
- Fix a logical error
Sending a distributed query with unknown (zero) client versionwhen a structure-lessDistributedtable over a remote shard is attached or loaded from metadata written by an older server version. #113675 (Alexey Milovidov). - Treat a NUL byte as an ordinary literal in match() patterns. #113690 (Vitaly Baranov).
- Fix
theilsUover a window frame returning an arbitrary value instead of 0 when the first argument is constant within the frame. #113691 (Alexey Milovidov). - Fix
Logical error: Duplicate announcement received for replica number Nwhen automatic parallel replicas (automatic_parallel_replicas_mode) adopts a plan whose single-node variant was sharded byquery_plan_join_shard_by_pk_ranges. #113730 (Alexey Milovidov). - Fix
CANNOT_CONVERT_TYPEand an exception inGroupingAggregatedTransformwhen reading aMergetable with one child being aDistributedtable under custom-key parallel replicas (parallel_replicas_mode = 'custom_key_sampling'or'custom_key_range'). Closes #113741. #113742 (Alexey Milovidov). - Fixed a
LOGICAL_ERRORwhen aSELECTused theSTREAMmodifier on a named table together with parallel replicas in the read-tasks mode. With a materialized CTE used as anINset inPREWHERE, the server raisedReading from materialized CTE ... DelayedPortsProcessor gate is missing in the query plan(a server abort in debug and sanitizer builds). A table carryingSTREAMis now rejected when parallel replicas are requested: atenable_parallel_replicas = 2the query fails withSUPPORT_IS_DISABLED, at1it runs without them, exactly as already happens forFINAL. #113754 (Groene AI). - Fixed a server crash when joining with a constant
ONexpression against a right side that contains anARRAY JOIN. Reading a lazily replicated right-side column used a freedColumnReplicated. Closes #113859. #113901 (Groene AI). - Fix undefined behavior and wrong results in
avgoverDate/DateTime/DateTime64/Time/Time64: the average is now computed exactly in integer space, fixing both theInt64-boundary overflow (UB, wrong result on x86) andFloat64precision loss above 2^53 (visible at nanosecond scale). #113912 (Alexey Milovidov). - Fix wrong results in
JOINwithjoin_algorithm = 'partial_merge'when the right side carries totals: the right side could be left unmerged, soLEFTjoins substituted default values for real matches andINNER/RIGHTjoins returned no rows at all. In theRIGHT/FULLnon-joined path the same state dereferenced a null pointer, which crashed the server. #113936 (Groene AI). - Fixed a defect in the
MySQLintegrations where overriding a TLS credential of a named collection with an emptyssl_ca_pem/ssl_cert_pem/ssl_key_pemvalue was accepted when the collection stored the credential in the contents form, silently dropping the configured CA or client certificate instead of rejecting the override. #113947 (Alexey Milovidov). - Fixes a
std::out_of_rangeexception (Logical error: 'std::exception. Code: 1001, type: std::out_of_range', which also aborts the server in debug and sanitizer builds) in the Parquet v3 reader when a column needed only for filter evaluation was scheduled for decoding after its output slot had already been dropped. #113956 (Groene AI). - Fix a logical error (
Unexpected return type) when a filter over a view whose column type differs from the underlying storage (e.g.information_schema.tables, whereengineisNullable(String), oversystem.tables, where it isString) is pushed down to the storage. #113984 (Alexey Milovidov). - Fix ClickHouse Keeper refusing to start with
CORRUPTED_DATAafter a crash during cross-segment Raft log truncation (writeAt), which could leave an acknowledged log entry stranded behind stale changelog segments. #114003 (Nishant Agarwal). - A table or database whose name is substituted into a
ReplicatedMergeTreeZooKeeper path through the{database}or{table}macro is now rejected if the name would not be a single safe path component. Previously a name containing/was spliced in unescaped, so the table registered its znodes inside another table’s keeper subtree and permanently brokeALTERandOPTIMIZEthere. A.or..component, a control character and macro syntax are rejected too. Existing tables keep loading and attaching. #114006 (Groene AI). - Fixes a memory leak with
optimize_aggregation_in_order = 1when the table sorting key is a strict prefix of theGROUP BYkey and an aggregate function whose state owns heap memory is used, such asquantileDD. Server memory grows with every such query until restart. #114010 (Groene AI). - Fixes a logical error when a distributed query plan contains a window function producing an aggregate function state, for example
theilsUState(a, b) OVER (ORDER BY a)withmake_distributed_plan = 1. Affects thecramersV,cramersVBiasCorrected,theilsUandcontingencyfamilies. #114020 (Groene AI). - Fix wrong results for
SELECT DISTINCTwith aLIMITthat has to read its whole input:LIMIT n WITH TIESdropped tying rows,exact_rows_before_limit = 1reported a truncatedrows_before_limit_at_least, andGROUP BY ... WITH TOTALScomputed the totals row from a prefix of the stream. #114025 (Groene AI). - Fixed
isProbablePrimeonUInt128/UInt256ignoringmax_execution_timeandKILL QUERY. A block of wide values ran to completion inside a single function call with no cancellation point, so a query could run for minutes past its deadline. #114032 (Groene AI). - Fixes a missing
system.query_views_logrow for a materialized view that fails while its dependencies are being collected withmaterialized_views_ignore_errorsenabled. In debug and sanitizer builds this also aborts the server withstd::out_of_rangeinstead of logging the view. #114064 (Groene AI). - Fixed
Code: 46. DB::Exception: Unknown function exists. (UNKNOWN_FUNCTION)thrown when aPREWHEREclause contains anIN (subquery)predicate andrewrite_in_to_join = 1(ormake_distributed_plan = 1, which force-enables it) is set. The same query spelled withWHEREworked correctly. #114067 (RohithPariki). - Fixed
ORDER BY ... LIMITreturning fewer rows than requested, possibly none, when a row policy was the only filter of the query and the sort column had aminmaxskip index. The top-K optimization narrowed the read before the row policy was applied. #114073 (Alexey Milovidov). - Fixes
hasAny,hasAll,has,indexOf,mapContainsKey,mapContainsValueandmapContainsreturning too few rows, or failing withTOO_LARGE_STRING_SIZE, when abloom_filterindex is queried with aFixedStringconstant. The index hashed the padded form of the constant while the function compares the unpadded one, so a matching granule was skipped. #114089 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR“Not-ready Set is passed as the second argument for functionglobalNullIn” and the loss of the query’s real error message, which could happen when statistics part pruning speculatively executed anIN/GLOBAL INsubquery during index analysis and that subquery failed. #114121 (Groene AI). - Respect the
allow_calculating_subcolumns_sizes_for_merge_tree_readingsetting in the PREWHERE optimization. #114146 (Pavel Kruglov). - Reject corrupted/malicious dictionary where
lcpexceeds the previous token orlcp + data_sizeoverflows, before the buffer write. #114155 (Elmi Ahmadov). - Fix
minandmaxonDateTime64columns returning wrong results once the aggregate is JIT compiled and the data contains timestamps before 1970.is_signedwas not specialised forDateTime64andTime64, which derive fromDecimal64, so the generated code compared tick counts as unsigned integers and a pre-1970 timestamp wonmaxand lostmin. #114168 (Groene AI). - Fixed an exception when reading a
MergeTreetable by primary-key range layers when a layer produces an empty pipe. #114177 (Alexey Milovidov). - Fixed the error code reported for some malformed
Replicated-serialized columns received over the Native protocol: these are now rejected withINCORRECT_DATAinstead ofLOGICAL_ERROR(which aborted the server in debug and sanitizer builds). #114186 (Pavel Kruglov). - Fixed
ATTACH PARTITION FROM,REPLACE PARTITION,MOVE PARTITION TO TABLEand adding aReplicatedMergeTreereplica failing withTables have different ...,METADATA_MISMATCHorINCOMPATIBLE_COLUMNSfor tables whose definitions were written with redundant parentheses, such asPARTITION BY (a),ORDER BY (b),INDEX ix (b * c) TYPE minmax,PROJECTION p (SELECT (b) ...),CONSTRAINT c CHECK (a > 0),TTL (d + INTERVAL 10 YEAR)orDEFAULT (a + 1). #114188 (Alexey Milovidov). - Fixed
ALP,FPCandGCDomitting their type-derived parameter from the codec hash. In a Compact part the writer shares one compressed stream per distinct codec hash, so two columns of different value width under the same codec collided and shared one codec object carrying the wrong width. This rejected valid inserts withCANNOT_COMPRESSwhen the widths disagreed, and otherwise compressed one of the columns worse than it should have. #114189 (Groene AI). - Fix
std::out_of_range: map::at: key not foundwhen aMergeTreekey expression contains amortonEncodeorhilbertEncodecall that is not itself a key column, for exampleORDER BY mortonEncode(hilbertEncode(x, y), x, y)orPARTITION BY mortonEncode(x, y) % 4. #114233 (Groene AI). - Clear plain LIMIT/OFFSET in the window-view backfill source query. #114247 (Alexey Milovidov).
- Fixed a
LOGICAL_ERRORinarrayAutocorrelationwhen the argument is a non-empty array whose element type isNothing, for exampleSELECT arrayAutocorrelation([arrayMax([])]). Such an argument is now rejected withILLEGAL_COLUMN. The empty array literal[]keeps returning[]. #114249 (Groene AI). - Fix a Keeper server never joining the cluster when
nuraft_use_bg_thread_for_snapshot_iois enabled: the log batch sent to a joining server was silently dropped, so the membership change never completed. #114275 (Shaohua Wang). - Fix
XDG_CACHE_HOMEbeing read fromXDG_STATE_HOME. #114278 (Alexey Milovidov). - Register Iceberg namespace in the catalog before writing table files (needed for SeaweedFS). #114285 (Azat Khuzhin).
- Fix inconsistent results when a filter on a non-key column of the right table was pushed down below an ANY INNER JOIN. #114313 (Kirill Shokhin).
- Fix bash completion with bash-completion 2.12+ (_comp_get_words). #114339 (Azat Khuzhin).
- Fixes a crash when reading a data lake table whose schema declares a column with an empty name. Malformed Iceberg metadata is rejected with
ICEBERG_SPECIFICATION_VIOLATION; a schema supplied by a catalog, Delta Lake or Paimon is rejected withAMBIGUOUS_COLUMN_NAME. The check is unconditional, so an Iceberg table that merely retains an unused historical schema with an empty field name also becomes unreadable instead of aborting once that schema is read. #114394 (Groene AI). - Fixes a bug where a client connecting to ClickHouse Keeper during a Raft leader change could be held for the whole
session_timeout_ms(30 seconds by default) before its connection was rejected, instead of being rejected as soon as the in-flight request was dropped. The connecting client can now reconnect to another replica sooner. #114401 (Groene AI). BACKUP,RESTOREandENGINE = Backupnow authorize the backup location against the user’sSOURCESgrants, the same ways3(),file()andazureBlobStorage()do. Previously a user holdingBACKUPbut notSOURCEScould write a backup to, and read one from, any location the server could reach. Writing a backup now requires theWRITEdirection on the destination’s source (WRITE ON S3,WRITE ON AZURE,WRITE ON FILE) and reading one requiresREAD;Disk(...)destinations stay restricted bybackups.allowed_diskonly. #114405 (Groene AI).- Fixes
CREATE OR REPLACEleaking an internal_tmp_replace_*table, andCREATE OR REPLACE VIEWfailing withNOT_IMPLEMENTED, whenignore_drop_queries_probabilityis set. The DROPs it issues internally are steps of one user statement, so DROP fault injection no longer applies to them. #114420 (Groene AI). - Fixed a
LOGICAL_ERROR(Bad cast from type DB::ASTLiteral to DB::ASTPartition) and unparseable formatted SQL when anALTER TABLE ... MOVEcommand deserialized from a JSON AST (dialect = clickhouse_json) paired thePARTform withTO TABLE, or thePARTITIONform withTO SHARD. Such payloads are now rejected withBAD_ARGUMENTS. #114429 (Groene AI). - Do not remove columns when it’s referenced in both
PREWHEREandWHEREfilter conditions even if it’s rewritten into a text index virtual column. #114460 (Elmi Ahmadov). - Fixed a
Not-ready Set is passed as the second argument for function 'in'error when a mutation whose predicate containsIN (subquery)is cancelled, for example byKILL MUTATIONorDETACH DATABASE, while the subquery’s set is still being built. Related: #107619. #114463 (Groene AI). ALTER TABLE ... DROP COLUMNof a column that is used in the sorting, primary or partition key now fails withALTER_OF_COLUMN_IS_FORBIDDENand an explanation, the same asALTER TABLE ... CLEAR COLUMNdoes. Previously it failed with a confusingUNKNOWN_IDENTIFIER: Missing columnserror coming from the recalculation of the key expressions. The same applies to dropping or clearing a wholeNestedgroup by its common prefix when a column of the group is used in a key; previously that could silently destroy the group’s data or leave a mutation that never finishes. Dropping a column that is used only in aTTLexpression now also reports which TTL expression it breaks. #114468 (Maksim Dergousov).- Fixed reading a
Tuplecolumn whose first element isNULLin theCustomSeparated,RegexpandTemplateformats with theCSVescaping rule. A bareTupleoccupies one field per element there, so the leading\Nfield is that element and not the whole column. Previously it was consumed as the whole column, shifting the remaining element fields onto the following columns, soCustomSeparatedcould not read back its own output. Closes #114402. #114471 (Groene AI). - Fixes
arrayExists(x -> x = needle, arr)returning a wrong result, or failing withTOO_LARGE_STRING_SIZE, when the array element and the needle are different string types (for example aStringneedle against anArray(FixedString(N))element). Theoptimize_rewrite_array_exists_to_hasoptimization, enabled by default, rewrote such a call tohas, which does not compare zero-padded the way=does. #114496 (Groene AI). - Reading an Iceberg table whose metadata describes a schema evolution that the Iceberg specification forbids no longer aborts the server. Four spec violations in
IcebergSchemaProcessorwere reported asLOGICAL_ERROR, which is treated as a failed assertion, or reached a fatal assertion unchecked; they now raiseICEBERG_SPECIFICATION_VIOLATION. #114518 (Groene AI). - Fixed the
Regexpinput format silently discarding the unparsed rest of a matched field, which stored a truncated or fabricated value instead of reporting an error:v=-1intoUInt64read0, andv=2020-01-01junkintoDateread1975-07-14under theJSONrule. Malformed fields are now rejected under theEscaped,CSVandJSONrules, matching the formats those rules are documented as behaving like. UnderRaw, a matched field containing a tab is now read as a whole instead of being truncated at the tab. #114520 (Groene AI). - Fix
LOGICAL_ERRORwhen filtering an Iceberg column thatALTER TABLE ... MODIFY COLUMNmadeNullable. Closes #85029. #114521 (Groene AI). CREATE TABLEandALTER TABLEnow reject lossy codec such asSZ3on a column used in the sorting key. #114531 (Groene AI).- Fixed a
LOGICAL_ERRORwhen reading a Delta Lake table whosemetaData.partitionColumnsnames a column thatmetaData.schemaStringdoes not declare. Such metadata is now rejected withBAD_ARGUMENTSon the delta-kernel reader andINCORRECT_DATAon the legacy reader, whenever the table or its schema is read from a snapshot, not only when the query carries a predicate. #114538 (Groene AI). - Reject a Variant whose ORC branches read back as one type. #114540 (Groene AI).
- Fix text index evaluation of
LIKE/ILIKEoperator built on Map or JSON containers. #114544 (Elmi Ahmadov). - Support quoted label names in PromQL grouping modifiers.. #114545 (Minh Vu).
- Fixes incorrect, often sign-flipped,
Time64literals andIN-list constants produced when rescaling a lower-scaleDecimal64overflowedInt64. Such a conversion now reportsDECIMAL_OVERFLOW, matching theDateTime64branch and explicitCAST. #114546 (Groene AI). - Accept trailing commas in PromQL grouping label lists.. #114548 (Minh Vu).
- Support quoted metric and label names in PromQL selectors. #114551 (Minh Vu).
- A query could be cancelled up to 1 ms before its
max_execution_timehad passed, failing with a self-contradictoryTimeout exceeded: elapsed 999.672 ms, maximum: 1000 ms. #114559 (Alexey Milovidov). - Fixed reading a table while a mutation is in progress: a
MATERIALIZEDcolumn could return a stale value, and selecting one together with an updated column could fail with an error. #114561 (Shaohua Wang). - Fixes
clickhouse-localaccepting aCREATE TABLEwhose name is too long for the configured--default_database, which produced a table that could not be dropped.DatabaseOverlaynow checks the table name length like the on-disk database it writes to. #114567 (Groene AI). - Fixed an RBAC bypass in the
Aliastable engine that allowed users without privileges on the target table to reveal its schema, row count, size, and existence. #114596 (Kai Zhu). - Fixed hash-table statistics — and with them aggregation hash-table preallocation — being silently and permanently disabled for the whole server when a query using the lazy
FINALoptimization (query_plan_optimize_lazy_final) was the first aggregation to run after server startup. #114597 (Alexey Milovidov). - Fixed a column that was renamed, dropped and added again in one
ALTERreturning the dropped column’s values instead of its own default while the mutation was still pending. #114601 (Shaohua Wang). - Fixed an infinite, uncancellable loop in functions
hopandwindowIDwhen the span of an interval argument in seconds is a multiple of 2^32 (for example,toIntervalDay(2147483648)): the wrapped subtraction dodged the time-overflow check, and with constant arguments the loop ran at analysis time, where the query could not even be killed. The same interval could also spin a background thread of aWINDOW VIEWforever; such a window view is now rejected at creation. #114607 (Alexey Milovidov). - Fixes a bug where an access entity carrying a
Map-valued setting, such as a settings profile withhttp_response_headersoradditional_table_filters, is stored in a form that ClickHouse cannot read back, leaving the entity permanently unloadable after a restart. #114620 (Groene AI). - Fixed a refreshable materialized view leaking its rotated-out target table when
ignore_drop_queries_probabilityis enabled. TheDROPa refresh issues to clean up the previous target is a step of the refresh, not aDROPthe user asked for, so the fault injection no longer applies to it. #114622 (Groene AI). - Fixes
has,indexOf,countEqual,mapContainsKey,mapContainsValueandMapsubscript returning “not found” for a constantLowCardinalityneedle equal to the element type’s default value, such as an emptyStringor a zero number. #114624 (Groene AI). - Fixed logical error
Multi-block postings must be compressedin queries over tables with a text index in the lazy posting-list apply mode, when the query was canceled during the read. #114636 (Anton Popov). - Fixed formatting of a subquery argument of the
viewandviewIfPermittedtable functions when the enclosing query has a trailingSETTINGSclause. Such a query was formatted asview((SELECT ...)), which cannot be parsed back, so the query failed the internal format-parse-format check and raisedInconsistent AST formatting. #114658 (Groene AI). - Fixed heap memory corruption when reading Parquet through an input format that owns its read buffer, for example a dictionary with
SOURCE(FILE(... format 'Parquet')). Background prefetch and decode tasks could still read and write through the buffer after the pipeline released it, which could abort the server. #114668 (Groene AI). - Fix reading a subcolumn (
.size0,.null, a tuple element,String.size) through aMergetable when the underlying table declares the parent column asALIAS. Such a read returned the type default, and when the parent was selected in the same query it could return the value of an unrelated column. #114673 (Groene AI). - Fix
ANY RIGHT JOINandSEMI RIGHT JOINwith severalOR-ed conditions in theONsection returning some rows of the right table twice and losing the matches of others. A writtenANY LEFT JOINwas affected too, because the planner may swap the tables and execute it asANY RIGHT JOIN. #114676 (Vladimir Cherkasov). - Fixed wrong results of the trivial
GROUP BY ... LIMIToptimization (settingoptimize_trivial_group_by_limit_query) for queries withDISTINCT,QUALIFY, window functions, orarrayJoinin the projection: these consume or filter the groups after the aggregation, so capping the aggregation atLIMIT + OFFSETkeys could return too few rows or wrong values. The optimization no longer applies to such queries. #114695 (Alexey Milovidov). - Fixed rows missing from the result of a
SELECTfiltered bypointInPolygonover a MergeTree primary key when the polygon argument is an invalid constant literal andvalidate_polygons = 0. Primary key analysis derived granule pruning from a polygon it never validated, and dropped granules holding matching rows. #114710 (Groene AI). - Fixes a server crash that happens when aggregate states of the
-OrNullor-OrDefaultcombinators are merged withgroup_by_overflow_mode = 'any'and a non-zeromax_rows_to_group_by, for example when a query reads through an aggregate projection. #114740 (Groene AI). - Fixed a
LOGICAL_ERROR(“Unexpected number of kept output positions after removing unused columns fromReadFromMergeTree”) raised by aSELECT ... FINALwhosePREWHEREuses a column thatFINALneeds for merging (ver,is_deleted,sign) and which does not select that column. #114746 (Groene AI). - Fix a logical error (
Block structure mismatch) when reading aMergetable withmake_distributed_planenabled over children with internal set operations. #114753 (Alexey Milovidov). - Reject an absurdly large
kafka_num_consumerswith a clear error instead of failing an allocation inside theKafkatable engine. Previously, withkafka_disable_num_consumers_limitenabled, such a value produced astd::length_errorexception. #114764 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR: Context has expiredexception when a stored expression containingaccurateCastOrDefaultor ato<Type>OrDefaultfunction is evaluated after the query that created it has finished, for example aMATERIALIZEDcolumn default onINSERTor a mutation expression. #114769 (Groene AI). - Fixes a
LOGICAL_ERROR(Cannot find input column ... on its position in inputs of expression actions DAG) when a query has aJOINabove a table whose text-indexed column is used by both aPREWHEREand aWHEREtext-search predicate. #114771 (Groene AI). - Fix lost wakeup of restarting thread on startup from the attach thread. #114802 (Azat Khuzhin).
OPTIMIZE TABLEon an object-storage table whose engine does not implement compaction reported success while doing nothing. It now raises an error, like every other engine that does not support the statement. This affectsDeltaLake,Paimon,Hudiand plain object-storage engines (S3,GCS,COSN,OSS,AzureBlobStorage,HDFS, and object-storage-backedURL);Iceberg, which does implement compaction, is unchanged. Closes #114765. #114805 (Groene AI).timeSeriesRangeandtimeSeriesFromGridthrew a falseDECIMAL_OVERFLOWfor timestamps before 1970 because the start/end timestamps were read as unsigned values. Also, forDateTime/UInt32timestamps the step was silently truncated to its lower 32 bits. Now all the calculations are done inInt64. #114815 (Vitaly Baranov).- Fixes a server abort (
Logical error: Part patch-... doesn't exist) when aDROP TABLEruns concurrently with a lightweightUPDATEon aReplicatedMergeTreetable. The update now holds the table’s shared lock until its patch part is committed, so theDROPwaits instead of removing it. #114826 (Groene AI). - Fix few bugs in async inserts (possible crash in case of some queries failed with
MEMORY_LIMIT_EXCEEDEDand never workedasync_insert_queue_flush_on_shutdown). #114839 (Azat Khuzhin). - Fixed
LOGICAL_ERROR: Unexpected return type from tuple. Expected Tuple(..., UInt8). Got Tuple(..., LowCardinality(UInt8))when aLowCardinalitycolumn compared withIN (subquery)is read throughtuple(...)across a subquery boundary andenable_analyzer = 0. With the old analyzer,x IN (subquery)over aLowCardinalitycolumn now returnsLowCardinality(UInt8), the same type asx IN (literal list)and the same as withenable_analyzer = 1. #114856 (Nikita Fomichev). - The AI-function quota settings (
ai_function_max_api_calls_per_query,ai_function_max_input_tokens_per_query,ai_function_max_output_tokens_per_query) were enforced per block rather than per query, letting a query exceed the configured limit in proportion to the number of blocks and threads processed. They now bound the whole query per server: the API-call limit is an exact cap (atomic reservation), and the token limits are best-effort. A distributed query enforces the limits independently on each participating server / fragment. #114885 (George Larionov). - Fixes a server abort that happens when the global thread pool is momentarily saturated while tables are still loading.
AsyncLoadernow keeps running if it cannot spawn an extra loader worker and some worker will still drain the queued jobs, instead of callingstd::terminate. #114897 (Groene AI). - Fixed undefined behavior and incorrect boundary results in
quantileandquantilesforDateTime64and wideDecimalvalues. #114919 (Alexey Milovidov). - Fix server abort on a corrupt ORC stripe footer. #114924 (Groene AI).
- Fix possible crash due to ThreadGroup use-after-free (for async INSERTs/MVs/EXPLAIN ANALYZE). #114940 (Azat Khuzhin).
- Fixed a hang when dropping a
TimeSeriestable whose name sorts lexicographically below its inner tables’ names, for exampleDROP TABLE `-ts`or dropping a materialized view declared withENGINE = TimeSeries. The drop self-deadlocked on the DDL guard and could not be cancelled withKILL QUERY. #114953 (Groene AI). - Fix
BAD_DATA_PART_NAME(“Trying to get part name in new format for old format version”) on aReplicatedMergeTreecreated with the deprecated positional syntax underallow_deprecated_syntax_for_merge_tree. A mutation could be reported as done on a replica that had not applied it, and the table could stay readonly after a restart. #114980 (Groene AI). - Fix the logical error
Not-ready Set is passed as the second argument for function 'in'for a query with anINsubquery reading from a remote cluster: the query now fails with the actual error from the subquery, such as a connection failure. #114983 (Alexey Milovidov). - Fix logical error for IN with an identical non-constant tuple on both sides in the old analyzer. #114988 (Groene AI).
- Fix reading a tuple element through a positional Tuple structure hint. #115000 (Groene AI).
- Do not alias pre-aggregation states of a zero-size aggregate in arrayReduceInRanges. #115008 (Groene AI).
- Fixed an
INSERTinto aLog,TinyLogorStripeLogtable that fails while committing the recorded file sizes. Such an insert could keep its rows in the table even though it reported an error, or leave the data files of an array column inconsistent with each other. Reading aLogorTinyLogtable whose array column holds no elements while its offsets claim some now raises an error naming the column instead of reading past the end of the elements. A partially written elements column was already rejected. #115027 (Groene AI). - Fix an adaptive aggregator abort on lazily replicated columns. #115034 (Groene AI).
- Fixed an out-of-bounds read in
pointInPolygonwith a constant polygon whose bounding box is unbounded, for example when a coordinate reaches+-DBL_MAX. Such a polygon is now rejected withBAD_ARGUMENTS, and a polygon with an empty ring is treated as having no interior. Previously the query could return a wrong result, or abort the server in builds with hardening or sanitizers enabled. #115035 (Groene AI). - Fixed an
out_of_rangeexception raised as an internalCode: 1001error when asequenceMatch,sequenceCountorsequenceMatchEventspattern contains the event number0, for examplesequenceMatch('(?0)'). Such a pattern is now rejected withBAD_ARGUMENTS. A temporal condition holding a lone sign, such assequenceMatch('(?1)(?t>+)(?2)'), was silently treated as(?t>0)and is now rejected withSYNTAX_ERROR. #115056 (Groene AI). - Fixed
Found patch part ... that intersects mutation with version ...(LOGICAL_ERROR) on tables with lightweight updates. A merge of patch parts could produce a patch whose range of data versions spans the data version of an existing part; that patch can then be neither applied nor skipped, so every later operation on the partition failed and the replication queue stalled. Such merges are no longer assigned. #115064 (Alexey Milovidov). - Fixes a
LOGICAL_ERROR(Cache file segment is in detached state) when reading through the filesystem cache with the experimentaluse_reader_executorsetting. The regression was introduced by #110029 and is not in any release, so no backport is owed. #115070 (Groene AI). - Arrow Flight server: accept
Basicauthentication credentials encoded in Base64 without padding, as sent by Go-based Flight clients such as the ADBC Flight SQL driver, and return a proper authentication error instead of a genericUnexpected error in RPC handlingwhen theauthorizationheader is malformed. #115085 (Alexey Milovidov). - Fix autocompletion (hints and TAB completion from
system.completions) in the embedded client used by the SSH interface and the Web terminal: suggestions were loaded through a separate connection that authenticated as thedefaultuser with an empty password, which failed on servers wheredefaulthas a password, and otherwise leaked names of entities the logged-in user has no access to. Suggestions are now loaded through the session’s own connection. #115086 (Alexey Milovidov). - Fixed a server that refuses to start after a table was created with
CREATE TABLE ... AS url('http://host/**/', ...)whileallow_experimental_url_wildcard_from_index_pageswas enabled. Loading such a table’s metadata re-evaluated the experimental check and failed withSUPPORT_IS_DISABLED, aborting startup. #115095 (Groene AI). - Rewrite bucketIndexForTimestamp in 64-bit arithmetic. #115097 (Vitaly Baranov).
- Fixed the formatting of
ALTER TABLE ... MATERIALIZE INDEX,MATERIALIZE STATISTICSandMATERIALIZE PROJECTION, which dropped theIF EXISTSclause, so the formatted query was not the query that was parsed. Also rejected fourALTER ... STATISTICSAST JSON payloads that the SQL parser cannot produce and that formatted into a different command. #115099 (Groene AI). - Fixed an exception (
Block structure mismatch in Expression for FilterSortedStreamByRange) for someSELECT ... FINALqueries withPREWHEREover a table whose sorting key is an expression. #115113 (Shaohua Wang). - Fix clickhouse-local CORS CLI overrides. #115129 (Alexey Milovidov).
- Disable distributed index analysis with projections (wrong results). #115132 (Azat Khuzhin).
- Fixed
ifandmultiIfreturning a large positive value instead of a negative one when aTimebranch is combined withTime64,DateTimeorDateTime64and the expression is JIT-compiled. #115146 (Groene AI). - A web terminal embedded in another page, such as the SQL console or
play.html, receives its credentials from that page and no longer opens a connection of its own before they arrive. Previously it connected twice - once with an empty password, then again with the real credentials - and printedConnecting...twice. #115148 (Alexey Milovidov). - Fixed wrong results when a
WHEREclause contained aNULLexpression under aNOT, for exampleSELECT count() FROM t WHERE NOT (id >= 20 AND NULL). Index analysis treated such a condition as provably true for the whole range, so the filter was skipped:count()returned rows the query rejects, andALTER TABLE ... DELETEwith that condition removed rows it should have kept. #115152 (Groene AI). - Fixed
EXPLAIN ANALYZElosing the join statistics of a view declaredSQL SECURITY DEFINERorSQL SECURITY NONEwhose body contains a JOIN. In debug and sanitizer builds the query aborted with the logical errorJoinStep analyzed without the analyze mode. #115156 (Groene AI). - Fixed an out-of-bounds read while deserializing corrupted posting lists of a text index. #115222 (Anton Popov).
- Fixed wrong results for
SELECT count(arrayJoin(arr))with the defaultoptimize_trivial_count_query = 1. The stored row count was returned instead of the number of array elements, and onfile()andurl()the query returned0. Closes #115123. #115227 (Groene AI). - Fixes
NOT_FOUND_COLUMN_IN_BLOCKon everyINSERTinto a table that declaresSTATISTICS(...)on anALIASorEPHEMERALcolumn, which made such tables read-only. #115231 (Groene AI). - Fix the final statistics of a finished query (
N rows in result,Read ... rows) being rendered in an invisible color in the Web UI. #115245 (Alexey Milovidov). - Fixed silently incorrect results and undefined behavior when reading a malformed
AggregateFunction(uniq, ...)state. Theskip_degreefield of the serialized state was used as a shift exponent without validation, so an out-of-range value produced an arbitrary cardinality instead of an error. Such states are now rejected withINCORRECT_DATA. #115276 (Groene AI). - Fixed a row policy bypass where the mergeTreeIndex table function exposed primary key and minmax index values of the rows hidden by a SELECT row policy on the source table; reading mergeTreeIndex for a table with a row policy is now denied. #115304 (Yarik Briukhovetskyi).
- Fixed
CREATE QUOTAandALTER QUOTAsilently discarding all but the lastFOR INTERVALblock when the separating comma between intervals was omitted. Such a statement succeeded while installing none of the earlier limits. The intervals now accumulate again, as they did before 2020. Closes #115282. #115320 (Groene AI). - Fixed wrong results from
if,multiIfandCASEwhen one branch is aDateorDate32and the result type isDateTimeorDateTime64. Withcompile_expressions = 1(the default) the compiled expression copied the date’s day count into the timestamp column without converting days to seconds, soif(cond, toDate32('1900-01-01'), toDateTime64('1970-01-01', 3))returned1969-12-31 23:59:34.433. Closes #115272. #115325 (Groene AI). - Do not leave metadata referencing a dropped named collection. #115326 (Groene AI).
- Fixed
timezoneOffset(aliastimeZoneOffset) returning an offset wrong by exactly one day for time zones whose UTC offset differs from their 1970-01-01 offset by a whole day, such asPacific/KiritimatiandPacific/Apiaafter they crossed the international date line, and for most zones before 1970. This also fixesparseDateTime,parseDateTimeOrNull,parseDateTime64,parseDateTimeInJodaSyntax,EXTRACT(TIMEZONE_HOUR / TIMEZONE_MINUTE ...),formatDateTime’s%z,toUTCTimestampandfromUTCTimestamp, which consume that offset. Closes #115281. #115332 (Groene AI). - Fixed a bypass of settings constraints:
SET <name> = DEFAULTreset a setting without checking the constraints from the user’s profile, so aMIN/MAX/CONSTconstraint could be escaped by resetting the setting instead of assigning to it, and a session could leave readonly mode withSET readonly = DEFAULT. #115334 (Alexey Milovidov). - Arrow Flight server: reject malformed Basic authentication credentials that omit the username/password separator. #115347 (Alexey Milovidov).
- Fixed a
LOGICAL_ERROR(Join is supported only for pipelines with one output port) for afull_sorting_mergeJOIN withquery_plan_join_shard_by_pk_rangesenabled when one of the two sides is pruned to no parts at all - by the primary key, by column statistics, or because the table is empty. #115352 (Alexey Milovidov). - Disable the query condition cache for filters over _part_starting_offset. #115358 (Azat Khuzhin).
- Fixed
randConstantreturning two different values in one query when its calls carry different aliases.randConstantis documented to hold a single value for the whole query, andSELECT randConstant() = randConstant()already returned1, but adding aliases as inSELECT randConstant() AS a, randConstant() AS bproduced two unrelated values. #115384 (Alexey Milovidov). - Fixed
uniq,uniqExact,uniqHLL12anduniqThetareturning a wrong result for an argument wrapped in an injective function that hides nullability, such asuniqExact(tuple(x))over aNullablecolumn. Theoptimize_injective_functions_inside_uniqoptimization removed the wrapping function, after which NULL rows were skipped instead of counted. #115466 (Vladimir Cherkasov). - Fix
GroupingAggregatedTransformproducing duplicate chunks for the same bucket. #115487 (Nikita Taranov). - Fixed the error message of
geoToH3naming the wrong argument position and the wrong type when a coordinate is notFloat64. Under the defaultgeotoh3_argument_order = 'lat_lon'the message pointed at the other argument and printed that argument’s type. Closes #101813. #115503 (Groene AI). - Reject a bare carriage return (
\r), in addition to a line feed (\n), in HTTP header names and values that pass through the HTTP header filter. This closes an HTTP header injection (request/response splitting) gap for features that pass user-provided headers, such as theurltable function and engine, HTTP dictionaries, and data lake catalogs. #115510 (Sergei Trifonov). - Fixed caches configured by a maximum number of entries (
SLRUpolicy) silently stopping to admit new entries once that many entries had been accessed at least twice. Affected caches include the Iceberg and Paimon metadata file caches, the Parquet metadata cache, the text index caches, the vector similarity index cache, the compiled expression cache and the ObjectStorageQueue file status cache. #115517 (Groene AI). - Fixed a hang of up to one hour in
BACKUP/RESTORE ... TO S3, GCS disks and thes3table function when the named collection setshttp_client = 'gcp_oauth'and the Google OAuth2 token endpoint accepts the connection but never answers. The bearer token request no longer inherits the caller’s data transfer request timeout; its response wait is bounded at 10 seconds, matching the STSAssumeRolerequest cap. #115531 (Groene AI). - Fix
dictGetand its variations in distributed queries: an unqualified dictionary name is now bound to the current database of the initiator, instead of being resolved against the current database of each shard, where it either was not found or resolved to a different dictionary of the same name. #115541 (Alexey Milovidov). - Fix a race that could make a
STREAM BOUNDEDquery return fewer rows than were committed before it started, usually none. #115543 (Alexey Milovidov). - Fixed Keeper snapshots being written as empty files when
compress_snapshots_with_zstd_formatis disabled. The server loggedCreated persistent snapshotbut the snapshot file was 0 bytes, and the node then refused to start withCORRUPTED_DATA. Closes #115388. #115553 (Groene AI). - Fix
read_rows,read_bytes,written_rowsandwritten_bytesinsystem.query_thread_logreporting a thread lifetime running total instead of the values for the logged query. Rows of long-lived pooled threads, in particular the query’s initiatingHTTPHandlerthread, were affected. #115596 (Groene AI). - Fixed an out-of-bounds read of the cached dictionary hashes when aggregating or joining on a
LowCardinality(String)key whose dictionary grows while it is being aggregated, reachable fromTTL ... GROUP BY. It could yield a wrong hash, and a reported heap-buffer-overflow in sanitizer builds. #115604 (Groene AI). CREATE TABLEandALTER TABLEnow reject a lossy codec such asSZ3on a column used in the partition key. #115626 (Groene AI).- Fix invalid backslash escape characters in text, tokenbf_v1 and ngrambf_v1 indexes. #115634 (Elmi Ahmadov).
- Fixed
removePartAndCoveredPartswhen it is called for a part that is present in the active data part set. #115640 (Mikhail Artemenko). - Allow KeeperMap readers to accept shared metadata when equivalent primary keys differ only by redundant outer parentheses. #115642 (Sergey Kuznetsov).
- Fixed a bug where restoring a database or table under a new name dropped the table aliases from the bodies of stored views, so reading a restored view failed with
UNKNOWN_IDENTIFIER. Closes #115479. #115645 (Groene AI). - Fixed
Code: 349. Cannot convert NULL value to non-Nullable typewhen ahasornotHaspredicate carries a NULL array element and the primary key is aString,Array(String)orMap(String, String), and fixed wrong results when that element is aDynamicorVariantholding NULL. The NULL is now dropped from the set during key analysis, as it already was for other key types. #115647 (Groene AI). - Fixed a bug in the function
formatRowNoNewlinethat could produce incorrect results or a logical error when a row is formatted to an empty result. #115669 (Alexey Milovidov). - Reject zero and negative
stepvalues in one-point Prometheus range queries. #115679 (Minh Vu). - Reject PromQL timestamps and durations that exceed the Int64 range. #115682 (Minh Vu).
- Fix server crashes on deeply nested input in
readWKB,JSONMergePatch, the address parser of theurl/remote/cluster/mysql/postgresqltable functions, theCURSORclause parser and the CapnProto schema parser. Fix a crash in the parser of theEXECUTEstatement when an argument is not a literal. #115700 (Alexey Milovidov). - Do not return uninitialized memory in the result of a binary string literal whose length is not a multiple of eight, and from the LZ4 decompressor when a compressed block has no body. #115704 (Alexey Milovidov).
- Bound the size of the startup message of the PostgreSQL wire protocol, which is read before authentication. #115708 (Alexey Milovidov).
- Fix the
MULTIPLE_EXPRESSIONS_FOR_ALIASerror in queries where a column alias coincides with the alias of a table expression in theFROMsection (an analyzer regression in version 25.2). #115714 (Alexey Milovidov). - Fixed
clickhouse-localterminating the whole process when a connection handler of a listener started withSYSTEM START LISTENthrew, for example because a client sent a malformed packet or reset a keep-alive socket. Such a process now logs the error and keeps serving, likeclickhouse-serverdoes. #115715 (Groene AI). - Fix
LOGICAL_ERROR: No available columnswhen a query reads no columns from a table expression that has no columns at all, for exampleSELECT count() FROM loop(db, tbl)wheretblis anAliastable whose target was dropped, or a parameterized view. Such a query now fails withUNSUPPORTED_METHODinstead of aborting the server in debug and sanitizer builds. #115716 (Groene AI). - Fix
LOGICAL_ERROR“Reading from materialized CTE ‘X’ before its materialization completed - DelayedPortsProcessor gate is missing in the query plan” when aMATERIALIZEDCTE is read from inside anINsubquery over aDistributedtable. Closes #113184. #115740 (Groene AI). - Reject invalid names of projections and indexes. #115824 (Alexander Tokmakov).
- Reject PromQL vector matching modifiers when one operand is a scalar. #115828 (Minh Vu).
- Fixed
cast_keep_nullablenot preserving nullability when the target type isLowCardinality. Casting a NULL-capable value toLowCardinality(T)threwCANNOT_INSERT_NULL_IN_ORDINARY_COLUMNinstead of producingLowCardinality(Nullable(T)). Closes #103485. #115851 (Groene AI). - Add Objects’ paths to deduplication hashing, preventing incorrect deduplication. #115866 (Mikhail f. Shiryaev).
- Fix
TYPE_MISMATCH(“CAST AS Array can only be performed between same-dimensional array types”) for a query with a constant of typeArray(Map(...)), such ashas([map('k', 'v')], m), executed over aDistributedtable or with parallel replicas. #115883 (Alexey Milovidov). - Fix
Unknown identifierraised during query plan optimization undermake_distributed_plan = 1when a window query’s sort column passes through anExpressionstep that does not mention it. Closes #115737. #115890 (Groene AI). - Fixed
h3kRing,h3HexRing,h3Lineandh3ToChildrenignoringmax_execution_timeandKILL QUERYwhile expanding a block of rows. #115893 (Alexey Milovidov). - Reading through a
Mergetable that matches anAliastable whose target is a parameterized view no longer raisesLOGICAL_ERROR: Table has no columns.(which aborts the server in debug and sanitizer builds). Such a table now reportsSTORAGE_REQUIRES_PARAMETER, the same error the parameterized view itself reports. Any other matched table that cannot supply columns now reportsUNSUPPORTED_METHODinstead of an internal error. #115896 (Groene AI). - Fixed the on-the-fly preview of a pending mutation whose expression references
_sample_factor. Withapply_mutations_on_fly = 1and aSAMPLEclause, the expression was evaluated with the reading query’s sample factor instead of the value the background materialization persists, so previewed rows disagreed with the eventual materialized result, and a pendingALTER TABLE t DELETE WHERE _sample_factor > 1could make aSAMPLEread return no rows at all. The query’s own_sample_factorcolumn is unchanged. #115906 (Groene AI). - Fixed a case where
ATTACH TABLEcarrying anENGINE = URL(...)definition did not check theTABLE ENGINEgrant of the engine the URL scheme dispatches to. A user holding onlyTABLE ENGINE ON URLcould attach and then read aFile,S3,AzureBlobStorageorHDFSbacked table, whichCREATE TABLEcorrectly rejects. #115914 (Groene AI). - Do not let an unparsable KeeperMap metadata node stop the server from starting. #115941 (Groene AI).
- Fix a crash of the
showCertificatefunction on a server that obtains its TLS certificate with ACME (Let’s Encrypt). The function now reports the certificate that is actually served, also after a certificate reload. #115976 (Alexey Milovidov). - Fixes a server abort in debug and sanitizer builds when inserting into a materialized view whose
TOtarget is another materialized view. Such an insert already failed on released versions, with an uninformativeCode: 1001 STD_EXCEPTION; it now reportsNOT_IMPLEMENTEDnaming the offending view. #115985 (Groene AI). - Statistics files with format version
V3are now read instead of rejected withILLEGAL_STATISTICS. Such files were produced only by builds ofmasterfrom a narrow window, but parts containing them were completely unreadable, and on a readonly diskALTER TABLE ... MATERIALIZE STATISTICScannot regenerate them. #116030 (Alexey Milovidov). - Fixed
LOGICAL_ERROR: Index with name auto_minmax_index_<column> already existswhen a singleALTER TABLEstatement combinedRENAME COLUMNwith another command, such asMODIFY SETTING, on a table with implicit minmax indices (add_minmax_index_for_numeric_columnsand friends). Renaming a plain column also no longer leaves a followingDROP COLUMNfailing withUNKNOWN_IDENTIFIER, nor a followingADD COLUMNwithout its implicit index. #116063 (Groene AI). - Fix stateless workers crash with object storage. #116067 (Konstantin Vedernikov).
Build/Testing/Packaging Improvement
- Provide signed artifacts for macOS. #115169 (Konstantin Bogdanov).
- Fix building from source with clang 23. #112288 (Azat Khuzhin).
- Reduced the dependencies and the code size of the SQL parser, which can now be built on its own — see
utils/wasm-parserfor a standalone WebAssembly build of it. The tables of SQL keywords and access types are now built at compile time instead of on every server start. #112067 (Alexey Milovidov). - Building from source now fails during CMake generation instead of corrupting
StorageSystemLicenses.generated.cppwhen license generation fails. #111222 (Mikhail Artemenko). - Updated the bundled Apache Thrift library to version 0.24.0. #111278 (Groene AI).
- Add
libucontextfor musl builds, enabling theboost::contextucontextbackend used by sanitizer builds. #111437 (Konstantin Bogdanov). - Fix source-level portability issues when building with musl. #111631 (Konstantin Bogdanov).
- Editing
Core/ProtocolDefines.hno longer triggers a near-full rebuild when building from source: the include was removed fromBlockInfo.hand added only in the files that use its constants. #111650 (Alexander Gololobov). - Fix a startup abort in macOS debug builds by disabling memory-tracker debug checks for allocations made by system libraries. #112080 (Arsen Muk).
- Updated the bundled
libarchiveto version 3.8.9. #112434 (Konstantin Bogdanov). - Updated
StringZillato version 5.0.5. #112319 (Konstantin Bogdanov). - Update
jwt-cppto v0.7.2. #112595 (Konstantin Bogdanov). - Update the bundled SQLite amalgamation from 3.41.2 to 3.53.4. #112599 (Konstantin Bogdanov).
- Updated
aws-c-httpto version 0.11.0. #112413 (Govind R Nair). - Update
libcotpto v4.2.1. #112596 (Konstantin Bogdanov). - OpenSSL can now be built from its portable C sources on architectures that have no hand-written assembly in the build description, instead of failing at the final link with undefined symbols. The new
OPENSSL_NO_ASMCMake option selects the same path explicitly. #112863 (Alexey Milovidov). - Added an
ENABLE_ORCCMake option (on by default), so a build can have Parquet without ORC and without the protobuf andprotocthat ORC brings with it. #112864 (Alexey Milovidov). Common/Exception.cppno longer requires ClickHouse’s patched libc++ to compile, so a build linking a different C++ standard library gets exceptions without a throw-site stack trace rather than not compiling. #112865 (Alexey Milovidov).- Stack unwinding on aarch64 musl builds now continues through signal frames and blocked syscalls instead of stopping at the libc frame, improving stack traces from the fatal error handler and the sampling query profiler. #112592 (Konstantin Bogdanov).
- Update the vendored
libexpatto 2.8.2. #112593 (Konstantin Bogdanov). - Update
simdjsonto v4.6.5. #112594 (Konstantin Bogdanov). - Update Apache Arrow to 25.0.0 and Apache ORC to 2.3.1. #112604 (Konstantin Bogdanov).
- Coverage builds (
WITH_COVERAGE) now link the profile runtime built in-tree from the vendored LLVM sources instead of the archive bundled with the host clang toolchain. #112607 (Konstantin Bogdanov). - Update Protocol Buffers to v35.1 and gRPC to v1.83.0. #112614 (Konstantin Bogdanov).
- Added an experimental WebAssembly (
wasm64, via Emscripten) target:emcmake cmakenow configures the tree and the lower layers build. Also fixed-DENABLE_LIBFIU=OFF, which did not build on any platform. #112911 (Alexey Milovidov). - Fixed every
-Wunique-object-duplicationsite: header-defined mutable singletons that would get one copy per shared object instead of one per process. Mostly by moving the definition into a.cpp. #112995 (Alexey Milovidov). - Installing a
tgzpackage over a dangling symlink now preserves the symlink chain and applies the packaged target’s mode and ownership instead of aumask-derived mode. #112766 (Alexey Milovidov). - In
aarch64musl builds,memmovenow uses the ARM optimized-routines assembly implementation (shared withmemcpy) instead of the generic C word-at-a-time loop. #113502 (Konstantin Bogdanov). - In musl builds,
getaddrinfowithAI_ADDRCONFIGnow follows glibc semantics, solocalhostno longer resolves to an unusable::1first in IPv4-only environments, andsysconfreturns glibc’s buffer-size hints forgetpwuid_r/getgrgid_rinstead of -1, unbreaking libhdfs3. #113485 (Konstantin Bogdanov). - In musl builds,
sched_getcpuis now an rseq read (~1ns) instead of a syscall, matching glibc and removing the system-time overhead of jemalloc’spercpu_arenaon allocation-heavy workloads; musl also registers rseq eagerly and exports the glibc__rseq_*ABI. #113501 (Konstantin Bogdanov). - Fix local (non-CI) builds compiling all vendored Rust code (the
PCOcodec, Delta Lake reads viadelta-kernel-rs,prqlc,chdig,wasmtime, the client’s fuzzy history search viaskim) withopt-level = 0. TheSANITIZECMake variable was declared withoption, so its default value was the BOOLOFF, which failed theSTREQUAL ""“no sanitizer” checks, and every build configured without an explicit-DSANITIZE=...took the sanitizer workaround path that disables Rust optimization. #114083 (Alexey Milovidov). - Push docker image layers zstd-compressed. #114342 (Alexey Milovidov).
- Build Debian packages for the release builds only. #114739 (Alexey Milovidov).
- Fixed building
unit_tests_dbmsin configurations without the full library set (ENABLE_LIBRARIES=0orENABLE_ROCKSDB=0). #115655 (Alexey Milovidov).
ClickHouse release 26.7, 2026-07-22. Presentation, Video
Backward Incompatible Change
- Mark rotated non-replicated
MergeTreesystem log tables without TTL astable_readonlyto avoid unnecessary background operations. Thetable_readonlyMergeTreesetting now also suppresses all background work on a plainMergeTreetable — regular, TTL (DELETE/MOVE/recompression) and recompression merges, background mutations, and background part moves — and rejects the mutating partition commands (ATTACH/MOVE/DROP/DROP DETACHED/FETCH/REPLACE PARTITIONandMOVE PARTITION ... TO TABLEinto the table), in addition to the inserts, mutations, andOPTIMIZEit already rejected. As a result, atable_readonlytable with a TTL no longer reclaims its expired data while the setting is enabled. Downgrade warning: the rotated system log tables (for examplesystem.text_log_0) now storetable_readonly = truein their metadata. Thetable_readonlysetting exists since 26.3, so servers older than 26.3 fail to start after a downgrade withUNKNOWN_SETTING(Unknown setting 'table_readonly': for storage MergeTree: Cannot attach table). Before downgrading to a version older than 26.3, drop the rotatedsystem.*_log_Ntables (it is safe to drop them), or runALTER TABLE system.<table>_log_N RESET SETTING table_readonlyon each of them. #95079 (Mathuranath Metivier). - S3 access originating from user SQL no longer resolves the server’s own cloud credentials (environment, IMDS/IRSA, instance profile, AWS config files,
role_arn-based STS, GCP OAuth metadata) by default; such a request must use explicit credentials orNOSIGN. Named collections now defaultuse_environment_credentialsto0. The previous behaviour can be restored per request withuse_environment_credentials = 1(or globally via the<s3>config) together with the new settings3_allow_server_credentials_in_user_queries(disabled by default). Explicitly supplied and operator-provisioned config credentials are unaffected. On server startup orRESTORE, a persistentS3/S3Queuetable, dynamic S3 disk, orDataLakeCatalogwhose definition resolves such credentials is loaded anonymously (inaccessible until re-credentialed) instead of aborting startup, controlled by the new server settings3_load_table_anonymously_if_credentials_restricted(enabled by default). #106855 (Raúl Marín). - The
**/glob (any number of directories) now also matches the same directory. Previously,**/in glob patterns was not handled as a special case, sodata/**/file.txtwould not matchdata/file.txt(zero directory levels). #97676 (Alexey Milovidov). - Reject the
zip/zipxbackup archive format for backups stored on object storage — directS3(...)/AzureBlobStorage(...)destinations andDisk(...)destinations backed by S3 or Azure — for bothBACKUPandRESTORE. Zip requires seeking to read its central directory, which is very slow over object storage. Use a tar-based format such astar.gzinstead. #101770 (Yash ). - Extended the supported range of
DateTime64from[1900-01-01, 2299-12-31]to[0000-01-01, 9999-12-31]. Values outside the former range are now computed correctly (via cctz) instead of being clamped to the boundary. With precision 8 or 9 the range remains narrower because the ticks are stored asInt64(with nanosecond precision the maximum is still2262-04-11). Backward compatibility: if you used out-of-range date-times before, but relied on the very specific saturation rules inside the old range, keep in mind that now the results are changing to be more correct. #107907 (Alexey Milovidov). AggregatingMergeTreenow rejects, at table creation time, schemas where a column is neither part of the sorting key nor an aggregate-state measure (AggregateFunction/SimpleAggregateFunction). Such columns are silently collapsed to an arbitrary value during background merges, producing wrong results for queries thatGROUP BYor filter on them. Setallow_dimensions_outside_sorting_key = 1to restore the previous behavior. Closes #751. #108087 (Alexey Milovidov).- Removed the config-based workload scheduling configuration (the
resourcesandworkload_classifiersserver config sections). UseCREATE RESOURCEandCREATE WORKLOADqueries instead. The obsolete config sections are ignored with a warning. #108286 (Sergei Trifonov). - ClickHouse now always uses the unified insert deduplication hash for both synchronous and asynchronous inserts; the legacy per-insert deduplication behaviours are removed. The server setting
insert_deduplication_versionis kept as a migration guard: the server refuses to start if it is set to a legacy value (old_separate_hashesorcompatible_double_hashes). To upgrade from a version that used a legacy value, first run a release that supportscompatible_double_hashes(which writes both the legacy and unified hashes). For replicated tables run it for at leastreplicated_deduplication_window_seconds(one hour by default; the default windows retain the unified hashes of all inserts for that window, which is considered enough for an insert retry loop). For non-replicated tables withnon_replicated_deduplication_window> 0 that window is count-based rather than time-based, so runcompatible_double_hashesfor at least that many inserts. Then remove the setting (or set it tonew_unified_hash) before upgrading to this version. #108361 (Sema Checherinda). If you never setinsert_deduplication_version, you can ignore this item. - Removed the long-deprecated functions
snowflakeToDateTime,snowflakeToDateTime64,dateTimeToSnowflakeanddateTime64ToSnowflake. They were deprecated back in v24.6 in favor ofsnowflakeIDToDateTime,snowflakeIDToDateTime64,dateTimeToSnowflakeIDanddateTime64ToSnowflakeID, which should be used instead. The settingallow_deprecated_snowflake_conversion_functions(which used to re-enable them) is now obsolete and has no effect. #108711 (Alexey Milovidov). - The setting
use_legacy_to_timeis now0by default, sotoTimeconverts values into theTimedata type instead of converting a date with time to a fixed date. The legacy behavior is still available via thetoTimeWithFixedDatefunction or by settinguse_legacy_to_time = 1. #108729 (Alexey Milovidov). - Naive Bayes models (used by
naiveBayesClassifier) are now configured as a dictionary with theNAIVE_BAYESlayout, built at load time from a table of pre-aggregated per-class n-gram counts, instead of the previous server-side configuration (an XML config file referencing serialized.binmodel files), which is no longer supported — existing models must be recreated as dictionaries. Three new functions are added alongsidenaiveBayesClassifier:naiveBayesClassifierWithProbreturns the predicted class together with its probability,naiveBayesClassifierWithAllProbsreturns every class with its probability, andnaiveBayesNgramstokenizes text into n-grams the same way the dictionary does, for building the training data from raw labelled text. Additionally, several performance optimizations have been applied: on a 9.7 MiB code-point trigram language model, it uses ~49× less memory (from 1.84 GiB to 38 MiB), loads ~11× faster, and classifies ~11× faster. #108773 (Nihal Z. Miaji). - The
hasColumnInTablefunction no longer accepts the optionalhostname,username, andpasswordarguments for checking a column on an arbitrary remote server; only thehasColumnInTable(database, table, column)form remains. The removed remote mode was a security concern: it let any user trigger outbound connections to arbitrary hosts and leaked credentials into query logs, and it was not gated by any privilege. #110881 (Alexey Milovidov).
New Feature
- Added
EXPLAIN ANALYZEfor examination of query performance: the query is executed, and the actual execution metrics are rendered in the familiar query plan format. #106586 (Kirill Kopnev). #110668 (Kirill Kopnev). - Added support for
WHEREclauses in projection definitions. Projections withWHEREonly materialize rows matching the predicate, and the optimizer can use them (cost-based) when the query’sWHEREimplies the projection’sWHERE. #102347 (S Bala Vignesh). - Added the
skip_unavailable_shards_modesetting (also available as aDistributedengine setting) to control which exceptions from a remote shard are silently ignored whenskip_unavailable_shardsis enabled. #79091 (cjw). - Add
groupFormataggregate function that formats rows in each group using a specified output format and returns the result as a string. #93201 (Yang Hu). - Added
AWS_MSK_IAMas a supported value forkafka_sasl_mechanism, enabling ClickHouse to authenticate with Amazon MSK using IAM roles without managing SASL/SCRAM credentials. #96100 (kalavt). - Add aggregate function combinator
-Tuple, which applies the underlying aggregate function to each element of aTuplecolumn independently and returns aTupleof the results, preserving element names:sumTuple(t)fort = (a, b)returns(sum(a), sum(b)). Aggregate functions with several arguments take one tuple per argument, paired by position:corrTuple((a1, a2), (b1, b2))returns(corr(a1, b1), corr(a2, b2)). Unlike-ForEachover arrays, elements may have different types, and per-element result types and names are preserved. #98190 (RinChanNOW). - Text indexes now support a
postprocessorargument — an arbitrary expression that transforms each token after tokenization (for example,lower). #98939 (Jimmy Aguilar Mena). #108606 (Jimmy Aguilar Mena). - Added the
system.stemmerssystem table, which lists all languages that can be specified for thestemfunction. #100611 (Jimmy Aguilar Mena). - Add support for
WITH TIESfor negativeLIMIT. #100930 (Nihal Z. Miaji). - Added support for the standard SQL
AT TIME ZONEandAT LOCALpostfix operators as syntactic sugar fortoTimeZone. The expressionexpr AT TIME ZONE zoneis now equivalent totoTimeZone(expr, zone), andexpr AT LOCALis equivalent totoTimeZone(expr, timeZone()). #106092 (lizepeng). - The
URLtable engine andurltable function now dispatch to the appropriate backend based on the URL scheme:file://is served by theFileengine,s3:///gs:///gcs:///oss://byS3,az:///azure:///abfss:///abfs://byAzureBlobStorage,hdfs://byHDFS, andhttp(s)://by theURLengine as before. Theurl_basesetting is applied before scheme dispatch. Only the S3 schemes resolved by the defaulturl_scheme_mappersare dispatched; other S3-compatible vendor schemes (cos,obs, …) are not, and require using thes3engine/function directly. #106093 (Alexey Milovidov). - Added the
RemoteandRemoteSecuretable engines, the persistent counterparts of theremoteandremoteSecuretable functions.CREATE TABLE ... ENGINE = Remote('addresses', db, table, ...)now works in addition toCREATE TABLE ... AS remote(...). #106189 (Alexey Milovidov). - Added engine-agnostic
SYSTEM STOP,SYSTEM START,SYSTEM PAUSE,SYSTEM CANCEL, andSYSTEM REFRESHcommands, and their... ALL BACKGROUNDserver-wide forms, to control the background activity ofKafka,RabbitMQ,NATS,S3Queue/AzureQueuetables and refreshable materialized views through one unified interface. For refreshable materialized views they alias the existingSYSTEM ... VIEWcommands. As part of supporting these controls on NATS, JetStream tables now acknowledge messages only after a successful insert (at-least-once, previously messages were auto-acknowledged on delivery and could be lost if the insert failed). A newnats_wait_for_flush_intervalsetting (defaultfalse, preserving the previous low-latency behaviour) optionally keeps a consumption cycle open for the whole flush interval instead of flushing as soon as the queue drains. A newnats_commit_on_selectsetting makes a directSELECTon a JetStream table consume (acknowledge) the messages it reads. #107476 (Samuel Krempaský). - Added support for the
mysql,postgresql, andsqlitetable functions and table engines to accept a user’s query (instead of a table name) and pass it to the external database as is, written either as a subquery(SELECT ...)or asquery('SELECT ...'). The structure of the resulting table is inferred from the query result, and such a table is read-only. Closes #46758. Based on the initial implementation by Denis Vidiaev (#79652). #107740 (Alexey Milovidov). - Added tabs to the ClickHouse Web UI (Play) for working with multiple queries at once. Tabs, their titles, parameters, active state, and small result snapshots are persisted across reloads (large and image results are not restored), integrate with browser history and the URL, and can be switched with the mouse wheel. #107826 (Alexey Milovidov).
- Introduce the
QueryRunnertable engine. Records inserted into aQueryRunnertable represent queries that the engine executes. The engine can be used for asynchronous query execution, batch execution of generated queries, directing queries to remote clusters, benchmarks, fuzzing, and testing with shadow traffic. #107888 (Miсhael Stetsyuk). - Add the
GeoJSONoutput format for writing GeoJSONFeatureCollectiondocuments, producing one feature per row. The single geo-typed column (Point,LineString,MultiLineString,Polygon,MultiPolygon,Ring, orGeometry) becomes each feature’sgeometry; a column namedidbecomes the featureid; and any remaining columns become the featureproperties, where a lone object-typed column namedproperties(aJSON,Map, or namedTuple) is written directly as thepropertiesobject. ARingis written as a single-ringPolygon. The newformat_geojson_validate_geometrysetting (enabled by default) controls whether geometries that are not valid GeoJSON shapes — such as aPolygonwith fewer than four points or an unclosedPolygonring — are rejected when reading and writing. Additionally, theGeoJSONinput format now infers theidcolumn asNullable(String)instead ofString, so a feature with an absent or explicit"id": nullmember is read asNULLand kept distinct from an empty string"". Based on the initial implementation by Mark Needham (#98124). #108065 (Nihal Z. Miaji). - Added the
dotProductTransposedfunction (aliasscalarProductTransposed) that computes the approximate inner product between aQBitcolumn and a reference vector, complementing the existingL2DistanceTransposedandcosineDistanceTransposedfunctions. #108100 (Alexey Milovidov). Added quantized transposed distance functionscosineDistanceTransposedQuantized,L2DistanceTransposedQuantizedanddotProductTransposedQuantizedthat operate on aQBit(Int8)ofquantizeBFloat16ToInt8Lloyd-Max codes, dequantizing the stored codes on the fly. A floating-point reference vector is the full-precision query, compared atFloat32precision (aFloat64query is narrowed); anArray(Int8)reference is itself dequantized, for a symmetric quantized-vs-quantized distance. #109405 (Alexey Milovidov). - Added an optional stride parameter to the
QBitdata type (QBit(T, dimension, stride)) that stores groups of dimensions in separate streams, so a vector search can read only the first dimensions efficiently (e.g. for Matryoshka embeddings). The transposed distance functions accept an optional fourthused_dimsargument to read a reduced number of dimensions. #108103 (Alexey Milovidov). - Added support for the
Int8element type in theQBitdata type, enabling storage and transposed-distance vector search (L2DistanceTransposed,cosineDistanceTransposed) over quantized 8-bit integer vectors. #108105 (Alexey Milovidov). - New function
randomHadamardTransform(vector[, seed[, output_dims]]): a deterministic randomized Hadamard transform of a float vector — an orthogonal, norm-preserving rotation useful for preprocessing embeddings before quantization, and (when truncated) as a Johnson–Lindenstrauss / subsampled-randomized-Hadamard random projection. #108227 (Alexey Milovidov). - Support configuring lazy loading of dictionaries on a per-dictionary basis with the
dictionary_lazy_loadsetting in the dictionary definition, overriding the globaldictionaries_lazy_loadserver setting, so that some dictionaries can be loaded lazily while others are loaded eagerly. #108314 (Miсhael Stetsyuk). - Added a built-in documentation search page, available at the
/docspath of the HTTP interface, that provides instant search over thesystem.documentationtable and renders the reference documentation (with syntax highlighting, math, and cross-links). #108345 (Alexey Milovidov). - Added function
xxHash64Spark, which computes Spark-compatiblexxHash64values forStringandNULLinputs using seed42and returnsInt64. #108436 (Lalit Yadav). ALTER USER,ALTER ROLEandALTER SETTINGS PROFILEnow acceptSET name = valueas an alias forMODIFY SETTING name = value. It changes individual settings in place while keeping the rest, unlike the bareSETTINGSclause which replaces the whole settings list. This makes it less likely to accidentally wipe a user’s other settings. #108722 (Groene AI).- Support
ALTER TABLE ... MODIFY CONSTRAINT [IF EXISTS] name CHECK exprto change the expression of an existing constraint in place. #108768 (Alexey Milovidov). - Web UI: added a per-column color coding switch (the 🌈 icon in a column header) to toggle between bar, heatmap, categorical, and no visualization. The selected modes are remembered in the URL and browser history. #108873 (Alexey Milovidov).
Keepernow correctly handlesZooKeeper’sCreateContaineropcode (19), gated behind a new opt-increate_containerfeature flag (disabled by default, likecreate_ttl). Once enabled after a full ensemble upgrade, externalZooKeeperclients (e.g. JavaZooKeeper3.9+) can create container nodes againstKeeperinstead of gettingConnectionLoss; container nodes report the expectedephemeralOwnersentinel value, and a background GC thread on the leader auto-deletes childless containers. A plainCreaterequest carrying theCONTAINERcreate-mode flag without opcode 19 continues to be rejected (ZBADARGUMENTS): no knownZooKeeperclient emits that combination. This is server-side protocol compatibility only: ClickHouse’s ownZooKeeperclient (zkutil) is unchanged and has no API to create container nodes itself. #108908 (unintended).- Added functions
geoToUTM,UTMToGeo,geoToMGRSandMGRSToGeofor converting between WGS84 geographic coordinates and the UTM and MGRS coordinate systems. #108939 (Alexey Milovidov). - Added the
digits(n, offset[, length])function, which returns the digits ofnstarting at the 1-basedoffsetand spanninglengthdigits, or to the end of the number iflengthis omitted. #109012 (Umang Agrawal). - Add the
sqrarithmetic function for calculating the square of a number. #109061 (Lalit Yadav). - Added a new function
dictGetRootwhich returns the topmost ancestor (the root) of a key in a hierarchical dictionary. It is a convenient equivalent ofdictGetHierarchy(dict_name, key)[-1]. #109459 (Alexey Milovidov). - Add
SYSTEM UNLOAD DICTIONARYandSYSTEM UNLOAD DICTIONARIEScommands to release dictionary memory without dropping the dictionary definition. Dictionaries will be reloaded lazily on the next access. #109639 (Matheus Nerone). - Added functions
geometryIntersectCartesianandgeometryIntersectSphericalthat return whether two geometries intersect. UnlikepolygonsIntersectCartesian/polygonsIntersectSpherical, they accept any geometry data type (Point,LineString,MultiLineString,Ring,Polygon,MultiPolygon), including the commonGeometrytype, and the two arguments may be of different types. #110062 (Alexey Milovidov). - Query parameters (
{name:Type}substitutions) can now be used as setting values, both in theSETTINGSclause of a query (such asSELECTorINSERT) and in standaloneSETqueries, e.g.,SELECT ... SETTINGS max_threads = {threads:UInt64}andSET max_threads = {threads:UInt64}. #108760 (Alexey Milovidov).
Experimental Feature
- Wildcard expansion for the
urltable function and theURLtable engine: wildcards in the URL path are expanded by listing HTTP index pages (HTML or plaintext directory listings) and extracting matching URLs, with limits on the index page size and on the number of directories read. Enabled by theallow_experimental_url_wildcard_from_index_pagessetting. #95181 (Yue Ni). - Text indexes can now store token positions (the
support_phrase_searchindex argument) to enable exact phrase matching with direct reads for thehasPhrasefunction. Requires enabling theMergeTreesettingallow_experimental_text_index_phrase_search. #103172 (Elmi Ahmadov). The argument was initially introduced under the namepositions. #109900 (Elmi Ahmadov). - Support manifest file compaction for
Icebergtables viaOPTIMIZE TABLE ... MANIFEST(guarded by theallow_experimental_iceberg_compactionsetting). Closes #95174. #98178 (Smita Kulkarni). FixOPTIMIZE TABLE ... MANIFESTforIcebergtables when manifest partition tuples do not match their partition spec. #111368 (Smita Kulkarni). - Add a Real Doubles (RD) variant and an optional
ALP(AUTO|STD|RD)argument to the experimentalALPcodec. BareALPnow auto-selects between the existingSTDscheme andRDinstead of always usingSTD. #99654 (Nazarii Piontko). - Add an in-memory SLRU cache for deserialized
Paimonmetadata files (manifest lists and manifests). When enabled via theuse_paimon_metadata_files_cachesetting, repeated queries against the samePaimontable skip re-downloading and re-parsing metadata from object storage. #104657 (XiaoBinMu). - Added “drivers” for executable user-defined functions. A driver declared in
<user_defined_executable_function_drivers_config>can be used inCREATE FUNCTION name ARGUMENTS (...) RETURNS T ENGINE = DriverName(...) AS '...code...'to compile or otherwise process a user code snippet at function-creation time and produce a runnable executable UDF. The resulting configuration is stored in<dynamic_user_defined_executable_functions_path>, and the originating query is persisted asATTACH FUNCTIONso the function survives server restarts. A proof-of-conceptc_function_bodydriver compiles and runs C function bodies inside sandboxed Docker containers inexecutable_poolmode. Based on the initial implementation by Daniil Timižev (#77128). #105131 (Alexey Milovidov). - Serve
SELECT count(*) FROM t WHERE col <op> default(col)from per-column sparsity statistics inserialization.jsonwithout any data scan when the predicate exactly partitions the column into defaults and non-defaults (under the new experimental settingoptimize_trivial_count_with_sparsity_filter, off by default). #105890 (Raúl Marín). - Prometheus Query API requests to
/api/v1/queryand/api/v1/query_rangeare now recorded insystem.query_logwithread_rowsandread_bytesmetrics. #106611 (James Cunningham). - The experimental
ReaderExecutorread path (use_reader_executor, off by default) can now hold a remote source connection open and reuse it across sequential reads, reducing the number of object storage requests on scans. #107735 (Sema Checherinda). It now also supports reading encrypted files, with a global encryption-header cache configured by theencryption_header_cache_sizeserver setting and cleared bySYSTEM DROP ENCRYPTION HEADERS CACHE. #109702 (Sema Checherinda). - Support distributed query-plan reads for
SELECT ... FINALonMergeTree-family tables whenmake_distributed_planis enabled. #108148 (Alexander Gololobov). - Add experimental plan-based parallel replicas execution for
MergeTreequeries. #108504 (Igor Nikonov). - Added the experimental
Quantizevector codec family and an opt-in two-stage approximate vector-search rewrite over quantized companion streams. #108565 (Shankar Iyer). - Revive the experimental
SZ3error-bounded lossy compression codec forFloat32/Float64(and arrays of them) columns, originally implemented by Konstantin Vedernikov (#83088). It requiresallow_experimental_codecs. #108788 (Alexey Milovidov). Fixed reading data compressed withSZ3('ALGO_LORENZO_REG', ...), which previously failed withCORRUPTED_DATA, and avoided undefined behavior when compressing non-finite floating-point values (NaNand infinities). #110762 (Alexey Milovidov). - Added the experimental
ZXCcodec — an asymmetric LZ codec with slow compression and very fast decompression, with a compression ratio betweenLZ4andZSTD. It requiresallow_experimental_codecs = 1, andsystem.compression_codecsreports it as experimental. #110620 (Alexey Milovidov). #111007 (Alexey Milovidov). - You can now authenticate to OneLake using a pre-obtained bearer token via the
onelake_bearer_tokensetting, instead of aonelake_client_idandonelake_client_secret. This avoids sharing a long-lived client secret. The token is not refreshed, so the database must be recreated once it expires. #109104 (Asya Shneerson). - AI functions no longer take the named collection as the first positional argument. Credentials come from the
ai_function_text_default_credentials/ai_function_embedding_default_credentialssettings or from acredentialskey in an optional trailingMap(String, String)argument, which also carries tunables (model,max_tokens,temperature,system_prompt,instructions,dimensions). #109232 (George Larionov). TheaiEmbedfunction now takesmodelas a required positional argument (aiEmbed(text, model[, params])) instead of reading it from the named collection, which ensures reproducibility for embeddings. #110619 (George Larionov). - Fix
data_uncompressed_bytesfor skip indices packed intoskp_idx.packed(viapacked_skip_index_max_bytes): the reported uncompressed size was the compressed size, which could also preventdistributed_index_analysisfrom activating. #109272 (Raúl Marín). - Added experimental packed data part storage for
MergeTreetables, which stores most of a part’s files in a singledata.packedarchive instead of a file per stream (projections and a few service files, such astxn_version.txt, are still written separately). It is controlled by themin_bytes_for_full_part_storage,min_rows_for_full_part_storage, andmin_level_for_full_part_storagesettings and is disabled by default. Once a table writes packed parts, older server versions cannot read them, so enabling this format prevents downgrading the server. #108118 (Raúl Marín). - Added an experimental table function
eval, which evaluates a constant expression to a query string and executes the resulting singleSELECTquery. The feature is disabled by default and can be enabled with the settingallow_experimental_eval_table_function. Author: Yue Ni. #110132 (Alexey Milovidov). - Add
zstdcompression support to the experimental Prometheus remote-write v1 HTTP handler. #110907 (James Cunningham). - Writing to
DeltaLaketables (theallow_experimental_delta_lake_writessetting) was promoted to Beta. #107034 (Kseniia Sumarokova). - Added
ProfileEventsDistributedPlanRemoteTasks,DistributedPlanLocalExecution, andDistributedPlanHostsUsedto observe the execution of experimental distributed query plans (make_distributed_plan). #107985 (Shankar Iyer). - Removed the experimental RocksDB-based storage in Keeper (
experimental_use_rocksdb). A better new on-disk storage is coming soon. #108000 (Michael Kolupaev). - Distributed index analysis (an experimental feature controlled by the
distributed_index_analysissetting) now sends big lists of data part names to remote servers as scalars instead of embedding them into the query text. This avoids possible failures due to themax_ast_elements/max_query_sizelimits and removes the AST parsing overhead. #110419 (Azat Khuzhin). - Optimize the experimental
timeSeries*ToGridaggregation functions: buckets are now aligned to both step and window, and the final aggregation is much faster when the window is much larger than the step. The serialization format of the aggregation state was changed in an incompatible way (these functions are experimental). #106724 (Vitaly Baranov). - External target tables of a
TimeSeriestable are now registered as referential dependencies: similarly to materialized views, this disallows dropping an external target table before dropping theTimeSeriestable that references it (ifcheck_referential_table_dependenciesis enabled). #108388 (Vitaly Baranov). - Add the PromQL function
increase. #111023 (Vitaly Baranov).
Performance Improvement
JOINs can now use the primary key index or skip indexes on the left-hand side table to prune granules. Controlled by the settingenable_join_runtime_filters_index_analysis. #109085 (Shankar Iyer).- Serialization and deserialization of vectors of trivially serializable types now use a single buffer I/O call instead of processing individual elements. #89842 (Jimmy Aguilar Mena).
- Optimize inverse dictionary lookups: a constant equality predicate such as
WHERE dictGet(dict, attr, key_expr) = valueis now constant-folded directly into a key filter (key_expr = const,key_expr IN [...], orWHERE 0) instead of being rewritten to anIN (SELECT ... FROM dictionary(...))subquery, and the constant path ofdictGetKeysnow executes in parallel. #91164 (Nihal Z. Miaji). - Add a new setting
merge_tree_generic_exclusion_search_max_stepsthat limits the number of steps the generic exclusion search algorithm spends analyzing the primary key index of each data part. The budget is spent on the largest remaining key ranges first, so even a small budget prunes the bulk of the data; ranges that were not fully analyzed are read whole, so query results stay correct but more granules may be read. The limit is applied loosely: it may be exceeded by at mostmerge_tree_coarse_index_granularitysteps, plus one step for each range the part is already divided into (for example, by the query condition cache). The default value 0 means unlimited steps. #92779 (Michael Jarrett). - Queries with
ORDER BYandLIMITon views overDistributedtables now use the merge-sorted-streams optimization: the outerORDER BY/LIMITis pushed into a simple view’s inner query, so each shard sorts its data locally and the coordinator merges pre-sorted streams instead of performing a full sort. #94102 (matanper). - Enable
optimize_or_like_chainby default. Closes #87779. #94517 (Alexey Milovidov). - Improve the performance of fetching a single user record from
system.userswhen the server has many users. #96699 (Alistair Evans). - Reading in order with parallel replicas now uses the same logic of splitting the table into
max_threadsparts as local reading, for better parallelism. #101434 (Nikita Taranov). - Use partition minmax index bounds to prune more granules during primary key analysis for
MergeTreetables, when a primary key column is also an input column of the partition key. For example, in aMergeTreetable withORDER BY (id, event_time)andPARTITION BY toYYYYMM(event_time), ClickHouse will use the partition minmax index onevent_timeduring primary key index analysis to make more informed granule-pruning decisions. Controlled by the new settinguse_partition_minmax_for_primary_key_pruning(enabled by default). #103480 (UnamedRus). - Enable the query condition cache for queries that use Top-K dynamic filtering (
ORDER BY ... LIMIT n). The cache entry is partitioned by the Top-K plan parameters, so the same query reuses cachedWHEREfilter results, while a differentLIMIT, sort column, or sort direction produces a fresh entry. #104478 (Alexey Milovidov). - Added the
use_constant_folding_in_index_analysissetting (disabled by default). When enabled,MergeTreeprimary-key,MinMax, and skip-index analysis fold partition-level constants into the filter predicate separately for each part, improving pruning for filters whose branches depend on partition values, e.g.(a = 1 AND b >= 1) OR (a = 2 AND b > 10)withPARTITION BY a. #104582 (Mikhail Artemenko). - Push
LIMITinto aggregation-in-order to enable early termination when theGROUP BYkey matches theORDER BYkey and the table sorting key, significantly reducing the number of rows read. #104859 (Konstantin Bogdanov). - Updating profile events is now up to 30 times faster, using per-CPU atomics for server-wide and per-user counters. Controlled by the
user_profile_events_per_cpuserver setting (it uses around 640 KiB per user on 64 cores, so with a very large number of users it may make sense to keep it disabled). #105056 (Azat Khuzhin). - Enable
allow_aggregate_partitions_independentlyby default. When aGROUP BYkey suits the partition key, ClickHouse can aggregate each partition independently and skip the global merging step. Runtime heuristics automatically skip the optimization when the partition layout would make it unfavorable (too few partitions, too many partitions, or significantly skewed partition sizes). #105128 (Alexey Milovidov). - Vector search queries with rescoring (
vector_search_with_rescoring = 1) now compute the exact distance only for the rows returned by the vector index, applying an exact row-position filter instead of brute-force rescoring neighbouring rows from the sameMergeTreegranule. #105591 (Sergey Kuznetsov). #108846 (Sergey Kuznetsov). - Improve the performance of the
partial_mergejoin algorithm onFixedStringkeys by comparing runs of values at once instead of one comparison call per value. #105737 (Artem Zuikov). SHOW TABLESandsystem.tableson data lake catalogs (Iceberg REST, Glue, Unity, Hive, Paimon) now push namespace-bound predicates down to the catalog, avoiding a full catalog scan. Closes #105022. #106029 (Smita Kulkarni).- Bound untracked memory per CPU to avoid overcommit and out-of-memory errors (the limits are configured with the
max_per_cpu_untracked_memoryandper_cpu_untracked_memory_thread_bufferserver settings). #106055 (Azat Khuzhin). - Speed up operators that scan a sorted stream for runs of equal key values —
DISTINCTin order,LIMIT BYin order, negativeLIMIT BYin order,full_sorting_mergeandpartial_mergejoins. #106502 (Nihal Z. Miaji). - Implemented a native reader and writer for the
ArrowandArrowStreamformats that does not use the Apache Arrow library, avoiding extra data copies and conversions. It is now the default (settingsinput_format_arrow_use_native_readerandoutput_format_arrow_use_native_writer) and is faster for both reading and writing. #106522 (Alexey Milovidov). - Re-enable LTO for jemalloc after fixing a thread-cache corruption that appeared with LTO, which improves performance. #106898 (Azat Khuzhin).
- Reduced memory usage and improved the performance of
JOINs. The right-hand side of a hash join now uses a compact 8-byte index-based row reference, so the hash-table entries ofALLjoins are as small as those ofANYjoins for every key type. Benchmarked on largeparallel_hashjoin queries —INNERandANYjoins of 100–300 million row tables onUInt64andStringkeys, with both unique and duplicated keys: the median query became about 12% faster and used about 15% less peak memory, with no query becoming slower.INNERjoins onUInt64keys gained the most (median about 21% faster with 38% less memory). #107189 (Harikrishnan Prabakaran). - Single-column non-Nullable
LowCardinality(String)join keys are now natively supported in the hash join. #107264 (Nikita Taranov). - Added the
dpsubjoin-order enumeration algorithm (dynamic programming over subsets), providing optimal join plans with lower optimization overhead thandpsizeand support for non-inner joins. #107351 (Fisnik Kastrati). - Speed up filesystem cache loading on startup by encoding each cache file’s size in its name (
<offset>_<size>), avoiding astatper file. Loading of cache files written by older versions remains supported. #107415 (Alexey Milovidov). - Improve the performance of
arrayElementonArray(LowCardinality(String))and of the mapLIKEfunctions onMaps withLowCardinality(String)keys or values, by avoiding unnecessary string materialization. #107450 (Michael Jarrett). - Avoid converting single-level aggregation to two-level aggregation when memory usage is small, by tracking the memory of the aggregation state itself instead of the memory of the whole query. #107490 (Hechem Selmi).
- Speed up analysis of aggregating queries: the cache key for the aggregation hash-table size statistics is now computed from the query plan instead of building the full query AST. #107643 (Dmitry Novik).
- Improve the performance of
INTERSECT ALLandEXCEPT ALL(the default mode forINTERSECTandEXCEPT) by several times, by keying the multiset on the row value instead of hashing each row with SipHash. #107649 (Raúl Marín). - Rebuild row policy filters without holding the cache lock, improving query scalability under concurrent
CREATE ROW POLICYandDROP ROW POLICY. #107917 (Azat Khuzhin). - Speed up the
match,extract,extractAll,replaceRegexpOneandreplaceRegexpAllfunctions for simple regular expressions by compiling them to native code with LLVM. Controlled by the new settingcompile_regular_expressions(enabled by default); patterns outside the supported subset transparently fall back to the RE2 engine. #108004 (Alexey Milovidov). - Sped up ZSTD decompression on AArch64 (ARM) for columns with small match offsets, such as fixed-width integer columns, by vectorizing short-offset overlapping copies with NEON. For example, decompression of a
UInt64column is up to ~2.3x faster on AWS Graviton 4. #108049 (Alexey Milovidov). - Use the
libdeflatelibrary for gzip/zlib/deflate compression and decompression, making it faster (compression ~1.15× with a better ratio, decompression ~1.4–1.5×) for.gz/HTTP/url/s3data and the Parquet GZIP codec. #108074 (Alexey Milovidov). - Improved performance of text-search queries combined with a primary key filter. #108114 (Anton Popov).
- Use runtime statistics collected during the first run of a query to optimize subsequent runs: the
hashjoin algorithm can automatically switch toparallel_hashbased on the collected statistics. #108125 (Hechem Selmi). The size of join runtime filters is optimized using the hash table size from runtime join statistics, controlled by the new settingjoin_runtime_filter_size_from_hash_table_stats. #108313 (Hechem Selmi). - LZ4 decompression speed was improved for fixed-size, low-cardinality columns. #108175 (Nikita Taranov).
- Speed up the default-whitespace
trimLeft/trimRight/trimBothfunctions (and their aliasesltrim/rtrim/trim): consecutive rows that need no trimming are copied in a single batch, and the per-row space scan runs only for rows that actually have a leading or trailing space. #108177 (Groene AI). - Improve the performance of
replaceAllandreplaceRegexpAllwhen the pattern is a single character and the replacement is a single character (for examplereplaceRegexpAll(s, ' ', '_')). Such replacements no longer change the string layout, so the column is now copied once and matching bytes are rewritten in place instead of running a per-match search loop. #108178 (Groene AI). - Improve performance of the
pointInPolygonfunction with a constant polygon. The preprocessed-polygon cache is now keyed on the raw constant arguments, so a constant polygon is parsed only once (on a cache miss) instead of being re-parsed on every input block. #108184 (Groene AI). - Speed up parsing of the canonical
YYYY-MM-DD hh:mm:ssdate-time representation in best-effort mode (date_time_input_format = 'best_effort',cast_string_to_date_time_mode = 'best_effort'), which is the default. This recovers a parsing performance regression introduced when those defaults were switched frombasictobest_effort. #108187 (Groene AI). - Avoid maintaining
system.predicate_statistics_logselectivity counters on theMergeTreeread path when the feature is disabled (predicate_statistics_sample_rate = 0, the default). This removes a per-granule atomic update and anO(rows)filter popcount from every read, recovering a performance regression that was most visible on AArch64. #108190 (Groene AI). - Speed up parsing of floating-point numbers from text with
precise_float_parsing = 1, making it as fast as or faster than the default parser on almost all inputs. Also bumps the bundledfast_floatlibrary to v8.2.10. #108205 (Raúl Marín). - Use the
simdutflibrary for base64 encoding and decoding functions, improving their performance. #108333 (Konstantin Bogdanov). - Optimize
DISTINCTfor expensive high-cardinality keys. #108366 (Nihal Z. Miaji). - On non-Linux builds (macOS and FreeBSD), jemalloc no longer purges dirty pages eagerly (a
madvisesyscall perfree); it now uses a background purging thread with a finitedirty_decay_ms, like on Linux. This significantly speeds up allocation-churning workloads such as recursive CTEs (~2x on a recursive-CTE benchmark on macOS) with negligible RSS impact. #108430 (Alexey Milovidov). - Speed up query planning under the analyzer for expressions that reference the same
WITHalias or repeat the same subexpression many times (for example deeply nestedif/multiIfchains), by not rebuilding shared subexpressions when constructing the actions DAG. #108523 (Dmitry Novik). - Runtime filters are now built on equality keys even when the
ONclause also contains non-equality predicates, reducing the number of rows entering the hash join for joins that mix equality and non-equality conditions.LEFT ANTI JOINis unaffected. #108579 (Antonio Álvarez Caballero). - Enable
-fno-math-errnoglobally across the codebase, which allows the compiler to optimize math functions better. #108628 (Nikita Taranov). - Lower the software-prefetch threshold for aggregation and join hash tables from
4 * L2 cache sizetoL2 cache size, so prefetch is enabled once the hash table no longer fits in L2. This recovers a regression onGROUP BYandJOINover medium-sized hash tables (~1-8 MiB) on platforms whose reported L2 is large (e.g. AArch64 with a 2 MiB L2). #108655 (Groene AI). - Improve window function performance. Window queries over wide tables that include
SELECT *now use significantly less memory and run faster. Window aggregates, includingquantile*,uniq*, andgroupArray, are faster withOVER ()andOVER (ORDER BY ... RANGE ...). Thecume_distfunction is also faster, and windows usingPARTITION BYorORDER BYnow perform better on columns with many repeated values. #108688 (Nihal Z. Miaji). - Sped up query analysis for queries with many or very large
AND-chains of comparisons: theoptimize_and_compare_chainoptimization is now bounded by a work budget (new settingoptimize_and_compare_chain_max_hash_work) instead of hashing a large fraction of the query tree, and lambda resolution no longer recomputes lambda-body hashes for its recursion guard. #108757 (Alexey Milovidov). - Fix a performance regression when reading
JSON/Dynamiccolumns with multiple threads: a per-value lookup of theinput_format_binary_max_type_complexitysetting caused reference-count contention on the shared query context, serializing parallel reads; the setting value is now cached per thread. #108797 (Seva Potapov). - Fixed a performance regression (introduced in #71781) where reading many small files from object storage via the
s3and other table functions stopped prefetching and fell back to synchronous reads, significantly slowing single-threaded and low-concurrency reads of lots of tiny files. #108872 (Nikita Fomichev). The initial small-object prefetch is now also issued when object storage reads go through the filesystem cache (filesystem_cache_name), so reads of many small files (e.g.S3Queueingestion) with the cache enabled are no longer synchronous and latency-bound. #109478 (Nikita Fomichev). - Parse deeply nested array and tuple literals in linear instead of quadratic time. #108892 (Alexey Milovidov).
- Reduce the overhead coming from lock contention in the
parallel_hashjoin algorithm. #108938 (Hechem Selmi). - Speed up
estimateCompressionRatioforT64-encoded columns by computing the compressed size analytically instead of compressing. #109054 (Raufs Dunamalijevs). - Remove a single-threaded bottleneck in the shuffle step of distributed query plans: each upstream stream now scatters its rows by destination bucket independently instead of funneling the whole data stream through a single transform. #109206 (Alexander Gololobov).
- Reduced Keeper server idle CPU usage. #109255 (Michael Kolupaev).
- Speed up serialization and merges of
JSONcolumns whose shared data contains many sparse paths: when flattening shared data into per-path columns, the per-row scan over all accumulated path columns is removed, and gaps are backfilled in bulk instead of inserting default values one cell at a time. #109341 (Groene AI). - Reduce CPU overhead of expression evaluation for queries with a large number of columns (e.g. vector search over a
QBitcolumn with a small stride, where each vector expands into hundreds of bit-plane sub-columns that are all fed into a single*DistanceTransposedcall). #109380 (Alexey Milovidov). - Improve the performance of H3 geo functions (
h3ToGeoBoundary,h3ToGeo,h3CellAreaM2/h3CellAreaRads2,geoToH3) by computing paired sine/cosine together and eliminating redundant trigonometric calls in the coordinate transforms. Results are unchanged (bit-for-bit identical). #109399 (Alexey Milovidov). - Improve performance of comparisons (
<,>,<=,>=) of wide integer types (Int128,UInt128,Int256,UInt256and types based on them, such asDecimal128) by up to 7 times, and of converting signed integers toInt256(up to 7 times on mixed-sign data), by making the comparison and sign-extension code branchless. #109474 (Manuel). - Optimized
uniqCombined(including the case of aggregation without keys) anduniqHLL12. #109794 (Anton Popov). #109831 (Anton Popov). - Functions
arraySortandarrayReverseSortare several times faster over numeric arrays (includingDecimalandDateTime64) when called without a lambda. #109832 (Manuel). - Speed up
addDays,addWeeks,subtractDays, andsubtractWeeksonDateTimeandDateTime64values in fixed-offset time zones (such as UTC) by taking an arithmetic fast path. #109836 (Manuel). - Optimized analysis of the text index. #109886 (Anton Popov).
- Parallelize processing of non-joined rows in the
parallel_hashjoin algorithm in two more cases: when there is a residual filter, and in the case of small join keys (single-level hash map). #110008 (Hechem Selmi). - Built-in web UI responses (the Play UI, dashboards, and static-file handlers) are now compressed according to the client’s
Accept-Encodingheader, using zstd, gzip, deflate, brotli, lz4, xz, snappy, or bzip2. For example, the/playpage shrinks from ~350 KB uncompressed to under 120 KB with zstd, reducing load times on slow connections. Already-compressed responses are left untouched, andVary: Accept-Encodingis emitted for correct CDN and cache partitioning. #110108 (Sayantanu Dey). - Push a filter below a window function or below
LIMIT BYwhen it is safe: a predicate written above them (an outerWHEREaround the subquery, or a conjunct inQUALIFY) that references only the windowPARTITION BYcolumns, or only theLIMIT BYkey columns (forLIMIT n BYwithn >= 1and noOFFSET), now reaches storage and enables primary key and partition pruning, skip indexes, and projections. For example,SELECT ... row_number() OVER (PARTITION BY key ORDER BY ts) AS rn ... QUALIFY rn = 1 AND key = 'x'no longer reads and windows the whole table. #110114 (Groene AI). #110116 (Groene AI). - With
join_use_nulls = 1, a null-rejectingWHEREthat references columns from both sides of an outer join (e.g.WHERE l.k = 42 AND r.k = 42) now converts the join toINNER(orLEFT/RIGHT) and prunes the primary key, the same as withjoin_use_nulls = 0. Previously the conversion was skipped in this case and both tables were read in full. #110121 (Groene AI). - Functions with a single non-const
Nullableargument now share the argument’s null map with the result instead of allocating and merging a new one. #110151 (Manuel). - Avoid a heap allocation per hyperrectangle check in primary key index analysis, speeding up mark filtering by 5-26% depending on the query shape. #110153 (Manuel).
- Improve performance of functions
arrayMinandarrayMaxover numeric arrays by ~1.3-1.5x by using a vectorized reduction instead of a per-element comparison loop. #110163 (Manuel). - Vectorize decompression of the
Deltacodec. Decoding is now 1.5–5 times faster for 8/16/32-bit data types, making scans ofDelta-compressed columns up to 20% faster. #110189 (Manuel). - Speed up string search functions (
like,position,match,countSubstrings,hasToken, etc.) overEnumcolumns with a constant needle by searching only the distinct enum names and mapping the results back per row, instead of searching every row. #110325 (Alexey Milovidov). - Speed up aggregate functions
groupBitOr/groupBitAnd/groupBitXorand the variance family (varPop,varSamp,stddevPop,stddevSamp,skewPop,skewSamp,kurtPop,kurtSamp,covarPop,covarSamp,corr) with vectorized batch processing: up to 4x faster with the-Ifcombinator on unpredictable conditions, and up to 3x faster for the variance family without it. #110461 (Manuel). - Speed up the analysis of the text index (the stage that selects which granules to read): use exclusion search instead of iterating over all granules, and avoid creating a temporary bitmap for each range check. #110530 (Anton Popov).
- Account for the on-disk size of
Mapsubcolumns in the automaticPREWHEREoptimization. This fixes a performance regression inPREWHEREintroduced in #99200. Part of #110462. #110623 (Pavel Kruglov). - Speed up parsing of
UUIDvalues from text (e.g.JSONExtractintoLowCardinality(UUID),toUUID,CAST AS UUID) by validating and converting hex digits in a single pass instead of two. #110625 (Groene AI). - Significantly improve performance of the
timeSeries*ToGridaggregate functions by using faster sorting and hash table implementations. #110875 (Nikita Mikhaylov). - Queries like
SELECT * FROM t WHERE idnow use index skipping on theidcolumn. Closes #89222. #89603 (Aditya Chopra). - Added the
query_plan_merge_expression_into_joinsetting (enabled by default) to allow merging expression steps intoJOINsteps during the join reordering optimization. This enables join reordering across subqueries that wrap joins (e.g., when aJOINis inside a subquery with computed columns), leading to better optimization of complex join trees. #98533 (Vladimir Cherkasov). - Optimize
ANDchains with multiple comparison conditions on the same expression: detect contradictions (e.g.,a < 3 AND a > 5→false) and prune redundant conditions (e.g.,a = 3 AND a < 5→a = 3). #99736 (Xiaozhe Yu). - Materialized CTEs referenced from multiple branches of a
UNIONquery are now materialized once and shared across all branches. Previously, each branch received its own copy of the CTE, which was inlined and evaluated separately. #102107 (Dmitry Novik). - Threads in
BackgroundSchedulePoolare now created lazily on demand instead of all at once at server startup. A new server settingbackground_schedule_pool_initial_size(default16) controls how many workers are pre-spawned; the pool grows up tobackground_schedule_pool_sizewhen needed. This reduces the number of idle threads on lightly-loaded servers. Closes #85265. #105066 (Alexey Milovidov). - Skip unnecessary mark file loads for the
JSONtype’s advanced shared data serialization. #107051 (Pavel Kruglov). - The cache of preprocessed constant polygons for the function
pointInPolygonis now shared between queries and threads and bounded by the new server settingpoint_in_polygon_cache_size(default 256 MiB,0disables the cache, changeable at runtime). Previously, the cache kept up tomax_threadscopies of each preprocessed polygon, grew without bound across distinct polygons, and was never released until server restart. It can be cleared withSYSTEM DROP POINT IN POLYGON CACHE, and the current usage is reported insystem.metricsasPointInPolygonCacheBytes,PointInPolygonCacheCells, andPointInPolygonCacheSizeLimit. Closes #106393. #107247 (Nihal Z. Miaji). - Keeper no longer holds its internal snapshots lock while serializing and writing a snapshot to disk or moving snapshots between disks, so snapshot transfers to other nodes and Raft processing are no longer stalled by local snapshot creation. #107595 (Antonio Andelic).
- Parallelize the filesystem cache background eviction (controlled by the
keep_free_space_ratiosettings). Added a new settingkeep_free_space_eviction_threadsto control the parallelism, and increased the default ofkeep_free_space_remove_batchfrom100to250. #108147 (Kseniia Sumarokova). - Limit the number of concurrently staged parts in the Azure Blob Storage read-then-write copy (used by backups when native copy is unavailable) to
max_inflight_parts_for_one_file, preventing excessive memory usage when many large files are copied in parallel. #108232 (Smita Kulkarni). - Enabled all three text index caches globally — previously, they were only enabled within queries. Also, the posting lists cache size is now zero, which effectively disables it again, because posting lists are large and caching them is too costly. #108274 (Robert Schulze).
- Add streaming in-memory marks compression during marks loading to reduce peak memory usage. Closes #108285. #108325 (Pavel Kruglov).
- The new filesystem cache setting
reserve_granularity(default 4 MiB) reserves space ahead in coarser granules, reducing lock contention on the filesystem cache space reservation hot path. #108369 (Kseniia Sumarokova). - Reduce the amount of memory used by the filesystem cache metadata (per file segment and per key). #108477 (Kseniia Sumarokova).
- Queries to
system.iceberg_historywithWHEREfilters on thedatabaseandtablecolumns now access only the matching databases, which can save time if you have many unrelated remote databases on the server. #108492 (Den Kalantaevskii). - Removed unnecessary locking in the filesystem cache to reduce lock contention. #108932 (Kseniia Sumarokova).
- Reduced memory usage of
BACKUPandRESTOREmetadata handling. Opening a backup (forRESTORE, or as the base of an incrementalBACKUP) now parses the.backupmetadata as a stream instead of loading it into an in-memory XML document tree, which for large (especially incremental) backups avoids allocating a multi-gigabyte DOM tree. #109107 (Julia Kartseva). Finalizing aBACKUPno longer copies the file infos of all files into a temporary vector, which, for backups of millions of files, transiently cost several gigabytes. #109861 (Julia Kartseva). Writing backup entries also no longer copies the current host’s file-info list. #111162 (Julia Kartseva). - Reduce memory consumption in the aggregator. #109224 (Konstantin Vedernikov).
- Support the query condition cache for local
Parquetfiles read via theFiletable engine (previously supported only for object storage and data lakes). #109247 (Alexey Milovidov). - Reduced the memory usage of the text index header cache by 2-2.5 times. More headers of data parts fit into the cache (setting
text_index_header_cache_size), reducing disk reads for text search queries. #109332 (Anton Popov). - The transposed vector distance functions
L2DistanceTransposed,cosineDistanceTransposedanddotProductTransposednow apply the partial bit-plane read optimization toNullable(QBit)columns, reading only the requested bit planes instead of the whole column. #109358 (Alexey Milovidov). IS NOT DISTINCT FROMandIS TRUEnow use primary-key and minmax indexes to prune granules, the same as=. Previouslyk IS NOT DISTINCT FROM 42and(k = 42) IS TRUEscanned all granules. #110006 (Groene AI).- Pooled connections are no longer pinged before each use. This removes a
Ping-Ponground trip that was added to every reused connection, reducing the latency of distributed queries and ofclickhouse-benchmark. A stale pooled connection is detected with a zero-timeout poll (a non-blocking check that adds no round trip) and recovered by reconnecting. #110068 (Alexey Milovidov). - Fixed spurious reconnections of pooled HTTP keep-alive connections over TLS (HTTPS, S3). The stale-connection check used
pollon the socket, which misreports a live secure connection carrying an unread TLS post-handshake record (a session ticket orKeyUpdate) as closed; it now uses a non-blockingMSG_PEEKon plain sockets andSSL_peek/SSL_has_pendingon TLS sockets, which also correctly detects an orderly TLS shutdown and a TLS record that has only partially arrived. #110402 (Alexey Milovidov). - Queries accelerated by TopK dynamic filtering (
ORDER BY ... LIMIT k) now make fuller use of the query condition cache: the cache is populated even when lazy materialization is applied to the query, and such queries can reuse entries previously written by an ordinary query that had the sameWHEREpredicate. #110507 (Shankar Iyer). - A
LIKE/NOT LIKEpattern without wildcards (%,_) now uses an exact primary key range, so it reads the same number of granules as the equivalent=/!=predicate instead of a wider prefix range. #107077 (Groene AI). - Fix redundant file segment lock contention (a performance regression introduced in 26.1) when reading data through the filesystem cache. #109577 (Kseniia Sumarokova).
- Fixed skip indexes defined on
Tuplesubcolumns not being used when the field is accessed viatupleElement(t, 'name'),tupleElement(t, N), ort.Nwhile the full tuple is also read in the same query (e.g.SELECT *). All of these forms now prune granules the same way as the named subcolumn accesst.name. #110056 (Groene AI). - Fixed slow
ORDER BY ... LIMITqueries onDistributedtables whenprefer_localhost_replicaselects a local replica: the preliminary limit was removed from the local-shard plan, preventing lazy materialization and dynamic top-K filtering. #110136 (Michael Jarrett). - Fixed the text index not being used for the
ILIKEoperator when the index is defined over an expression rather than a bare column (for exampleassumeNotNull(col)with alower(...)preprocessor): such queries were reading all granules instead of using the index. This closes #110350. #110595 (Elmi Ahmadov). - Reduce lock contention in the filesystem cache: queries reading from the cache no longer block on the priority queue lock when updating an entry’s LRU priority. #109065 (Antonio Andelic).
- Text index queries that use a filter-only
postprocessorexpression (for exampleif(..., '', token)) now discard empty tokens up front instead of materializing them row by row, improving performance. #109049 (Elmi Ahmadov). - Reduce lock contention in system log queues, lowering query tail latency on busy clusters. #110539 (Sean Haynes).
- Improved the performance of substring search functions (
position,countSubstrings,multiSearch*,replaceAll,replaceOne, and their case-insensitive and UTF-8 variants) with a non-constant needle by up to 1.5x by using SIMD-backed string searchers on the per-row path instead of a naive implementation. #110580 (Raúl Marín). - Lazy materialization is now applied to
ReplacingMergeTreequeries withFINAL, a filter, and a smallLIMITeven withoutORDER BY. Columns not needed by the filter and theFINALmerge are fetched only for the rows that remain after the limit, which makes such queries much faster when they select wide columns with a selective filter. Controlled byquery_plan_optimize_lazy_materializationandquery_plan_max_limit_for_lazy_materialization. #110722 (Nikolai Kochetov). - Improved async insert performance when deduplication is enabled and one flush is split across multiple partitions: ClickHouse now reuses the computed deduplication hashes across partitions instead of recomputing them for each one. #111150 (Valery Petrov).
Improvement
- Added a setting
input_format_csv_missing_nullable_as_empty_string(disabled by default). When enabled, a missing value of aNullable(String)column in CSV input is read as an emptyStringinstead ofNULL, regardless ofinput_format_csv_empty_as_default. #58225 (kevinyhzou). #107577 (Alexey Milovidov). - Functions
toDateOrNull,toDateTimeOrNullandtoDateTime64OrNullnow accept integer arguments of all native integer types (interpreted the same way as bytoDate,toDateTimeandtoDateTime64, with an optional timezone argument), returningNULLfor values out of range of the result type. For example,toDateTimeOrNull(1583851242, 'Asia/Shanghai')returns2020-03-10 22:40:42andtoDateTimeOrNull(4294967296)returnsNULL. #79791 (Jitendra). - Added an
is_wildcardcolumn to thesystem.grantstable that indicates whether a grant uses wildcard prefix matching (e.g.,GRANT SELECT ON db*.*). Previously, wildcard and exact grants on the same name were indistinguishable insystem.grants. Closes #92835. #98577 (DQ). - Allow Snappy compression in the HTTP interface (
Accept-Encoding: snappy) and add thesnappy_modesetting to choose between the Hadoop Snappy block format and the Snappy framing format for genericfile/urlsnappy I/O. #100752 (Alexey Milovidov). - Support compatibility with the old analyzer under the
analyzer_compatibility_allow_non_aggregate_in_havingsetting. If enabled, non-aggregate conjunctions are moved fromHAVINGtoWHERE. #104232 (Dmitry Novik). - Added a new server setting
memory_worker_rss_speculative_reserve_ratio(default1.0) which makes the global memory tracker speculatively reserve memory on top of the observed RSS when the RSS growth outpaces the tracker’s bookkeeping between samples. With it, allocations getMEMORY_LIMIT_EXCEEDEDearlier, and the kernel OOM-killer is less likely to fire first. Set the ratio to0to disable the speculation. #104976 (Alexey Milovidov). - Added opt-in Prometheus metrics for filesystem cache eviction activity (
filesystem_cache_evictions_total,filesystem_cache_evicted_bytes_total,filesystem_cache_evicted_segment_hits,filesystem_cache_evicted_segment_size_bytes, and their per-user variants labeled withuser_id), exposed per cache viasystem.dimensional_metrics,system.histogram_metrics, and the Prometheus endpoint. They are controlled by the cache disk-config settingsexpose_prometheus_eviction_metricsandexpose_prometheus_eviction_metrics_per_user(both off by default), which can be toggled at runtime viaSYSTEM RELOAD CONFIG. #105020 (Sacheendra Talluri). - Make
EXPLAIN [PLAN] actions=1, compact=1, pretty=1the default. #105036 (Kirill Kopnev). - Bump
delta-kernel-rs(the library behind theDeltaLakeintegration) to v0.23.0. #105861 (Smita Kulkarni). - Add
duandwccommands toclickhouse-disks. They, respectively, print the total size in bytes for a given file or directory, and list the number of bytes, lines, and words in a file. #106268 (Asya Shneerson). - Added a new asynchronous metric
UntrackedMemory(visible insystem.asynchronous_metrics) that reports memory already allocated by threads but not yet accounted in the global memory tracking counter: each thread accumulates small allocations locally and reports them in bulk. This helps explain discrepancies betweenMemoryTrackingand the process’s actual memory usage.MEMORY_LIMIT_EXCEEDEDerror messages now also include the amount of untracked memory, making it easier to understand why a query or the server hit its memory limit. #106386 (Miсhael Stetsyuk). - Upgrade ClickStack (the observability UI) to version 2.28.0. #106406 (Aaron Knudtson).
- Added support for
BFloat16indotProductand improved its performance by batching the SIMD path. #106569 (Nikita Taranov). - Made the settings
max_named_collection_num_to_throw,max_table_num_to_throw,max_replicated_table_num_to_throw,max_view_num_to_throw,max_dictionary_num_to_throw, andmax_database_num_to_throwchangeable without a server restart. #106821 (Maxim Orlovsky). - Support the
REDUCED_REDUNDANCY,STANDARD_IA,ONEZONE_IA,GLACIER_IR, andEXPRESS_ONEZONEvalues (in addition toSTANDARDandINTELLIGENT_TIERING) for thes3_storage_class_namesetting. #107251 (Aditya Kumar). - Added the create-time
materialized_postgresql_use_extended_date_and_time_typessetting for theMaterializedPostgreSQLdatabase engine. By default (enabled), PostgreSQLdate/timestampcolumns are inferred asDate32/DateTime64; setting it to0atCREATE DATABASEtime infers the narrowerDate/DateTimetypes. The setting is not applicable to theMaterializedPostgreSQLtable engine. #107428 (Alexey Milovidov). - The
SOME/ALLarray quantifier (expr OP SOME(array)/expr OP ALL(array)) now also supports the keyword comparison predicatesIS DISTINCT FROMandIS NOT DISTINCT FROM, and the string-search predicatesLIKE,ILIKE,NOT LIKE,NOT ILIKE, andREGEXP, rewritten toarrayExists/arrayAll. #107454 (Alexey Milovidov). - Fixed a memory leak that occurred when opening a SQLite database failed (for example, when the
sqlitetable function or theSQLitedatabase engine is given a path that cannot be opened). #107807 (Alexey Milovidov). - In the Web UI (
play.html), the run shortcut hint now showsCmd+Enteron Mac andCtrl+Enteron other platforms instead of always showingCtrl/Cmd+Enter, and the, +Shift to run allpart of the hint is shown only when there are multiple queries. #107817 (Alexey Milovidov). #108957 (Alexey Milovidov). - The
Aliastable engine now supports reading with parallel replicas when the target table is of theMergeTreefamily. #107830 (Kai Zhu). - Added the
uniq_v2column statistics type — a lightweight alternative to theuniqstatistics, based on theuniqCombined64sketch. #107863 (Han Fei). Deprecated theminmaxcolumn statistics type and changed the default value ofauto_statistics_typestobasic, uniq_v2. #108680 (Han Fei). - AI functions (
aiGenerate,aiEmbed,aiClassify,aiExtract,aiTranslate) now retry transient network failures (connection resets, TLS connect failures, timeouts, unreachable addresses) whenai_function_max_retriesis set, matching the retry behavior of theurltable function. Previously, only provider-side HTTP error responses were retried. #107927 (Alexey Milovidov). INSERTinto aMergeTreetable now honors query cancellation andmax_execution_timewhile writing many parts, instead of potentially running long after being killed. #107929 (Michael Kolupaev).- In the Web UI (
play.html), the Web Terminal icon can now be opened in a new browser tab with a middle-button click or Ctrl/Cmd/Shift+click. #108006 (Alexey Milovidov). - AI SQL generation in the client no longer sends the
temperatureparameter unless it is explicitly set viaai.temperaturein the configuration. This fixes AI SQL generation for models that reject thetemperatureparameter. #108014 (Alexey Milovidov). - Added the
system.masking_policiestable andSHOW MASKING POLICIESintrospection to open-source builds. Masking policies themselves remain a ClickHouse Cloud feature, so the table is empty in open-source builds, but introspection queries no longer fail with an error. #108030 (Alexey Milovidov). - The Keeper-based Kafka consumer now randomizes the order in which it acquires temporary partition locks across replicas, improving fairness of partition distribution and reducing lock contention. Previously, the intended shuffle had no effect. #108033 (Alexey Milovidov).
- Added autocompletion to the Web UI (
play.html), based onsystem.completionsand the WASM-based SQL lexer. #108059 (Alexey Milovidov). clickhouse-clientandclickhouse-localnow show as-you-type autocompletion hints (inline “ghost” text) for the best matching suggestion when the cursor is at the end of the input. The most relevant suggestions (recently used and identifiers already present in the query) are ranked first. Navigate with Up/Down (or Ctrl-Up/Ctrl-Down); accept a single or selected hint with Tab or Right, and accept a selected hint with Enter; Tab also opens the classic completion list. Controlled by the new--hintsoption (on by default; requires--highlight). #108070 (Alexey Milovidov).- Support the
lengthfunction for theQBitdata type — it returns the dimension of the vector as a constant. #108071 (Alexey Milovidov). SupportCASTfrom aQBitto anArray, reconstructing the original vector — the inverse of the existingArraytoQBitconversion. #108072 (Alexey Milovidov). - Requests to REST data lake catalogs (such as OneLake) now include a ClickHouse
User-Agentheader. #108117 (Konstantin Vedernikov). arrayFoldnow respects query cancellation andmax_execution_time. Previously, a fold over a very long array ran entirely inside a single function call and could not be interrupted, soKILL QUERYand time limits were ignored until the fold finished. #108192 (Groene AI).MVTEncodeGeomnow snaps geometry to the integer pixel grid before clipping and clips polygons with thewagyulibrary, so the clipped output is valid (self-intersecting rings are repaired) and edge-aligned, matching PostGISST_AsMVTGeom. #108248 (Saarthak Gupta).- Add per-phase query pre-execution
ProfileEvents:QueryParseMicroseconds,QueryAnalysisMicroseconds,QueryPlanBuildMicrosecondsandQueryPipelineBuildMicroseconds. They expose where time is spent before query execution (parsing, analysis, query plan building, pipeline building) and are available insystem.query_logandsystem.events. #108282 (Jordi Villar). ALTER TABLEoperations that would produce table metadata exceedingmax_query_sizeare now rejected upfront, preventing tables from becoming unloadable by components such as DDL distribution and replica recovery. #108283 (Andrew Kravchuk).- Added
settingsandengine_settingscolumns tosystem.backupsandsystem.backup_log.settingsexposes the backup/restore-specific settings requested for an operation (e.g.,allow_s3_native_copy,deduplicate_files,structure_only), andengine_settingsexposes the settings effectively used by the backup engine’s reader and writer (e.g., the S3 request settings such asallow_native_copy, which may differ from what was requested after merging the endpoint configuration). This makes it possible to see which settings aBACKUP/RESTOREoperation actually ran with. #108334 (Julia Kartseva). - Added a
sourcecolumn tosystem.documentationcontaining the path of the source file where each entity’s documentation is defined. The table now also documents compression codecs, profile events, current metrics, asynchronous metrics, and the system tables themselves (with their columns), and the documentation of settings now includes their type and default value. #108346 (Alexey Milovidov). An empty setting default value is now rendered as empty string instead of empty backticks. #108708 (Alexey Milovidov). - Support asynchronous reads from remote replicas (
async_socket_for_remote) on macOS by implementing the epoll-based polling primitives on top ofkqueue. This lets distributed queries read shards in parallel on macOS instead of serially. #108403 (Raúl Marín). - Support
BFloat16in binary math functions. #108442 (Zhang Yifan). MergeTreecan now read a compressed stream whose blocks use different codecs. This is the read-side prerequisite for adaptive codec selection (#105404). #108592 (Raufs Dunamalijevs).- The automatic value of
max_threadsand similar settings is now shown insystem.settingsasauto(8)instead of'auto(8)'; the surrounding single quotes were a long-standing artifact baked into the value. Cross-version compatibility is preserved: the legacy quoted form is still accepted when parsing settings received from older servers. #108657 (Alexey Milovidov). - Several usability fixes for the
/schemaWeb UI: load the schema on Enter, theme-aware scrollbars, readable table names, consistent per-database grouping of independent tables, no text selection while dragging, and aplay-style authentication form (Credential Management API, URL-supplied credentials with password stripping, and live credential validation). #108724 (Alexey Milovidov). - The text index lazy posting-list apply mode is no longer experimental and can be selected with
text_index_posting_list_apply_mode = 'lazy'withoutallow_experimental_text_index_lazy_apply. The density-threshold setting was renamed fromtext_index_density_thresholdtotext_index_lazy_intersection_density_threshold. #108814 (Anton Popov). - Add a
delta_sharingcatalog type toDataLakeCatalogfor Databricks Delta Sharing’s Iceberg REST endpoint, whose namespaces are flat and which ignores theparentlisting filter. Use it instead ofcatalog_type = 'rest'for such endpoints, whereSHOW TABLESwould otherwise hang. #108865 (Seva Potapov). - Added a new
clickhouse-client/clickhouse-localoption--echo-query-separatorthat prints a custom separator before the formatted echoed query, making it easier to tell the typed query apart from its reformatted echo. Disabled by default. #108888 (David Meng). - Improvements to the database panel of the Web UI: the number of tables is shown in parentheses next to a database name when it is expanded. #108891 (Alexey Milovidov). A refresh button next to an expanded database reloads its list of tables. #108958 (Alexey Milovidov). When the panel is reopened, the previously expanded databases are restored. #108964 (Alexey Milovidov).
- Allow calculating the combined skip-index benefit in
EXPLAIN WHATIF: it shows the data ratio for the intersection of all existing suitable hypothetical indices. #108934 (Yarik Briukhovetskyi). - Fixed the horizontal scroll position of the result table being reset in the Web UI when clicking a link in a cell and returning to the page. #108941 (Alexey Milovidov).
- The
MySQLdatabase engine, table engine, and table function now map MySQL’s spatial column types (LINESTRING,POLYGON,MULTILINESTRING,MULTIPOLYGON, and the genericGEOMETRY) to the corresponding ClickHouse geometric types instead ofString. This is controlled by the newgeometryflag of themysql_datatypes_support_levelsetting, enabled by default.POINTis still always converted toPoint. The genericGEOMETRYcolumn maps to the umbrellaGeometrytype; reading a value whose subtype has no ClickHouse counterpart (MULTIPOINT,GEOMETRYCOLLECTION) throws an exception at read time. #108944 (Alexey Milovidov). - Web UI (
play.html): full keyboard navigation — arrow-key navigation in the database panel and result table, keyboard access to the toolbar buttons, theme switcher, and download menu, and visible focus outlines. #108972 (Alexey Milovidov). - HTTP interface: when credentials are provided both via URL parameters (
user/password) and anAuthorizationheader, the URL parameters now take precedence instead of the request being rejected. This fixes downloading results from the Web UI (play.html) failing withAUTHENTICATION_FAILED(error 516) when the browser has remembered Basic credentials. #108980 (Alexey Milovidov). - Restore
show_data_lake_catalogs_in_system_tablesas the setting that controls onlyDataLakeCatalogvisibility insystem.tables,system.columns, andsystem.completions. Addedshow_remote_databases_in_system_tables, enabled by default, to let users hideMySQLandPostgreSQLdatabases from those system tables separately. #109082 (Pablo Marcos). - Use the precise (closest-representable) float parsing algorithm by default and apply the
precise_float_parsingsetting to input formats (CSV,TSV,JSON,VALUES, …) and numeric literals, not justtoFloat*/CAST. Setprecise_float_parsing = 0for the previous, faster in some cases but less accurate, behavior. Closes #60146. Closes #74647. Closes #68914. #109086 (Raúl Marín). - A query with a single CTE is now formatted with the same newline and indentation as a query with multiple CTEs. Previously
WITH a AS (...)kept the CTE on the same line asWITH, while two or more CTEs putWITHon its own line with each CTE indented. #109092 (Groene AI). - Web UI: when the highlighted completion is the same as the already-typed word, or the same word in a different case (e.g.
HASHoffered for a typedhash), pressing Right/Tab/Enter no longer rewrites the word or gets swallowed by the autocompletion — the key moves the caret or inserts a newline as expected. #109106 (Alexey Milovidov). #109384 (Alexey Milovidov). - Added rainbow parentheses, matched-bracket, matching-identifier, and digit-group highlighting to the Web UI (
play.html), matchingclickhouse-client. #109108 (Alexey Milovidov). - In the Web UI,
TabandShift+Tabnow indent and unindent the selected lines by 4 spaces. #109110 (Alexey Milovidov). - Web UI: highlight the position of a syntax error in the query editor with a red background. The highlight is cleared as soon as the user returns focus to the editor. #109112 (Alexey Milovidov).
clickhouse-compressor --statand default-codec detection for old parts now report corrupted block headers as corruption instead of a misleading end-of-file error. #109157 (Raufs Dunamalijevs).- ClickHouse Keeper now respects the
os_collect_psi_metricssetting and skips PSI metrics collection when it is disabled. #109179 (Maxim Orlovsky). - In the Web UI, when query tabs are shown, the connection parameters (host, user, password) are hidden behind a key button in the top-right corner and shown in a drop-down on demand. #109243 (Alexey Milovidov).
- Web UI: show a single-value result (one row, one column, e.g.
SHOW CREATE TABLE) with full height instead of clamping it to three lines. #109245 (Alexey Milovidov). - In the Web UI, clicking a table in the databases panel with the middle mouse button, with Shift, or with the platform’s new-tab modifier (Cmd on macOS, Ctrl elsewhere) now opens its query in a new Web UI tab. #109246 (Alexey Milovidov).
- Key the query condition cache for remote (object storage)
Parquetfiles by ETag in addition to the path, so that overwriting an object in place no longer serves stale cached results. #109310 (Alexey Milovidov). - In the Web UI, empty strings and NULLs are no longer colorized in the categorical coloring mode. #109342 (Alexey Milovidov).
- Web UI: clicking a table’s icon in the database panel now shows the list of its columns, with type icons, a size bar proportional to the compressed size, and a tooltip with the compressed/uncompressed size and compression ratio. #109346 (Alexey Milovidov).
- Web UI: show the full tab title as a tooltip on hover when it is truncated. #109354 (Alexey Milovidov).
- In the Web UI, middle-clicking a tab’s title (or Ctrl/Shift/Cmd+clicking it) now duplicates the tab. #109357 (Alexey Milovidov).
- Web UI: resize the final progress and query statistics areas uniformly so they do not wrap awkwardly when the browser window is narrow. #109363 (Alexey Milovidov).
- Web UI: selecting a database in the database panel now uses it as the default database for queries run from the editor. #109372 (Alexey Milovidov).
- Support
reinterpretof anArrayof fixed-size elements as aString, the inverse of the existingreinterpretof aString/FixedStringas anArray. #109383 (Alexey Milovidov). - In the Web UI, do not display the per-column color-coding toggles when the result has no more than a single row. #109385 (Alexey Milovidov).
- Allow
CASTbetweenQBittypes that differ in the element type and/or the stride, as long as the dimension stays the same (for exampleCAST(x AS QBit(Float64, N))from aQBit(Float32, N)). Stride-only changes are lossless; element-type changes follow the correspondingArrayconversion semantics (for exampleFloat32toBFloat16may lose precision, andaccurateCast/accurateCastOrNullreject rows that are not exactly representable). #109387 (Alexey Milovidov). - Functions
quantizeBFloat16ToInt8anddequantizeInt8ToBFloat16now also acceptArrayandQBitarguments, applying the Lloyd-Max codec to the whole vector (returningArray/QBitof the corresponding element type), in addition to the existing scalar overloads. #109398 (Alexey Milovidov). - Web UI: the Documentation link now carries the current user name in the URL. #109419 (Alexey Milovidov).
- Support
arraySum,arrayAvg, andarrayProductfor arrays ofBFloat16. #109420 (Alexey Milovidov). - The MySQL-style format specifier
%finparseDateTime/parseDateTime64(and theirOrZero/OrNullvariants) now accepts between 1 and 6 fractional digits, interpreted as left-aligned microseconds like MySQL’sSTR_TO_DATE, instead of requiring exactly 6. Also fixed misalignedPrettyCompacttables in the built-in function documentation examples. #109421 (Alexey Milovidov). - Web UI: query tabs are now persistent — each tab keeps its rendered result (including images and charts) and its running query when you switch away and back, and long queries continue running in the background. Tab titles show a spinner, progress bar, and completion check-mark for their query. #109425 (Alexey Milovidov).
- Web UI: correctly display an error when a query fails after some of its result has already been streamed, instead of showing a client-side
SyntaxError: Unexpected end of JSON input(or, withhttp_write_exception_in_output_format, marking the failed query as successful). #109430 (Alexey Milovidov). - Added pinned columns to the Web UI: a column can be pinned from its header so that it stays visible (stuck to the edge) while the results table is scrolled horizontally. #109439 (Alexey Milovidov).
- In the advanced dashboard (
/dashboard), charts for specific metrics can now be added directly by the metric name as it appears in the source code or documentation, which makes it easier to add multiple metrics during debugging sessions. #109449 (Mikhail Artemenko). - Web UI: fixed the connection settings drop-down closing when selecting text with the mouse and dragging past its border. #109451 (Alexey Milovidov).
- Web UI: hovering over a result table column header now shows the full column name and type as a tooltip, so truncated headers can be read in full. #109463 (Alexey Milovidov). Fixed column header titles being clipped with an ellipsis even when the column was wide enough to show the full title. #110397 (Alexey Milovidov).
- Support SSD cache dictionaries (
SSD_CACHElayout) and theFileLogtable engine on macOS builds. #109493 (Raúl Marín). - Web UI: do not restore tabs with empty queries when the page is opened. #109529 (Alexey Milovidov).
- Fix unreadable as-you-type autocompletion hints and bright colors in the interactive client on terminals whose
TERMdoes not contain256(e.g. Ghostty, kitty, Alacritty, foot): bright colors are now emitted as aixterm bright color codes unconditionally instead of falling back to bold + dark color, which modern terminals render as a dark, hard-to-read color on dark backgrounds. #109622 (Alasdair Brown). - Enable jemalloc per-CPU arenas and allocation profiling on macOS builds. #109684 (Raúl Marín).
- Allow altering some authentication settings of a
OneLakedata lake catalog database withALTER DATABASE ... MODIFY SETTING. #110019 (alesapin). - The
Hiveengine now readsORCfile metadata (min/max indexes, row counts) with ClickHouse’s nativeORCreader instead of the Apache ArrowORCadapter. #110086 (Alexey Milovidov). - Reduced the binary size by ~10.5 MB by executing comparison and arithmetic operations on rarely used mixed type pairs (
Decimalvs integer of a different width, and pairs involvingInt128/UInt128/Int256/UInt256) via a conversion to a common type instead of a dedicated compiled kernel for every combination of types. Same-type pairs, commonly used pairs, and the memory-boundplus/minus/multiplykeep their dedicated kernels; results, result types and exceptional cases are unchanged. #110131 (Alexey Milovidov). - A subquery on the right side of
INwhose single column is an array one dimension deeper than the left argument is now interpreted as the set of the array’s elements (like an array literal or an array-returning function), instead of failing with a confusing type-mismatch error. For example,x IN (SELECT groupArray(x) FROM ...)now works. #110169 (Alexey Milovidov). - Reading from a
SQLitetable engine orsqlitetable function no longer busy-spins a full CPU core when the SQLite database is locked by another connection. The read now idles while waiting for the lock and stays cancellable. #110248 (Groene AI). - Round elapsed time, rate, and ratio values in log and exception messages to three digits, so numbers like
1.345844286 sec.are no longer printed at full precision. #110277 (Alexey Milovidov). - In the Web UI (Play),
BFloat16is now recognized as a floating point number and its columns are right-aligned and colorized accordingly. #110433 (Alexey Milovidov). - Support the
SETTINGSclause for thePostgreSQLtable engine and thepostgresqltable function (for exampleSETTINGS postgresql_connection_pool_size = 50), bringing feature parity with theMySQLengine. #110614 (Alexey Milovidov). SHOW CREATE TABLE(andSHOW CREATE VIEW/SHOW CREATE DICTIONARY) now suggests a similarly-named table in the error message when the requested table does not exist, the same waySELECTqueries do. #110633 (Alexey Milovidov).- Enable the
merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_oncesetting by default: the merge selector now automatically lowers the maximum number of parts to merge at once based on how full the partition is. See #91163. #110726 (Mikhail Artemenko). - Accept PostgreSQL cleanup commands
RESET,UNLISTEN, andDISCARDas no-ops in the PostgreSQL wire protocol instead of failing them with a syntax error. This improves compatibility with drivers such as Skunk that sendRESET ALLandUNLISTEN *during connection setup and cleanup. #110780 (Alexey Milovidov). - Change the default value of the
auto_statistics_typessetting frombasic, uniqtobasic, uniq_v2. #110878 (Han Fei). randomHadamardTransformnow computes an exact, length-preserving transform for any vector length whose largest odd factor is at most 64 (for example3584 = 512 * 7, common in embedding models), extending the previous2^N,2^k * {12, 20}, and2^k * 9families. A full transform of a length that cannot be represented exactly now raises an exception instead of silently zero-padding to a longer vector; passoutput_dimsto compute a truncated projection of an arbitrary length. #111006 (Alexey Milovidov).- Fixed a
LOGICAL_ERRORexception during backup of aReplicateddatabase that is being dropped and recreated concurrently; such backups now fail cleanly withCANNOT_GET_REPLICATED_DATABASE_SNAPSHOT. #100651 (Alexey Milovidov). - Surface the real underlying error when a zip archive cannot be unpacked (for example, when the archive is read from S3 and the read buffer refuses a seek). Previously, the actual error was hidden behind the generic
Couldn't unpack zip archive: Code = -100/Couldn't open zip archivemessage. #105103 (Groene AI). - Fix a confusing “Maybe you meant X?” hint after a server restart (or
DETACH DATABASE/ATTACH DATABASE): dropping an already-dropped table could suggest the just-dropped name as the alternative. #106238 (Groene AI). - Fixed a logical error (
Logical error: 'removed', aborting the server in debug builds) in the background table-drop queue, triggered when the same explicit UUID is reused across severalCREATE OR REPLACE TABLEqueries, which enqueues more than one dropped table sharing that UUID. #107031 (Groene AI). - Fixed an
Inconsistent AST formattinglogical error that could abort the server in debug and sanitizer builds when an aliased lambda was used as the operand of an access operator (tuple element.Nor array element[]) at a non-first position of an expression list, e.g.SELECT 1, ((p0, p1) -> p0 AS a7).4[3] FROM t. #107092 (Groene AI). - A cluster table function (
urlCluster,fileCluster,s3Cluster, …) nested inside another distributed query, such asclusterAllReplicas(..., urlCluster(...)), is now rejected with aBAD_ARGUMENTSerror instead of failing with a logical error (Distributed task iterator is not initialized). #107107 (Groene AI). OPTIMIZE ... DRY RUNinterrupted by a query timeout (max_execution_timewithtimeout_overflow_mode = 'break') now returnsTIMEOUT_EXCEEDEDinstead of a logical error aboutrows_sources(which aborted the server in debug/sanitizer builds). #107114 (Groene AI).- Stop logging a benign
Net Exception: Socket is not connectederror duringZooKeepersession finalize on macOS.clickhouse keeper-clientno longer prints this spurious error to stderr at exit. #107438 (Groene AI). - Fixed a signed integer overflow when a refreshable materialized view retries a failed refresh with
refresh_retriesset to a very large value (nearInt64max). The overflow could abort the server in builds with the undefined behavior sanitizer. #108005 (Groene AI). - Fix a
LOGICAL_ERROR(server abort in debug/sanitizer builds) when aJOINuses the null-safe comparison operator (<=>/IS NOT DISTINCT FROM) and one of the keys is a scalar subquery, e.g.... JOIN t2 ON (SELECT x FROM t1) <=> t2.k, with the old analyzer (enable_analyzer = 0). Such a query now returns a regularNOT_FOUND_COLUMN_IN_BLOCKerror instead of a logical error. #108123 (Groene AI). - Vector search queries that select the
_distancecolumn now return a proper error instead of failing with a logical error. #108423 (Robert Schulze). - Fix a
std::future_error(The associated promise has been destructed prior to the associated state becoming ready) that could surface, and abort the server in debug and sanitizer builds, when scheduling the final asynchronous S3/Azure multipart-upload completion task failed (for example under thread-pool exhaustion). The real scheduling error is now reported instead. #108730 (Groene AI). - Avoid excessive server log output and an oversized error message when compiling a very large regular expression (for example a
LIKEormatchpattern with hundreds of thousands of wildcards); such patterns now fail with a clearCANNOT_COMPILE_REGEXPerror. #108821 (Raúl Marín). - Fixed undefined behaviour when stringifying an out-of-range protocol packet type (e.g. in the
Unexpected packet from server/Received ... packeterror messages) for a desynced or fuzzed connection. #108885 (Groene AI). - Fixed a confusing internal error (
Method getResultType is not supported for TABLE query tree node) when a table expression was used as the left argument of theINoperator; such queries now produce a clear error message. #109412 (Alexey Milovidov). - Fixed reading an Iceberg table with a metadata file whose version number is all digits but exceeds the 32-bit integer range (for example
v99999999999999999999.metadata.json). Such a name previously produced an opaquestd::out_of_range(STD_EXCEPTION) instead of a clearBAD_ARGUMENTSerror. #109619 (Groene AI). - Fixed a possible
Logical error: 'ReadBuffer is canceled. Can't read from it.'when a row-based input format (e.g.TSV/CSV) failed to parse input and the underlying read had already been canceled (for example a malformed HTTP chunk or a truncated body). Building the verbose parse diagnostics no longer reads from a canceled buffer. #109708 (Groene AI). - Row policy filter expressions using
arrayJoin(or itsunnestalias) are now rejected with a clear error; previously such policies raised acolumn->size() == num_rowslogical error at query time. #109753 (Raúl Marín). #109973 (Raúl Marín). - Reading a Paimon table whose schema contains an unsupported nested type (for example a
ROWfield) now reports a clearBAD_ARGUMENTSerror naming the unsupported type, instead of a bareDB::Exception. (OK)with error code 0 and no message. #109762 (Groene AI). - Fixed a
LOGICAL_ERROR(std::length_error) when a query with the experimental settingmake_distributed_plan = 1used a very largedistributed_plan_default_reader_bucket_countordistributed_plan_default_shuffle_join_bucket_count. Such values are now rejected withINVALID_SETTING_VALUE. #109770 (Groene AI). - Fix a
LOGICAL_ERROR(query tree node does not have valid source node) when a recursive CTE resolved an identifier from an outer scope as a correlated column (withallow_experimental_correlated_subqueries = 1). Such queries now return a clearUNSUPPORTED_METHODerror. #109863 (Groene AI). - Fix a signed integer overflow when
ORDER BY ... WITH FILLskips a very large gap over anInt64/UInt64column (e.g. a step of 2 across a gap near 2^63). The overflow was undefined behavior under sanitizers and silently wrapped in release builds. #109937 (Groene AI). - Fix a
Bad cast from type DB::FunctionNode to DB::ConstantNodelogical error (server abort in debug/sanitizer builds) when runningSELECT ... ORDER BY ... WITH FILLagainst aDistributedtable with a lowoptimize_const_name_size. #109938 (Groene AI). - Fixed an
Invalid number of rows in Chunklogical error when anINTERPOLATEtarget is an alias of aWITH FILLcolumn with the old analyzer (enable_analyzer = 0). Such queries are now rejected with a clearINVALID_WITH_FILL_EXPRESSIONerror. #110103 (Groene AI). - Fix a logical error (server abort in debug/sanitizer builds) when the
indexHint/ignore/isZeroOrNullfunctions are given an argument whose type resolves toNothing, e.g. inside expressions likeindexHint(assumeNotNull(materialize(NULL))). #110192 (Groene AI). - Fixed a logical error
Too large size (...) passed to allocatorthat could occur when an out-of-range value was set for a read buffer size setting such asmax_read_buffer_sizeormax_read_buffer_size_local_fs. Such values are now clamped to 256 MiB by the settings sanity check, and additionally at the consumption site forINSERT ... FROM INFILE, which reads files insideclickhouse-clientwhere the sanity check does not apply. #110207 (Alexey Milovidov). CHECK TABLEnow reports the actual corruption for a projection part that failed to load its metadata, instead of a misleadingColumns doesn't match ... Expected: 0 columnserror. #110262 (Raúl Marín).- A type mismatch when a value read from a PostgreSQL source (e.g. the
postgresqltable function or thePostgreSQLtable engine) cannot be parsed into the declared column type (for example atextcolumn declared asInt32) is now reported as a proper query error; previously it aborted the server in debug and sanitizer builds. #110264 (Groene AI). - Support the query profiler, memory and trace profilers, and
system.trace_logsymbolization on macOS. #109825 (Raúl Marín). - Update
chdigto v26.7.1: compressed stack traces for sharing, query patterns, separate-arena memory support, Perfetto improvements, and compatibility fixes. #110938 (Azat Khuzhin). - Fix incorrect monotonicity inference for
intDivon an unsigned key divided by a signed constant, which could disable primary-key index pruning forIN/NOT INpredicates that cross the signed boundary of the result type; debug builds also hit aLOGICAL_ERRORInvalid binary search result in MergeTreeSetIndex. #107586 (Groene AI). - Added the
allow_lossy_numeric_supertypesetting (disabled by default). When enabled,if,multiIf,coalesce,ifNull,array, andmapover numeric arguments that have no lossless common type (for exampleDecimalandFloat64, orInt64andFloat64) resolve toFloat64instead ofVariant, so the result can be used with aggregate functions such assum,avg,min, andmax. Relevant aggregate-function error messages now mention the setting by name. Closes #106707. #107236 (Groene AI). - Start the Prometheus endpoint (for metrics-only configurations) and asynchronous metrics collection before tables are loaded, so metrics are visible during the potentially long metadata loading phase. #108402 (Christoph Wurm).
Bug Fix (user-visible misbehavior in an official stable release)
- Fix
TRUNCATE TABLEandDROP PARTITIONfailing on tables with many deduplication blocks, where removing them in a single ZooKeeper request could exceed the default 1 MBjute.maxbufferlimit. #105991 (Clayton McClure). This only affects you if you use Apache ZooKeeper (not recommended) instead of ClickHouse Keeper. - Fix the usage of qualified column names (
database.table.column) in theWHEREclause of mutations, such asDELETE FROMandALTER TABLE ... UPDATE/DELETE, overMergeTree-family tables; previously such queries failed with a missing-columns error. Closes #71760. #109491 (Mikhail Artemenko). - Fix the query result cache for PromQL queries. The
promqldialect bypassed the non-deterministic-function check and could serve stale results anchored atnow(); the Prometheus HTTP API (/api/v1/query,/api/v1/query_range) never stored cache entries at all. #110887 (Nikita Mikhaylov). - Fix the server failing to start when the
TZenvironment variable is empty. Closes #68920. #68921 (Ardenwick). - Fixed the server failing to start when a
Backupdatabase engine refers to a backup that has become unavailable (for example, when its files were deleted or the underlying storage is inaccessible). The database is now loaded without tables instead of preventing the whole server from starting. #83188 (Vitaly Orlov). - When using background inserts into tables with the
Distributedengine, delays caused by repeated errors when sending data to remote shards now decrease once the errors are resolved. Previously, the delay would only increase and never reset. #87378 (Andrei Kochemirovskii). - Fix
broken_data_filesinsystem.distribution_queueand theBrokenDistributedFilesToInsertmetric always reporting0for broken files discovered when scanning theDistributedasync-insert queue at startup. #92124 (KG.Xu). - Fix recovery of logging after a disk-full error. Previously, when the log disk became full, ClickHouse would enter a failed state and continuously spam error messages to syslog (potentially writing 100+ GB/hour), never recovering even after disk space was freed. Now the logging system automatically recovers once disk space becomes available, without requiring a server restart. #93127 (jaehanbyun).
- Forward static S3 credentials to Unity
DataLakeCatalogtable reads whenvended_credentialsis disabled, preventing anonymous object-storage access failures. #96910 (kgeg401). - Fix a crash in the schema parsing code of the
DeltaLaketable engine. #97112 (Kseniia Sumarokova). - Fix a security issue where an unauthenticated TCP client could probe table existence and replication status via the interserver port. #99854 (Shaohua Wang).
- Fix a syntax error when an alias follows a subquery in
DESCRIBE TABLE. Fixes #100031. #100205 (Yarik Briukhovetskyi). - Fixed an exception in correlated subqueries when outer columns become
Nullableundergroup_by_use_nullswithROLLUP/CUBE. #100365 (Alexey Milovidov). - Fixed a server abort (in sanitizer builds) and silent data loss during table startup when a rolled-back transactional
MergeTreepart intersects a committed part. #100992 (Tuan Pham Anh). - Fixed
indexOfAssumeSortedreturning incorrect results forArray(LowCardinality(String))columns inMergeTreetables. #101771 (Yash ). - Fix incorrect primary-key pruning when a table’s sorting key wraps a
Datecolumn intoDateTime(for example,ORDER BY toDateTime(date_column)) and a query filters on the original column with a comparison likeWHERE date_column >= '...'.toDateTime(Date)overflows forDatevalues beyond theDateTimerange (after2106-02-07), so the stored key is non-monotonic; ClickHouse no longer uses primary key pruning for this key/predicate combination because doing so could drop granules that contain matching rows. Closes #101744. #101814 (Nihal Z. Miaji). - Fixed
intDivOrNull,moduloOrNullandpositiveModuloOrNullreturning0instead ofNULL, andintDivOrNullandintDivOrZeroraising an exception instead of returningNULL/0, when the division leads to a floating-point exception (division by zero orINT_MIN / -1), including for mixed signed/unsigned arguments. #101976 (Yarik Briukhovetskyi). - Fix
LOGICAL_ERRORexceptions when readingIcebergorDeltaLaketables in corner cases such as concurrentIcebergmetadata updates or reads through themergetable function overDeltaLaketables. #102033 (Groene AI). - Fix outbound HTTP requests (e.g. the
aiGeneratefunction, theurltable function, S3) failing withNo route to hoston hosts that advertise both IPv4 and IPv6 addresses when only one address family is routable. The HTTP connection pool now falls back to the next resolved address when the first one fails with a network error, instead of propagating the error on the very first request. #103786 (Alexey Milovidov). - Fix a server abort during
RESTOREof backups containing tables with cyclic dependencies. #103824 (Konstantin Bogdanov). - Schema inference for Arrow
time32/time64columns (e.g.SELECT * FROM file(..., 'Arrow')) now infersTime64instead ofDateTime64; anything downstream relying on the old inferred type will observe the new type after an upgrade. Also,Time/Time64values can now be exported to Arrow with the appropriate Apache Arrow time type selected by precision. Fixes #104038. #104316 (/bin/cat). - Fixed a race between
ALTER TABLE ... RENAME COLUMNand a concurrentOPTIMIZE TABLE ... FINAL(or any background merge) inMergeTreethat could silently replace the renamed column’s data with default values. #104822 (Groene AI). - Fixed a
Block structure mismatchlogical error during a concurrentINSERTwhile anALTER TABLE ... RENAME COLUMNis in flight, in anAtomicdatabase withlazy_load_tables = 1afterDETACH DATABASE/ATTACH DATABASE. #104852 (Groene AI). - Fix
groupConcatwhen the parametric and two-argument spellings are mixed, e.g.groupConcat(',', 2)(x, '/'): the row-limit parameter was silently dropped, so every row was returned instead of the requested number; the delimiter from the second argument now correctly overrides the parameter. #104882 (Yarik Briukhovetskyi). - Fix a
LOGICAL_ERROR(Expected one block from input stream) thrown byKILL QUERY/KILL MUTATION/KILL PART_MOVE_TO_SHARD/KILL TRANSACTIONwhen theirWHEREclause contains a per-row subquery, or whenmax_block_sizeis small enough that the internalSELECTover the relevantsystem.*table emits more than one block. #104927 (Groene AI). - Fixed
CASTfrom smaller to larger interval units returning wrong results (for example,CAST(toIntervalSecond(60) AS IntervalMinute)returned0instead of1). Closes #104986. #105058 (Yarik Briukhovetskyi). - Fix a logical error (
Assertion 'row < chunk.getNumRows()' failed) inLIMIT ... WITH TIESqueries running with the read-in-order pipeline (optimize_read_in_order = 1andread_in_order_use_virtual_row_per_block = 1). #105102 (Groene AI). - Fix a leak in refreshable materialized views (
MATERIALIZED VIEW ... REFRESH ...): the temporary inner table that a refresh rotates out viaEXCHANGE TABLEScould not be dropped if it was larger thanmax_table_size_to_drop, so every subsequent refresh created yet another temporary inner table, growing the view’s data directory until the disk was exhausted. The refresh task’s internal drop now bypassesmax_table_size_to_dropandmax_partition_size_to_drop; those safety nets still apply to user-issuedDROP TABLEof the view itself. Closes #104900. #105106 (Groene AI). - Fix an unexpected
DATA_TYPE_CANNOT_BE_USED_IN_KEYerror onALTERqueries that do not change the sorting key (changing settings, comments, codecs, adding a non-key column, etc.) forMergeTreetables that have aSimpleAggregateFunction(or another type allowed only withallow_suspicious_primary_key = 1) in the sorting key. #105111 (Groene AI). - Fixed a use-after-free when querying
system.clustersreplica-state columns (such asis_active,unsynced_after_recovery,recovery_time) while aReplicateddatabase is being dropped or detached. Also, benign Keeper exceptions swallowed in this code path (the affected database is treated as transiently unavailable and skipped) are now logged at theInformationlevel instead ofError, so they no longer reach clients at the defaultsend_logs_level = 'warning'. #105149 (Groene AI). - Fixed an issue where running multiple statements in
clickhouse-local --ignore-errorwould echo every subsequent statement inside the error message for each lexical error or unmatched-parenthesis error. #105480 (Groene AI). - Fix a rare server crash when refreshable materialized views are dropped or replaced concurrently with their refresh scheduling. #105588 (Groene AI).
- Reject
ALTER TABLE ... DELETEandALTER TABLE ... UPDATEonIcebergtables whose data file format is notParquetwith a clearNOT_IMPLEMENTEDerror instead of crashing the server or silently corrupting the table. #105893 (Groene AI). - Fix wrong results from a view defined with
EXCEPTorINTERSECTwhose operand is aUNIONchain, afterDETACH/ATTACHor a server restart. The formatter was missing parentheses aroundUNIONchildren ofINTERSECT/EXCEPT, so the stored SQL was reparsed with reversed precedence. #105935 (Groene AI). - Fix
JSONdata misdetected asTSKVduring format auto-detection. Closes #100797. #106009 (Pavel Kruglov). - Forbid creating a
minmaxskip index directly onJSONcolumns — it could later fail inserts with aNO_COMMON_TYPEexception when mixed-type arrays were inserted. Create the index on typed subcolumns instead (e.g.INDEX idx json.field TYPE minmax). #106094 (linhaojie). - Fixed a logical error (
Parsed partition value ... doesn't match partition value for an existing part with the same partition ID) thrown byOPTIMIZE TABLE ... PARTITION ...and other queries that resolve a partition value, on tables with aTime-typed partition key. #106202 (Groene AI). - Fix a data part being incorrectly marked as having a broken projection after a lightweight delete leaves no projection part behind — either when the projection is rebuilt with zero output rows or when it is dropped (
lightweight_mutation_projection_mode = 'rebuild'/'drop'). The broken state previously disabled projection optimization for queries on that part. #106273 (Shaohua Wang). - Fixed
removeDirectoryonplainobject storage disks (such ass3_plain) removing all files inside a non-empty directory as if the removal were recursive; removing a non-empty directory now fails withCANNOT_RMDIR, and recursive removal handles the contents explicitly. #106281 (RinChanNOW). - Fixed a logical error (
Part ... doesn't exist) that could abort the server during recovery of a quorumINSERTfrom a Keeper hardware error when the quorum was concurrently marked as failed. #106424 (Alexey Milovidov). - Fix a
LOGICAL_ERRORexception about duplicate column names when applying row policies. #106438 (János Benjamin Antal). - Fix
CREATE OR REPLACE TABLEandREPLACE TABLEleaving a stranded_tmp_replace_*table on disk and replacing the original table with an empty one when the existing target exceedsmax_table_size_to_drop. The size check now runs before the swap, so a violation aborts cleanly with the user-visible table name in the error. #106782 (Groene AI). - Fix
JSON_QUERY/JSON_VALUE/JSON_EXISTSreturningDynamicinstead ofString/UInt8onDynamicarguments. Closes #106461. #106877 (Pavel Kruglov). - Fixed wrong results when querying a
ReplacingMergeTreetable withFINALand a filter on a text index whilequery_plan_optimize_lazy_finalwas enabled. The lazyFINALoptimization built reading steps that did not reproduce the direct read from the text index, so the filter dropped all matching rows. #106894 (Jimmy Aguilar Mena). - Apply
query_masking_rulesto messages appended to exceptions, so URL-encoded credentials in(in file/uri ...)suffixes of errors from thejdbc/odbctable functions are not leaked when masking rules are configured. #106916 (Gaurav Dubey). - Fixed parts being marked as broken and detached on any part reload (server restart,
DETACH/ATTACH) for tables with aLowCardinality(Nullable(...))column in the partition key. Since 26.5, the per-part minmax index file was not written when such a column’s minimum and maximum wereNULL, while the part consistency check still required the file. Parts written by affected versions lack the minmax index file and still need to be re-attached manually. Closes #106837. #106945 (Pedro Ferreira). - Fix a
LOGICAL_ERROR(Unexpected expression in JOIN ON section. Expected boolean (UInt8), got 'Nothing') when a non-equiJOIN ... ONpredicate references aNothing-typed column, such as one produced byARRAY JOIN []. #106981 (Groene AI). - Fix a rare
LOGICAL_ERROR(Attempt to release query context that does not exist) and the accompanying server crash when readingMergeTreetables through a filesystem cache disk created withenable_filesystem_query_cache_limit = 1. #107028 (Groene AI). - Fix a server crash when moving an empty part to a
plain_rewritabledisk (for example, withALTER TABLE ... MOVE PARTITION ... TO DISKfor an empty part kept byremove_empty_parts = 0). #107040 (Groene AI). - Fix incorrect row order in
ORDER BYqueries overUNION ALLwithoptimize_read_in_orderandread_in_order_use_virtual_rowenabled. Closes #106879. #107053 (Vladimir Cherkasov). - Fixed a
LOGICAL_ERROR(Unsupported argument types) in thegeohashesInBoxfunction when its coordinate arguments mixed constant and non-constant values, or when a coordinate was aBFloat16. Mixed const/non-constFloat32arguments now work, andBFloat16arguments are rejected with a clear error. #107063 (Groene AI). - Fixed wrong results (duplicate rows) for
SELECT DISTINCTover aGROUP BYwithWITH CUBE,WITH ROLLUP, orGROUPING SETSon the same keys. Thequery_plan_remove_redundant_distinctoptimization no longer removes theDISTINCTin these cases, because the grouping modifiers emit extra rows with the key columns defaulted, which can collide with real group values. #107072 (Groene AI). - Fix a wrong result in an
OUTER JOINwhen theWHEREfilter is a conjunction that contains a constant term (for examplep AND 1, orWHERE p QUALIFY NULLwhere theQUALIFY NULLis merged intoWHERE). The constant conjunct could be pushed into the non-preserved side of the join and removed from the post-join filter, so the join produced non-matched rows with the side columns defaulted, and those rows incorrectly passed the filter. #107084 (Groene AI). - Fixed
executable_pooluser-defined functions configured with<lifetime>not picking up changes to the underlying script. Previously, onlySYSTEM RELOAD FUNCTIONSwould re-read an edited script; periodic<lifetime>reloads kept executing the old version. #107087 (Groene AI). - Fix a
LOGICAL_ERRORexception (Cannot find input column ... on its position in inputs of expression actions DAG) for a correlated scalar subquery over a source projecting the same column identifier twice (e.g.SELECT number, *) whencorrelated_subqueries_default_join_kind = 'left'. #107112 (Groene AI). - Fixed a data race on the server-global trace collector between a worker thread starting its profiler and server shutdown. #107307 (Groene AI).
- Incremental backups no longer store
S3credentials in the<base_backup>locator of the.backupmetadata file. Backups created withuse_same_s3_credentials_for_base_backup = 1, or with explicit base backup credentials matching this backup locator, store a non-secret marker and are restored without extra restore-time settings; for backups created with different explicit base backup credentials or extra base authentication arguments, pass them toRESTOREwith thebase_backupsetting. Backups created by older versions with embedded credentials remain restorable. #107357 (Pablo Marcos). - Fixed the
CSVWithNamesandCSVWithNamesAndTypesheader having fewer columns than the data whenoutput_format_csv_serialize_tuple_into_separate_columnsis enabled (the default). The header (and the types row) now flattensTuplecolumns into their leaf fields with dotted names (e.g.t.a,t.b), so the header column count matches the data. A new settingoutput_format_csv_header_serialize_tuple_into_separate_columns(default1) controls this and can be set to0to restore the previous single-name header. #107371 (Groene AI). - Fixed reading
Icebergv3 tables whoseParquetdata files contain reserved row-lineage columns (such as_row_id); the nativeParquetreader no longer raisesICEBERG_SPECIFICATION_VIOLATIONfor reserved field IDs that are not part of the table schema. #107377 (Greg Maher). - Fixed a rare server abort during shutdown (
std::future_error:The associated promise has been destructed prior to the associated state becoming ready) caused by a scheduled task being dropped from a thread pool queue before it ran. #107383 (Groene AI). - Fix the
MaterializedPostgreSQLtable and database engines so that a single table or database can be replicated from a non-default PostgreSQL schema (materialized_postgresql_schema), including the case where tables with the same name exist in several schemas of the same database (previously they would share a publication and replication slot and cross-talk). #107425 (Alexey Milovidov). - Fix
MaterializedPostgreSQLstopping replication of an entire database (withLOGICAL_ERROR: Columns number mismatch) when a single replicated table’s structure changed while the server was down. Now only the affected table is skipped and can be recovered withDETACH/ATTACH. #107427 (Alexey Milovidov). BACKUPof aMaterializedPostgreSQLdatabase no longer hangs forever withTable ... were created or changed its definition during scanning, and now actually backs up the table data (delegated to the underlyingReplacingMergeTree), which can be restored as a standaloneReplacingMergeTree. #107433 (Alexey Milovidov).- Fixed a regression where setting
compatibility = '26.6'(which implicitly enables thehivepartition strategy) silently accepted{_partition_id}in S3/object storage table paths instead of raisingBAD_ARGUMENTS. #107437 (Lefteris). - Fixed a memory leak in the bundled
mongo-c-driverthat could occur when reading from MongoDB (for example, via a MongoDB dictionary or themongodbtable function) if a retryable read error was followed by a failed retry server selection. #107448 (Groene AI). - Fix an exception when inserting into an
Icebergtable whose metadata was created by an external engine and omits the optionalsnapshots,metadata-log, orsnapshot-logarrays. Such inserts now succeed instead of failing. #107473 (Shaohua Wang). - Fixed
DELETE FROM(lightweight delete) requiring theALTER UPDATEprivilege in addition toALTER DELETE. A user granted onlyALTER DELETEcan now runDELETE FROM, as documented. #107491 (Shaohua Wang). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKwhen reading Hive-partitioned files withuse_hive_partitioning = 1and aWHERE/PREWHEREclause that filters a real (non-virtual) column while a Hive partition column is also selected. #107505 (Groene AI). - Fix a
LOGICAL_ERROR(Different order of columns in UNION subquery) when the old analyzer (enable_analyzer = 0) reads a subset of columns from a subquery whoseUNIONchildren areINTERSECT/EXCEPTset operations. #107511 (Groene AI). - Fix
NULLvalues being silently converted to empty strings when insertingArrow/ORCdata into aLowCardinality(Nullable(...))column. This was a regression introduced in 26.5. #107532 (Jimmy Aguilar Mena). - Fix a logical error (
Stream ... variant_discr ... is not found) that could occur when merging or reading aMergeTreepart produced by a mutation of a table with aDynamiccolumn. #107562 (Alexey Milovidov). - Fixed a logical error (
WhichDataType(const_type).isArray()) during primary-key analysis whenpointInPolygonis called with a constant polygon argument of a wrapper type such asVariantorDynamic(for example,pointInPolygon((x, y), if(c, [(0, 0), ...], NULL))). #107589 (Groene AI). - Fixed a logical error (
Last stored last_written_position in meta file ... is bigger than current last_written_pos) in theFileLogengine that could happen when a watched file was deleted and recreated reusing the same inode. #107617 (Groene AI). - Fix a rare server abort (
std::future_error:The associated promise has been destructed prior to the associated state becoming ready) during ZooKeeper client request processing, when an asynchronous Keeper request was dropped while being sent, for example under memory pressure. #107647 (Groene AI). - Fixed
RESTOREforReplicatedMergeTreetables so duplicate-content parts from a backup are preserved instead of being silently deduplicated. #107652 (Pablo Marcos). - Fix runtime join filter producing wrong results for
JSONcolumns. Closes #107646. #107663 (Pavel Kruglov). - Fixed incorrect results from distributed queries selecting
ALIAScolumns that share a common subexpression: columns could be misaligned and values returned under the wrong column. #107675 (Vladimir Cherkasov). - Quotas keyed by
normalized_query_hashnow account all resources (read_rows,read_bytes,result_rows,result_bytes,execution_time,written_bytes,errors) per query pattern, like the query-count counters, instead of accounting them against a single shared per-user bucket. #107681 (Alexey Milovidov). - Fixed a
Block structure mismatch in UnionStep streamlogical error (server abort on debug/sanitizer builds,Code: 49on release builds) that occurred when sibling branches of aUNION/INTERSECT/EXCEPTdiffered only in theirWHEREpredicate and one branch’s predicate was constant-folded to aConstcolumn. #107719 (Groene AI). - Fix logical errors (
Bad cast) caused by inconsistent stripping ofLowCardinalitynested insideVariantandDynamiccolumns, for example inconcat,format, and primary key analysis. Closes #107598. #107773 (Pavel Kruglov). - Fixed a severe work-distribution skew with parallel replicas when the cluster contains inactive replicas (for example, stale entries left after autoscaling). Such replicas are no longer counted by the reading coordinator, so work is balanced across the online replicas instead of piling onto a single one. #107805 (Alexey Milovidov).
- Fix the
Not-ready Set is passed as the second argumentexception that could occur when building anINsubquery set during primary key analysis failed silently (for example, a subquery timeout withoverflow_mode = 'break'), leaving the set permanently unbuilt for the query pipeline. #107924 (Alexey Milovidov). - Fix a server crash in predicate pushdown (
enable_optimize_predicate_expression, legacy analyzer) when aUNIONsubquery appears inside aJOIN ... ONcondition. #107930 (Groene AI). - Fix spurious
CHECKSUM_DOESNT_MATCHandParquetread errors (and, for some formats, silently wrong results) when an S3 or S3-compatible (e.g. GCS) object is overwritten in place while being read. Such reads now fail with a clear, retryable error instead of returning data stitched from two object versions; controlled by the new settings3_validate_etag_on_read(on by default). #107934 (Shaohua Wang). - Fixed a
SELECTfailing withNOT_FOUND_COLUMN_IN_BLOCKon a table that has asetdata-skipping index when a row policy filters it using an always-true condition combined with a check on a non-indexed column. #107971 (Shaohua Wang). - Fixed executable user-defined function command parameter parsing so placeholders with empty or invalid names are not accepted as parameters. #107983 (Goutam Adwant).
- Fix performance regression for
Mapsubcolumns withPREWHERE. Closes #107912. Caused by #99200. #107988 (Pavel Kruglov). - Fix an out-of-bounds write when reading a
Variantcolumn from a malformedNativeblock whose discriminators reference a variant index that does not exist. #107991 (uwezkhan). - Fix wrong query results from incorrect primary key and partition pruning when
toStartOfDay,toStartOfISOYear,toDaysSinceYearZero,toRelativeSecondNum,toRelativeMinuteNum,toRelativeHourNum,toRelativeWeekNum,toRelativeDayNum,toMonthNumSinceEpoch, ortoYearNumSinceEpochis applied to aDate32key column containing dates outside the range the function can represent (in particular dates before1970-01-01). These functions report themselves as monotonic to the primary index, but previously wrapped around for such arguments, so the index could prune granules that actually contained matching rows; they now saturate at the bounds of their result type and stay monotonic over the wholeDate32range. #108018 (Nihal Z. Miaji). - Fix
accurateCastOrNullof aTuplewhose element isDynamic/Variant: a genuine sourceNULLwas treated as a conversion failure. For aNullabletarget element a sourceNULLnow stays an elementNULL(matching a plainTuple(Nullable(...))source); for a non-Nullabletarget element a sourceNULLnow nulls the whole tuple instead of producing the element default; parse/overflow failures still null the whole tuple. #108023 (Groene AI). Also fix a logical error when casting aDynamicorVariantcolumn nested inside aTupleto a non-Nullableelement type withaccurateCastOrNulloraccurateCastOrDefault. #108061 (Alexey Milovidov). - Fixed
numericIndexedVectorPointwiseMultiplyreturning an empty result when multiplying by an all-ones vector that has a different BSI (bit-sliced index) configuration. #108027 (Alexey Milovidov). - Fixed
toTime64andCAST(... AS Time64)not clamping out-of-range values to theTime64range insaturateandignoreoverflow modes, which could produce values that display identically but compare as different. #108028 (Alexey Milovidov). getClientHTTPHeaderis now correctly treated as non-deterministic, so its result is no longer incorrectly reused by the query result cache. #108029 (Alexey Milovidov).clickhouse-client --port 9440again automatically enables a secure (TLS) connection; this was broken by a refactoring that stopped passing the port to the secure-connection check. #108032 (Alexey Milovidov).- A transient error while refreshing data parts of a read-only table no longer permanently stops the background refresh task. #108034 (Alexey Milovidov).
- Fixed memory/CPU/mutation overload warnings in
system.warningslagging one asynchronous-metrics cycle behind (and being absent on the first cycle). #108035 (Alexey Milovidov). - The
mongodbtable function now acceptsoid_columnspassed as a named argument (e.g.oid_columns='_id'), instead of rejecting it withBAD_ARGUMENTS. #108039 (Alexey Milovidov). - Fix a
Bad cast from type DB::ColumnNullable to DB::ColumnVector<...>exception (logical error) when a qualified asterisk (t.*) selects aJOIN USINGkey and that join is nested below aPASTE/CROSS/comma join or an outerONjoin, withjoin_use_nulls = 0. #108043 (Groene AI). - Fixed incorrect handling of zero-width assertions (
\b,^,$) in the regexp “match all” functionsextractAll,extractAllGroupsVertical,extractAllGroupsHorizontal,countMatchesandsplitByRegexp. For example,extractAll('new york is the greatest', '\b(\w)')now correctly returns the first letter of each word instead of every letter. #108047 (Alexey Milovidov). - Fixed
CREATE TABLE ... AS SELECTonAtomicdatabases leaving an empty table behind when the query fails — for example when the user has no access to a table referenced from a subquery. Previously a retry reported that the table already exists instead of the original error. The table is now created via a temporary table and becomes visible only after it has been fully populated. #108048 (Alexey Milovidov). - Allow querying a
range_hashedorcomplex_key_range_hasheddictionary that uses aDateTime64,Decimalor floating-point range with a matching argument todictGet/dictHas. Previously such queries failed withmust be convertible to Int64, and open-ended intervals ofDecimal/DateTime64ranges incorrectly returned the default value. #108052 (Alexey Milovidov). - Fixed an exception (
CANNOT_PARSE_TEXT) when loading a dictionary with a composite key whose key columns are not the first columns in the dictionary definition, with a localClickHousesource using an explicit query. Source columns are now matched to the dictionary structure by name instead of by position. #108053 (Alexey Milovidov). - Fixed the
valuestable function failing withARGUMENT_OUT_OF_BOUNDwhen a decimal literal that is not exactly representable in a narrow floating-point column (such as0.1for aFloat32column) is used, e.g.SELECT * FROM values('x Float32', 0.1). Such values are now accepted and converted to the nearest representable value, consistent withCASTandINSERT ... VALUES. #108055 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR(No available columns) when executingSELECT count()(or other trivial queries) on a table where the user is grantedSELECTaccess only on anALIAScolumn. #108056 (Alexey Milovidov). - Fixed
mapFilter,mapSort(and its variants) andmapConcatdroppingLowCardinalityfrom the key and value types of aMap. PreviouslymapFilterover aMap(LowCardinality(String), String)column returnedMap(String, String), which could corrupt the metadata of a table created viaCREATE TABLE ... AS SELECTand makeCHECK TABLEfail. #108057 (Alexey Milovidov). - Fix incorrect results when using
hasTokenon text indexes with a tokenizer other thansplitByNonAlpha. #108066 (Robert Schulze). - Fixed a freeze of
SYSTEM RELOAD DICTIONARIES(andRELOAD DICTIONARY) when many MySQL dictionaries defined in XML shared a single connection pool viashare_connection. Such pools now honorconnection_pool_sizeandconnection_wait_timeout(default 5 seconds) from the configuration, matching dictionaries defined through named collections. #108083 (Alexey Milovidov). - Allow
EXISTS <dictionary>for a user that has only theSHOW DICTIONARIESprivilege on the dictionary (previously it requiredSHOW TABLES). #108084 (Alexey Milovidov). - Fixed
CREATE TABLE dst AS src SETTINGS ...(and similar variants withORDER BY/PARTITION BYbut without an explicitENGINE) silently dropping the source table’s engine, storage clauses (such as tableTTLand keys) and settings. The engine and the non-overridden storage clauses are now inherited from the source table, and the specified settings are merged on top of the source table’s settings. #108085 (Alexey Milovidov). - Fixed
INSERTintoMergeTreetables failing withfilesystem error: in rename: Permission deniedon filesystems backed by Windows (WSL, CIFS/SMB, Docker Desktop bind mounts), caused by the part writer leaving file descriptors open across the part-directory rename. #108089 (Alexey Milovidov). - Fixed a crash (null pointer dereference) when querying a
Hivetable without aWHEREclause, e.g.SELECT * FROM hive_table. #108094 (Alexey Milovidov). - Fix a
LOGICAL_ERROR(“Unexpected return type from if”) when reading a column underapply_mutations_on_fly = 1after anALTER UPDATE col = ... WHERE <cond>with a non-constant or false condition followed byALTER MODIFY COLUMN col <new type>. #108128 (Groene AI). - Fix
toStartOfIntervalanddateTruncreturning a rounded value instead of the start of the containing interval when the input has finer precision than the interval unit, e.g.toStartOfInterval(toDateTime64('2023-10-09 10:11:12.000999', 6), INTERVAL 1 millisecond)returned10:11:12.001instead of10:11:12.000. The overload with an explicit origin was affected too. Closes #103535. #108186 (Yarik Briukhovetskyi). - Hide sensitive information in the
view_querycolumn ofsystem.query_views_log. #108214 (Valerii Mordovskii). - Fixed a wedge on a
MergeTreetable attached with a legacyhypothesisskip index (a removed index type kept only forATTACHcompatibility). Previously a lightweightDELETE,OPTIMIZE, a plainINSERT, or a filteredSELECTon such a table failed withILLEGAL_INDEX(“Index of type ‘hypothesis’ is no longer supported”), and theDELETEmutation retried forever. The dead index is now treated as inert: it is carried forward untouched during merge/mutation, skipped on insert and query planning, and can still be dropped withALTER TABLE ... DROP INDEX. #108217 (Groene AI). - Fix the setting
type_json_allow_duplicated_key_with_literal_and_nested_objectnot working with typed paths inJSON. #108218 (Pavel Kruglov). - Fix a
LOGICAL_ERROR(Different list of shards in child plans) when running a query withmake_distributed_plan = 1over aMergeTreetable that has a normal/aggregate projection. #108256 (Groene AI). - Fixed
replaceRegexpOneandreplaceRegexpAllso.matches newline characters by default, consistently with other regular expression functions. #108265 (linjiayu1025-collab). - Fix a logical error when casting an
Array(Dynamic)orArray(Variant)toQBitwithaccurateCastOrNull, e.g.accurateCastOrNull(CAST(range(114), 'Array(Dynamic)'), 'QBit(Float32, 114)'). #108288 (Groene AI). index_granularity_bytesis now honored forAggregateFunctionstate columns. Previously the granule byte cap was ignored for such columns (for exampleuniqExactstates inAggregatingMergeTreetables and aggregating projections), producing granules far larger than the configured limit and increasing read amplification and query-time memory. #108297 (Groene AI).- Fix lightweight
UPDATE/DELETEconditions being evaluated twice, which could lead to incorrect behavior for non-deterministic conditions and extra work for deterministic ones. Closes #86032. #108323 (ofeliacode). - Fix an exception in a predefined HTTP handler when a header whose
headers_regexpregular expression allows an empty value is absent from the request. #108324 (Vitaly Baranov). - Fix
arrayPartialSortwith a non-constant limit argument. #108327 (Vitaly Baranov). - Fixed a cancelled or
KILLedINSERTcontinuing to run for a long time while building a skip index (for example an unboundedset(0)index on a high-cardinality column). The index build now stops promptly when the query is cancelled. #108351 (Shaohua Wang). - Fixed a
SELECTfrom theprimestable function not responding to cancellation: with a largestep(orlimit) the query could keep running for a long time afterKILL QUERYor a timeout. It now stops promptly. #108353 (Shaohua Wang). - Fixed parsing of data-type names whose name contains the substring
INT(for example a function-like name such asquantileInterpolatedWeightedused in a data-type position). Such names were mistaken for MySQL integer types and had their first(...)argument group silently consumed as a display-width modifier, which could break the query formatting round-trip. #108354 (Groene AI). - Fixed an inconsistency where a malformed
ARRAY JOINfollowed by a comma and a parenthesized table list was misparsed as a cross join instead of being rejected. #108365 (Raúl Marín). - Hide secret arguments of functions such as
encrypt,decrypt, andHMACinEXPLAIN actions,EXPLAIN header, andEXPLAIN PIPELINEoutput whenformat_display_secrets_in_show_and_selectis disabled (the default). #108386 (Raúl Marín). - Fix
CREATE OR REPLACEof a refreshable materialized view with aTOtarget: it was incorrectly rejected because the target table is already owned by the view being replaced. #108392 (Nikolay Degterinsky). - Fixed a server crash (
Received signal 4, illegal instruction) that could be triggered by a malformed or desynchronized native TCP protocol stream. The client-supplied initial address is now validated to be a numerichost:portbefore it is parsed, instead of letting a non-numeric port reach the trappedgetservbynamelibc function. #108410 (Groene AI). - Fixed a server crash during shutdown when shutting down a database throws an exception (for example when a table’s flush hits a ZooKeeper timeout). The rest of the shutdown sequence is no longer skipped, so system logs are flushed and their threads are joined before the server exits. #108417 (Groene AI).
- Fixed regular expression functions (
match,extract,extractAll,replaceRegexpOne,replaceRegexpAll, etc.) silently returning wrong results when the pattern contained a NUL (\0) byte. The NUL is now treated as an ordinary literal byte, consistent with RE2. #108427 (Alexey Milovidov). - Fixed
clickhouse-localreturning an empty reply to HTTPOPTIONSrequests when nohttp_options_responseis configured, which made the web UI (/play) show the connection as broken even though queries worked. #108428 (Alexey Milovidov). - Fix a
LOGICAL_ERROR(“Invalid action query tree node …”) exception when a distributed query both deduplicated structurally-identical duplicate-ALIAScolumns and referenced a table function with akey = valuenamed-collection argument (for exampleoss(s3_conn, filename = '...')). #108435 (Groene AI). - Fixed a server crash (
LOGICAL_ERROR: 'Unexpected exception in refresh scheduling') that could happen on startup when a coordinated refreshable materialized view in aReplicateddatabase was attached on a Keeper that does not support theMULTI_READfeature flag (for example after a Keeper downgrade). The view is now stopped gracefully instead of aborting the server. #108441 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKerror (e.g.Column _part not found) when selecting virtual columns from aMergeTreetable under parallel replicas, including viaSELECT *withasterisk_include_virtual_columns = 1. #108451 (Groene AI). SYSTEM RESET DDL WORKERnow requires the newSYSTEM RESET DDL WORKERprivilege. Previously any authenticated user (includingreadonlyones) could run it and repeatedly reset the DDL worker state, blockingON CLUSTERDDL. #108460 (Groene AI).- Restrict the model path of
catboostEvaluateto theuser_filesdirectory, like thefiletable function and the dictionary sources. Previously the function accepted an arbitrary filesystem path with no containment check, which allowed probing the existence of and triggering reads of files outsideuser_files. Models must now be located insideuser_files. #108463 (Groene AI). - The
hasColumnInTablefunction now requires theSHOW COLUMNSprivilege on the target table, the same grant required byDESCRIBEandSHOW CREATE TABLE. Previously any user could callhasColumnInTableto probe column names and test table and database existence without any access check. #108464 (Groene AI). - Fixed excessive memory allocation when deserializing crafted aggregate function states for
mannWhitneyUTest,rankCorr,largestTriangleThreeBuckets,quantileGK,sequenceMatch/sequenceCountandgroupArrayIntersect. A malformed state could declare a huge element count and make the server try to allocate tens of gigabytes from a few bytes of input; such states are now rejected withTOO_LARGE_ARRAY_SIZE. #108465 (Groene AI). - Validate the redirect target of an S3
301 Moved Permanentlyresponse againstremote_url_allow_hosts(RemoteHostFilter). Previously the AWS SDK 301 handling followed the attacker-supplied endpoint from the response (Locationheader or<Endpoint>element) without the host check, so a malicious or compromised S3-compatible server could redirect ClickHouse to an arbitrary host (SSRF). The 307 redirect path already performed this check; both paths are now consistent. #108466 (Groene AI). - Fixed a credential leak where the legacy
storage_aws_access_key_id,storage_aws_secret_access_key,storage_catalog_credential, andstorage_auth_headersettings of theDataLakeCatalogdatabase engine were shown in plaintext insystem.databases.engine_fullandSHOW CREATE DATABASE. They are now redacted as[HIDDEN]. #108470 (Groene AI). - Fixed
ssl_certificateuser identification so a single*wildcard matches exactly one name component (RFC 6125 6.4.3). Previously a wildcard in aCNorDNS:SAN subject (for example*.corp.example.com) also matched multi-label names such asevil.deep.corp.example.com, letting a holder of a certificate for a deeper subdomain authenticate as the wildcard user.URI:SAN matching is unchanged. #108472 (Groene AI). - Fixed SQL injection in the MySQL wire protocol: the
SHOW TABLE STATUS LIKEargument and theSET <mysql_setting>value sent over the MySQL interface (port 9004) are now parsed and re-quoted instead of being concatenated verbatim into the rewritten query. Also fixedKILL QUERY <id>over the MySQL interface silently ignoring multi-digit connection ids. #108474 (Groene AI). - Sensitive values passed as HTTP query-string parameters (for example the
param_*query-parameter binding such asparam_secret_key/param_aws_secret_access_key, thepasswordparameter, or S3-stylesignatureparameters) are no longer written verbatim tosystem.text_logor OpenTelemetry spans. TheRequest URIlog line now redacts the values of parameters whose names look sensitive, replacing them with[HIDDEN]. #108475 (Groene AI). - Enforce the
http_forbid_headersconfiguration during schema inference for theurltable function andURLstorage engine. Previously a forbidden header was still sent over the network while inferring the schema (for example with theRegexpformat orDESCRIBE), and its response body could be reflected back in a parse error, leaking secrets. The header filter is now checked before any network access on the inference path, matching the existing behavior ofurlCluster. #108476 (Groene AI). - Fixed wrong results when using
SELECT ... SAMPLE ...together with the query condition cache (settinguse_query_condition_cache, enabled by default). #108488 (Groene AI). - Fixed a server crash (stack overflow) caused by deeply nested expressions such as
[[[ ... ]]]orarray(array( ... ))whenmax_parser_depthis set to a large value. #108493 (Raúl Marín). - Fixed the
RabbitMQtable engine hanging indefinitely onDROP TABLEor server shutdown when the broker closes the AMQP connection due to missed heartbeats without sending a TCP RST. All blocking event loop calls now have a 30-second timeout so shutdown always completes. #108497 (Aly Ayman). - Secondary queries executed as part of internal queries will now be logged as internal queries. #108506 (Miсhael Stetsyuk).
- The
ArrowFlighttable engine and thearrowFlighttable function now honor the<remote_url_allow_hosts>allow-list. Previously, the connection host and port were not validated, so a query could reach hosts not present in the allow-list. #108507 (Groene AI). - The MySQL wire protocol commands
COM_FIELD_LIST(mysql_list_fields) andCOM_INIT_DB(USE database) now enforce the same access control as their SQL equivalents (SHOW COLUMNS/DESCRIBEandUSE). Previously, they could disclose column names of tables the user only had partial column grants on, and switch the current database without theSHOW DATABASESprivilege. #108508 (Groene AI). - Match
http_forbid_headerscase-insensitively. HTTP header names are case-insensitive, so forbiddingAuthorizationnow also blocksauthorization,AUTHORIZATION, and other case variants. Configuredheader_regexppatterns are now matched case-insensitively without needing an explicit(?i)flag. #108509 (Groene AI). - Fixed a server crash (segmentation fault) that could occur when a distributed query referenced a not-yet-materialized
MATERIALIZEDCTE as an external table and the remote source was created lazily. #108547 (Groene AI). - Fixed wrong results when the query condition cache (
use_query_condition_cache = 1) reused a skip-index-derived mark exclusion for a query that ran a different set of skip indexes, for example withuse_skip_indexes = 0,ignore_data_skipping_indices, or a differentuse_skip_indexes_for_disjunctionsmode. Skip-index-derived cache entries are now keyed by the effective set of skip indexes that ran. #108548 (Groene AI). - Fixed several bugs in
changeYear,changeMonth,changeDay,changeHour,changeMinuteandchangeSecondwithDateTime64arguments: the result column was created with the hardcoded default scale 3 instead of the argument’s scale, which led to aLOGICAL_ERROR(writeSlice expects same column types) when the result was passed toarrayPushBack/arrayPushFront/arrayConcat; nanosecond-precision (scale 9) inputs threwDECIMAL_OVERFLOW; and pre-epoch sub-second inputs returned the wrong calendar second. Also fixedtimeSlotsoverDateTime64ignoring the scale of the optionalSizeargument in its declared return type and returning wrong timestamps for the largest scale inSize. #108551 (Groene AI). #108681 (Takumi Hara). #108994 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKerror when a compound predicate is aliased inGROUP BYand referenced again, withenable_identifier_resolve_cacheenabled (the default). #108553 (Groene AI). - Fix a logical error (
Equal values are not contiguous within the range assumed to be sorted) when runningDISTINCTover aSTREAMread (SELECT DISTINCT ... FROM table STREAM). Read-in-order optimizations are no longer applied toSTREAMreads, which produce rows in commit order rather than sorting-key order. #108568 (Groene AI). - Fixed projections returning a column’s type default (e.g.
0) instead of its declaredDEFAULTvalue (e.g.-1) in two cases: when reading a column that was added withALTER TABLE ... ADD COLUMN ... DEFAULTafter the projection was created (reads from the base table were already correct), and after the column’sTTLexpired on a wide part. #108569 (Shaohua Wang). #109013 (Shaohua Wang). - Fixed a
ReadBuffer is canceled. Can't read from it.error that could occur when an upload to S3 (for example a backup) is retried after a transient read error. #108573 (Groene AI). - Fix
ATTACH PARTITION ... FROMrejecting tables whose primary keys are equivalent but declared differently (one explicitPRIMARY KEY, the other implicit fromORDER BY). #108590 (Jordi Orihuela). - Fixed direct read from the text index failing when multiple text indexes are partially materialized. Fixes #108530. #108607 (Anton Popov).
- Fix a metadata disclosure where
DESCRIBE loop('db', 'table')andDESCRIBE loop(<inner table function>)bypassed theSHOW COLUMNS/ source access check, letting an unprivileged user read a table’s column schema. #108624 (Groene AI). - Fixed the
_etagvirtual column for theS3QueueandAzureQueuetable engines: it was declared but never populated, soSELECT _etagalways returned an empty string. It now returns the object ETag, like theS3engine and thes3table function. #108625 (Groene AI). - Fixed reading
Arrow,ArrowStreamand Arrow-basedORCfiles whose timestamp column carries a fixed numeric UTC offset (e.g.+05:30,-08:00,00:00) or the non-IANA markerfixedas its timezone, which previously failed withCannot load time zone ...(BAD_ARGUMENTS). #108633 (Groene AI). - Fixed an exception (
LOGICAL_ERROR: Join is supported only for pipelines with one output portorNOT_IMPLEMENTED: MergeJoinAlgorithm is not implemented for strictness Semi) whenjoin_algorithm = 'full_sorting_merge'was used for aSEMI/ANTIjoin, including the joins produced by decorrelating anEXISTScorrelated subquery.full_sorting_mergenow declines strictness/kind combinations it cannot execute, so the planner falls back to another enabled algorithm or reports that the join cannot be executed. #108658 (Groene AI). - Fixed a heap buffer overflow when building a text index with
positions = 1over many distinct short tokens. #108659 (Groene AI). - A query reading from or writing to S3 that is cancelled (e.g. by
KILL QUERY) while an S3 request is in flight is now reported as cancelled instead of with a misleading network/S3 error. In particular, a cancelled backup or restore to S3 now reportsBACKUP_CANCELLED/RESTORE_CANCELLEDinsystem.backups. #108673 (Julia Kartseva). - Fixed a startup failure where a
DataLakeCatalogdatabase created by an older version (25.12 or earlier) with a malformedauth_headercould not be attached after upgrading to 26.2 or later, preventing the server from starting. Theauth_headeris now validated only onCREATE, and onATTACHthe catalog is built lazily on first use instead of during startup, so a single misconfigured or unreachable catalog database no longer blocks server startup. #108674 (Groene AI). - Fixed a logical error (
Sort order of blocks violated) during a merge, and incorrect reads, when a non-nullableLowCardinalityelement of aNullable(Tuple(...))column is used as a subcolumn (for example as a sort key). #108679 (Groene AI). - Fix a possible crash (use-after-free) when
SYSTEM FLUSH DISTRIBUTEDruns concurrently withDROP TABLEof the sameDistributedtable. #108684 (Groene AI). - Fix a crash in Base64 decoding of the Azure account key, reachable via
azureBlobStorage(and related Azure table functions and storages) when the key is not valid Base64: a byte>= 0x80caused an out-of-bounds read, and any invalid byte caused undefined behaviour. Invalid keys are now rejected cleanly. #108716 (Groene AI). - Fix
NUMBER_OF_COLUMNS_DOESNT_MATCHerror when a subquery on aDistributedtable reads two or moreALIAScolumns that expand to the same expression (for examplea1 String ALIAS toString(x), a2 String ALIAS toString(x)) and the subquery feeds an outer query, e.g.SELECT count() FROM (SELECT a1, a2 FROM dist GROUP BY a1, a2). #108725 (Groene AI). - Fixed
CREATE OR REPLACE MATERIALIZED VIEW ... POPULATEleaving the new view unsubscribed from its source table, which silently dropped every row inserted after the replace. #108728 (Alexey Milovidov). - Fix an exception (
Cannot find sharding key column, and in debug and sanitizer builds a server abort) when aDistributedtable’s sharding key is an expression the analyzer const-folds, for exampleif(1, toInt32(id), toInt32(id) + 1), withoptimize_skip_unused_shards = 1. #108737 (Groene AI). - Fixed a logical error (
Bad cast from type DB::ColumnNullable to DB::ColumnString) and possible wrong results when usinggroup_by_use_nullswith aLowCardinalityconstant grouping key inGROUPING SETS/ROLLUP/CUBE. #108771 (Alexey Milovidov). - Fixed partition and primary key pruning being silently disabled when a
LowCardinality(FixedString)(orLowCardinality(Nullable(FixedString))) key column is wrapped in a function in the key, for examplePARTITION BY sipHash64(k) % NwithWHERE k = 'literal'. Such queries scanned all partitions instead of pruning them. #108777 (Groene AI). - Fixed a logical error (a server abort in debug and sanitizer builds) when an
INSERT ... SELECTthrough anAliastable, or into aTimeSeriestable, is cancelled without an exception, for example withtimeout_overflow_mode = 'break'. #108783 (Groene AI). #108796 (Shaohua Wang). - Fix a
Bad cast from type DB::ColumnSparse to DB::ColumnStringlogical error (a server abort in debug and sanitizer builds) whengroupConcatis applied to aTuplewhoseStringelement is stored sparse. #108790 (Groene AI). - Fix
TYPE_MISMATCHinmapFilter,mapSort,mapReverseSort,mapPartialSortandmapConcatwhen aMapvalue contains a nestedMapwithLowCardinality, e.g.mapFilter((k, v) -> 1, map('a'::LowCardinality(String), map('x'::LowCardinality(String), 'y'))). #108798 (Groene AI). - Fixed
insert_quorum = 'auto'not rejecting inserts up front when fewer than a majority of replicas were alive. Such inserts now fail immediately withTOO_FEW_LIVE_REPLICASinstead of writing a local part and later timing out withUNKNOWN_STATUS_OF_INSERT. #108800 (Gagan Dhakrey). - Fixed a bug where the
WITH TOTALSrow of aJOINcould contain default values (such as0) instead of the constant values coming from a constant subquery on one side of the join. The wrong result appeared only for some join orderings or with thequery_plan_join_swap_tablesetting. #108807 (Vladimir Cherkasov). - Fixed a segmentation fault (null-pointer dereference) that could occur when server shutdown ran concurrently with the shutdown of an
S3Queue/AzureQueuetable. #108810 (Miсhael Stetsyuk). - Fixed a startup abort (
Cannot allocate ThreadStack,EINVAL) on glibc builds running on CPUs with a large signal-stack size (for example Intel Sapphire Rapids / Granite Rapids with an AMX-aware kernel), where the signal alt-stack size was not rounded up to a multiple of the page size. #108813 (Groene AI). - Fix distributed queries occasionally failing with
UNEXPECTED_PACKET_FROM_SERVER(expected TablesStatusResponse, got ProfileInfo) when a connection that a previous cancelled query left out of sync was reused from the pool. #108854 (Alexey Milovidov). - Fixed a logical error (an exception in release builds, a server abort in debug and sanitizer builds) that could happen for a function call with more than one
LowCardinalityargument over a distributed table, for exampleconcatAssumeInjective((SELECT toLowCardinality('p')), s)used as aGROUP BYkey with theremotetable function. The messages wereDefault functions implementation for LowCardinality is supported only with a single LowCardinality argumentorExpected the argument ... to have N rows, but it has M. #108871 (Groene AI). - Fix
reinterpret(x, 'Decimal128(scale)')(andDecimal32/Decimal64/Decimal256/DateTime64targets) producing a result column whose internal scale was the source scale instead of the requested target scale when the source and target had the same physical type. The values were correct, but the column object was structurally inconsistent with its declared type. #108878 (Groene AI). - Fixed a
LOGICAL_ERROR(New empty part is about to materialize but the directory already exist) that could abort the server in debug and sanitizer builds when aDROP/DETACH/MOVE/REPLACE PARTITIONon aMergeTreetable ran after a previous such operation was interrupted (for example a rolled-back transaction or a crash) and left a staletmp_empty_<part>directory behind. The stale directory is now reclaimed instead of failing. #108879 (Groene AI). - Fixed ClickHouse Keeper returning incorrect
dataLength = 0in theStatofCreate2responses, and the ClickHouse ZooKeeper client not deserializing theStatofCreate2responses. #108909 (unintended). - Fixed
clickhouse-localrejecting an empty option value written adjacent to=(for example--format_csv_null_representation=''); it now behaves the same as--format_csv_null_representation ""andSET format_csv_null_representation = ''. #108910 (Vismay). - Fixed a
LOGICAL_ERROR(Inconsistent AST formatting) that aborted the server in debug and sanitizer builds when formatting aTupledata type that mixes named and unnamed elements (for exampleTuple(a UInt8, UInt16)). #108915 (Groene AI). - Fix a segmentation fault when merging
uniqExactaggregate states withGROUPING SETS,ROLLUPorCUBEandmax_threads > 1. #108928 (Raúl Marín). - Fixed possible wrong results or out-of-bounds reads when an
INSERTis rolled back after a mid-batch error (for example inBuffertables, asynchronous inserts, or theKafka/RabbitMQ/FileLogengines) while lazy column replication (enable_lazy_columns_replication) is in effect. #108935 (Groene AI). join_any_take_last_rowis now respected by all supported hash-based join paths, including joins that use automatic spilling to disk. #108936 (János Benjamin Antal).- Fixed a bug in the analyzer where
FINALon one table of aJOIN(e.g.FROM t1 FINAL JOIN t2) was incorrectly applied to the other joined tables as well, which could make such queries slower. #108979 (Vladimir Cherkasov). - Fix a
LOGICAL_ERROR(“Cannot find__grouping_setcolumn in header of MergingAggregatedTransform with grouping sets”, or “Chunk info was not set for chunk in MergingAggregatedTransform”) that could occur, with the analyzer disabled, for aUNION ALL/INTERSECT/EXCEPTwhere one branch usesGROUP BY GROUPING SETSwith parallel replicas and another branch usesFINAL. #109003 (Groene AI). - Fixed a
LOGICAL_ERRORin the automatic parallel replicas planner that could occur whenautomatic_parallel_replicas_modeis enabled together withparallel_replicas_min_number_of_rows_per_replicagreater than 0. #109011 (Groene AI). - Fixed an excessive memory allocation during schema inference of the
MsgPackformat: a corrupted input whose array/map/string/binary header declares a huge element count no longer drives a single multi-gigabyte allocation and is rejected as malformed input. This fixes an out-of-memory condition in release builds (and anallocation-size-too-bigabort under sanitizers). #109019 (Groene AI). - Fixed
use_client_time_zonebeing ignored forDateTime/DateTime64string literals interpreted on the server (asynchronousINSERT,SELECTliterals). The client now propagates its local time zone assession_timezonewhenuse_client_time_zoneis enabled, so server-side parsing matches the synchronousINSERTpath. #109051 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKerror whenquery_plan_optimize_lazy_finalis enabled together with aWHEREfilter partially pushed toPREWHERE(viaoptimize_move_to_prewhere_if_final). #109073 (Groene AI). - Fixed an error when using a qualified asterisk like
b.*in a query wherebis a table (or subquery/CTE) alias that shares its name with a non-compound column of another table. Such queries no longer fail and correctly select all columns ofb. #109078 (Vladimir Cherkasov). - Fix a
Block structure mismatch in JoinSteplogical error (a server abort in debug and sanitizer builds) when a correlated subquery is decorrelated into a join and the source relation carries a column name more than once, e.g.WITH t AS (SELECT number, * FROM numbers(3)) SELECT *, (SELECT t.number WHERE t.number >= 0) FROM twithcorrelated_subqueries_default_join_kind = 'right'. #109114 (Groene AI). - Fixed a hang where a query reading through the filesystem cache could keep waiting on an in-progress download after being cancelled with
KILL QUERY, and where dropping orSYSTEM STOP VIEW-ing a refreshable materialized view whose refresh was stuck in such a wait would block. #109116 (Murphy). - Fixed the
parallel_view_processingsetting being ignored when inserting into a table with materialized views — since 25.10, views always ran in parallel regardless of the setting. #109170 (Antonio Andelic). - Fixed a parser inconsistency where an
INSERTcolumn list accepted a qualified column matcher written ast.* LIKE '<pattern>'/t.* ILIKE '<pattern>'but rejected its canonicalt.COLUMNS('<regexp>')form, breaking the query format round-trip (and aborting the server in debug and sanitizer builds). #109176 (Groene AI). - Fixed non-monotonic
ProfileEventsincrements: theNetworkReceiveBytesandAIOWriteBytescounters could be incremented by a negative amount (wrapping around to a huge value) on a socket timeout or an AIO failure, andMemoryOvercommitWaitTimeMicrosecondswas measured with a non-monotonic clock. #109180 (Azat Khuzhin). - Fix schema inference for the
Arrow,ArrowStream,Avroformats and the legacyORCandParquetreaders returningNullable(Tuple)for nullable struct columns while theNullable(Tuple)type is not allowed (allow_experimental_nullable_tuple_typeis disabled).DESCRIBEreturned a type thatCREATE TABLErejects, so creating a table or inserting data using the inferred schema failed with the errorNullable Tuple type is not allowed. #109185 (Nihal Z. Miaji). - Fixed a wrong result of correlated
EXISTSand scalar subqueries when the correlation appears only in the subquery projection together with a non-correlatedWHEREclause (the subquery could evaluate to false /NULLfor every row). Fixes #105760. #109186 (Dmitry Novik). - Fixed
CREATE USER ... HOST LIKE 'a', 'b'(and the equivalentALTER USER) silently keeping only the first pattern. All specifiedHOST LIKEpatterns are now stored in the user’s host allow-list. #109187 (Groene AI). - Fixed a text index defined on
mapValues(map)ormapKeys(map)being silently not used when a table was queried through aDistributedengine table with the analyzer. The index was used for the local table and via thecluster/remotetable functions, but a query through aDistributedengine table skipped it (and failed withINDEX_NOT_USEDunderforce_data_skipping_indices). #109188 (Groene AI). - Fixed a false
LOGICAL_ERROR(There was an error on <host>: Cannot obtain error message (probably it's a bug)) that could abort the server in debug and sanitizer builds when running a DDL query on aReplicateddatabase and its per-hostfinishedstatus node in Keeper had already been cleaned up. #109192 (Groene AI). - Fix
SAMPLEratios with an exponent whose magnitude overflowsInt32(e.g.SAMPLE 1e-3000000000) being silently treated asSAMPLE 1. #109197 (Raúl Marín). - Fix the access check for
SYSTEM PREWARM PRIMARY INDEX CACHE ... ON CLUSTER, which incorrectly required theSYSTEM PREWARM MARK CACHEprivilege instead ofSYSTEM PREWARM PRIMARY INDEX CACHE. #109198 (Raúl Marín). - Fixed
ALTERqueries failing forMergeTreetables created with a customdisksetting (SETTINGS disk = disk(...)). Fixes #63019. #109199 (Mikhail Artemenko). - Fixed a server crash when states of the aggregate functions
cramersV,cramersVBiasCorrected,contingencyortheilsUfrom a window context (OVER ()) and from a plain aggregation are combined through chained set operations (EXCEPT,INTERSECT) or nestedUNION ALLand then read, for example via the-Mergecombinator. #109200 (Groene AI). - Fix a wrong result for
ANY JOINwith a constantONcondition (e.g.t1 ANY INNER JOIN t2 ON 1): the query returned the full Cartesian product instead of theANYjoin result. #109207 (Vladimir Cherkasov). - Fixed a server crash on asynchronous insert with deduplication when
optimize_on_insertmakes the inserted block empty (for example, rows summing to zero inSummingMergeTree). #109229 (Den Kalantaevskii). - Fix
SYSTEM DROP REPLICAandSYSTEM DROP DATABASE REPLICA ... FROM ZKPATHto reject empty or root-only ZooKeeper paths at parse time withBAD_ARGUMENTS, route auxiliary Keeper paths to the named Keeper, and canonicalize Keeper paths so the local self-protection checks cannot mis-target or bypass the intended replica. #109230 (Groene AI). - Fix S3 settings priority so a URL-scoped
<s3>endpoint block takes precedence over the top-level<s3>defaults. #109251 (Bharat Nallan). - Fixed a bug where column
DEFAULTvalues were not applied forINSERT INTO TABLE FUNCTION(for exampleremoteorfile) with inlineVALUESdata when the server parses the inline data itself (send_table_structure_on_insert_with_inline_data = 0). An explicitNULLinserted into a non-Nullablecolumn with aDEFAULTbecame0instead of the declared default. It now behaves like a plain tableINSERTand the HTTP protocol. #109258 (Groene AI). - Fix
CREATE TABLE ... AS SELECTfroms3Cluster(and other cluster table functions such asfileCluster/urlCluster) failing withNOT_FOUND_COLUMN_IN_BLOCKinside aReplicateddatabase. #109266 (Groene AI). - Fixed
SHOW TABLESandSELECT ... FROM system.tablesreturning different results for data lake catalog databases: tables that ClickHouse cannot read are now consistently hidden from both. #109273 (Smita Kulkarni). - Fixed a bug where merging a
MergeTreetable that has projections while theenable_block_number_columnorenable_block_offset_columnsetting is enabled produced projection parts containing a spurious_block_number/_block_offsetcolumn. The merged projection part then no longer matched the projection definition and the insert-produced projection parts, soCHECK TABLEandOPTIMIZE ... DRY RUNreported it as corrupted (CORRUPTED_DATA). #109284 (Groene AI). - Allow reading an Avro
arrayof two-field{key, value}records into a ClickHouseMapcolumn. This is the encoding Iceberg and Spark produce for aMAP<K, V>with a non-string key (Avro native maps only support string keys). Previously such a file could be read asArray(Tuple(key, value))but not asMap(K, V), which failed withType Map(...) is not compatible with Avro array. #109289 (Groene AI). - Fixed a server crash on
CREATE HYPOTHETICAL INDEX ... TYPE set(andngrambf_v1/tokenbf_v1) when the required index argument is omitted. Such statements are now rejected with a clear error. #109294 (Groene AI). - Fixed a
LOGICAL_ERROR(Current component is empty) that could be raised by mutation operations such asKILL MUTATIONon aMergeTreetable that stores its metadata in Keeper, when theenforce_keeper_component_trackingserver setting is enabled. #109297 (Groene AI). - Fixed reading
ORCtimestamps beyond ~year 2262 into aDateTime64column with a scale coarser than 9. The nativeORCreader used to convert every timestamp through a fixedDateTime64(9)intermediate, which overflowsInt64at nanosecond scale and rejected such values withVALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE, even when the requestedDateTime64scale (for exampleDateTime64(6), as produced by Iceberg) can represent the value. Timestamps are now read directly at the requested scale, anddate_time_overflow_behavioris honored when even the target scale cannot hold the value. #109302 (Groene AI). clickhouse-localacting as a server (afterSYSTEM START LISTEN HTTP) now serves HTTP connections using theTabSeparateddefault output format, matchingclickhouse-server, instead of the interactivePrettyCompactdefault. This fixes connecting toclickhouse-localover HTTP with drivers such asclickhouse-connect. The interactive terminal session still renders results asPrettyCompact. #109362 (Alexey Milovidov).- Fixed a transient
Code: 499 ... InvalidPart(S3_ERROR) failure on S3 multipart uploads. MinIO can briefly report a just-uploaded part as missing onCompleteMultipartUpload; this error is now retried like the already-handledNoSuchKey, bounded bys3_max_unexpected_write_error_retries. #109364 (Groene AI). - Fix
UNKNOWN_IDENTIFIERerror onALTER TABLE ... DROP COLUMNwhen another column has aDEFAULTorMATERIALIZEDexpression that defines and references an inline alias. #109374 (Alexey Milovidov). - Fix a data race (and resulting rare crash) in the parallel merge of
uniqExactaggregate states with two-level sets, which could occur withGROUPING SETS,ROLLUPandCUBE. #109389 (Groene AI). - Fixed an error (
NOT_FOUND_COLUMN_IN_BLOCK, orstd::bad_function_callin older versions) when runningCREATE TABLE ... ON CLUSTER ... AS SELECTreading aDistributedtable on a cluster with two or more shards. #109407 (Alexey Milovidov). - Fixed merges for tables with
TTL ... GROUP BY(rollup): parts that were already fully aggregated could be rescheduled for merging again and again indefinitely, and tables withMATERIALIZEDcolumns or enabled persistent virtual columns were handled incorrectly — such columns are now aggregated withany. Closes #105647. #109410 (Mikhail Artemenko). #109532 (Mikhail Artemenko). - Fixed
INwith a bare array column on the right argument silently returning a wrong (always-false) result or throwing an exception, so thatx IN arrbehaves likehas(arr, x). #109416 (Alexey Milovidov). - Fix
UNKNOWN_IDENTIFIERerrors onALTER TABLEoperations (RENAME/ADD/MODIFY COLUMN, andMATERIALIZE INDEXon a table with freshly inserted parts) forMergeTreetables with an implicit min-max index over the persistent virtual columns_block_number/_block_offset(enabled byadd_minmax_index_for_block_number_column/add_minmax_index_for_block_offset_column). #109428 (Groene AI). #110236 (Groene AI). - Fix a
LOGICAL_ERRORinarrayFoldover a non-constArray(LowCardinality(T))argument (for examplearrayFold((acc, x) -> acc + x, materialize([1, 2, 3]::Array(LowCardinality(Int64))), toInt64(0))), which failed withArguments of 'plus' have incorrect data types(a server abort in debug and sanitizer builds). #109462 (Groene AI). - Fixed
CHECK TABLEon aReplicatedMergeTreetable reporting a healthy part as broken when a transient, retryable ZooKeeper error (e.g. connection loss) occurred during the check; such errors are now surfaced as a retryable query error instead. #109465 (Alexey Milovidov). - Fix segfaults in
groupArrayLastMergeand thelargestTriangleThreeBucketsaggregate function: deserialization of aggregate function states is now validated, so a broken state does not lead to an out-of-bounds memory access. #109485 (Miсhael Stetsyuk). #109492 (Miсhael Stetsyuk). - Fixed the global
max_rows_in_join/max_bytes_in_joinlimit not being enforced for theparallel_hashjoin algorithm, where a query withjoin_overflow_mode = 'throw'could silently succeed instead of raisingSET_SIZE_LIMIT_EXCEEDED. #109488 (Hechem Selmi). - Fixed reading Paimon tables partitioned by a
BIGINTcolumn whose value does not fit intoInt32. Such partition values were truncated (for example9223372036854775807became-1), which produced a wrong partition path and failed with a filesystem error. #109510 (Groene AI). - Fix a crash when reading Iceberg tables with equality delete files. If a column is nullable in the equality delete file but non-nullable in the table schema (or vice versa), the values read from the delete file were inserted into a column of a different type through an unchecked cast (a column type confusion), corrupting the column and crashing the server. #109551 (Miсhael Stetsyuk).
- Fixed the MySQL
connect_timeout, read and write timeouts not taking effect: a connection attempt to an unresponsive MySQL server could hang for more than two minutes even withconnect_timeout = 1, because the sampling query profiler’s periodic signals kept resetting the MySQL client’s internal poll deadline. #109592 (Shaohua Wang). - Fixed a
LOGICAL_ERROR(creation_csn is not set while removal_csn is set to 1) that could be thrown when a non-transactionalTRUNCATEran concurrently with an uncommitted transaction that had inserted into the same table. Such aTRUNCATEno longer removes parts created by not-yet-committed transactions. #109598 (Tuan Pham Anh). - Fix
TYPE_MISMATCHerrors when readingParquetstruct columns whose physical nullability differs from the requested ClickHouse type: a non-nullableParquetgroup can now be read asNullable(Tuple(...)), and the nativeParquetreader can read a physically nullable struct (aParquetOPTIONALgroup) asNullable(Tuple(...)). #109615 (Groene AI). #109898 (Groene AI). - Fixed silent data loss when an
INSERT ... VALUESin a multi-query stream is followed by a trailing SQL comment (for exampleVALUES (1) -- comment) under the server-side inline insert parsing path (send_table_structure_on_insert_with_inline_data = 0). The trailing comment was scanned as row data past the terminating;, causing the following queries in the stream to be silently skipped. #109643 (Groene AI). - Fix a segfault when a query arrives in a narrow window during server shutdown after an error at startup. #109675 (Miсhael Stetsyuk).
- Fixed stale skip indices (
text,bloom_filter, etc.) and projections after materializing lightweight updates withALTER TABLE ... APPLY PATCHES. Previously the index and projection files that depend on a patch-updated column were left unchanged, so queries using them could return wrong results (e.g.hasTokenmissing an updated row, or a projection returning stale aggregates once the spent patch part was removed). #109709 (Groene AI). - Fix
system.tablessilently skipping databases for users with per-database grants when the query reads only thename/databasecolumns. Introduced in 26.2. #109723 (Samay Sharma). - Fix a
LOGICAL_ERRORwhen writing aLowCardinality(Time)column to theArrowformat withoutput_format_arrow_low_cardinality_as_dictionary = 1. #109730 (Groene AI). - Fix
ObjectStorageQueue/AzureQueue(and theazureBlobStoragetable function) silently skipping objects when the object storage returns an empty listing page together with a continuation token. Azure Blob Storage does this (e.g. when a listing crosses an internal partition boundary), and the async list iterator was treating the empty page as the end of the listing and dropping the token. It now follows the continuation token. #109761 (Gal Ben Moshe). - Fixed partition pruning returning no rows for Iceberg tables partitioned by a timestamp (
DateTime64) column. #109764 (Den Kalantaevskii). - Fix an
ILLEGAL_COLUMNexception in theconvfunction forFixedStringarguments; they are now correctly cast toString. Closes #109670. #109771 (hp). - The
getClientHTTPHeaderfunction now treats header names as case-insensitive, according to RFC 9110; in particular, theauthorizationheader is now filtered out regardless of case. Closes #103957. #109791 (Mikhail f. Shiryaev). - Fix
max_execution_time(withtimeout_overflow_mode = 'throw') sometimes never cancelling a query: when the internal timeout watcher was already waiting for a query with a later deadline, a query with an earlier deadline registered afterwards could be missed entirely, letting it run long past its time limit. #109792 (Shaohua Wang). - Fixed the file name of gzip-compressed Iceberg metadata files. ClickHouse wrote them as
v{N}.gzip.metadata.json(the HTTPContent-Encodingtoken), while the Iceberg spec expects thegzextensionv{N}.gz.metadata.json. As a result Spark and other Hadoop-catalog readers could not find the metadata written by ClickHouse. ClickHouse now writesv{N}.gz.metadata.jsonand still reads the legacygzipname for backward compatibility. #109812 (Groene AI). - Fixed
NOT_IMPLEMENTEDerror (“Method getDataAt is not supported for Nullable(String)”) that could be thrown by a join withenable_join_runtime_filters = 1(on by default since 26.2) when the build-side join key wasLowCardinality(Nullable(...))withNULLvalues and the runtime filter fell back to its bloom filter. #109824 (Groene AI). - External database engines (e.g.
PostgreSQL) no longer push down range comparisons (>=,>,<=,<) onUUIDcolumns. ClickHouse and external databases order UUIDs differently, so pushing these down silently dropped rows from the result; such predicates are now evaluated by ClickHouse instead. #109833 (Vismay). - Fixed a server crash when a lambda expression was passed where a higher-order function expects a concrete value (for example the accumulator of
arrayFold, as inarrayFold(lambda, arr, another_lambda)). Such queries are now rejected withILLEGAL_TYPE_OF_ARGUMENTinstead of crashing whenenable_analyzer = 0. #109840 (Groene AI). - Fixed the
icebergLocaltable function andIcebergLocalengine declaringazureinstead oflocalas their object storage type, which made them fail the disk type check (Disk type doesn't match) when used with a local disk viaSETTINGS disk = '...'. #109872 (Pedro Ferreira). - Fix reading Iceberg tables partitioned by the same source column more than once (for example
PARTITIONED BY (hours(ts), ts)). Such tables previously failed withCannot add column ...: column with this name already exists (ILLEGAL_COLUMN). #109895 (Groene AI). - Fix wrong query results caused by the primary key index incorrectly pruning granules for tables with a reversed (
DESC) key column when parts have no final mark (non-adaptive granularity,index_granularity_bytes = 0). #109901 (Nihal Z. Miaji). - Fixed
generateRandomStructureoccasionally producing an invalid structure string with two data types concatenated (for exampleDecimal32(7)IPv4) when type nesting exceeded the internal depth limit, which made the result unparseable. #109928 (Groene AI). - Fixed
NOT_IMPLEMENTEDerror (Method getDataAt is not supported for Nullable(String) in case if value is NULL) when atextindex is built onArray(LowCardinality(Nullable(String)))(includingNestedfields stored that way) and an indexed array contains aNULLelement.NULLarray elements are now skipped during index construction, matchingArray(Nullable(String)). #110055 (Groene AI). - Fix wrong results when a
minmaxskip index is built on aLowCardinality(Nullable(...))column:WHERE/PREWHERE/HAVING ... IS NULLpredicates pushed to storage previously pruned every granule and returned 0 rows even though the column containedNULLvalues. #110061 (Groene AI). - Fix
distinct_overflow_mode = 'break':DISTINCTnow returns the partial result accumulated up to the limit and stops reading the source, as documented. Previously the chunk that crossedmax_rows_in_distinct/max_bytes_in_distinctwas discarded (truncated or empty results) and the query kept reading and inserting into the hash set to the end of the input, which could end inMEMORY_LIMIT_EXCEEDED. #110075 (Sergey Kuznetsov). - Fixed a logical error
ChunkInfoRowNumbers does not existonOPTIMIZE TABLEof an Iceberg table containing a data file in a non-Parquet format (e.g.ORC) newer than all position delete files. #110107 (Alexey Milovidov). - Fix
max_bytes_in_distinctandmax_bytes_in_set: string keys are stored in an arena that was not counted by the limit checks, soDISTINCT/INover string keys could hold memory exceeding the byte limit by the whole key payload (unbounded in the key length). The limits now account for the arena, matching their documentation; queries with string keys close to a byte limit may now trip it earlier (correctly). #110120 (Sergey Kuznetsov). - Fix a
LOGICAL_ERROR(Bad cast from type ColumnLowCardinality to ColumnString) whenidentity(or a scalar subquery result) wraps a value containing a nestedLowCardinalityand the query usesWITH TOTALS/WITH ROLLUP. #110138 (Groene AI). - Fixed reading
Npyfiles with zero-sized inner dimensions: the number of materialized rows and the optimized and non-optimizedcountresults now agree. #110146 (Yanjun Qiu). - Fixed a quadratic-time blowup (and unresponsiveness to
max_execution_time) in aggregation in order when grouping by multiple keys whose sort order is only a prefix of the grouping key. #110159 (Alexey Milovidov). - Fix a logical error (
Unexpected number of columns in result sample block) when a filter containing a correlated subquery (for exampleexists((SELECT ...))) is optimized withconvert_query_to_cnforoptimize_and_compare_chain. #110187 (Alexey Milovidov). - Fixed an exception (
UNION mode UNION_DEFAULT must be normalized) when aDELETEorALTER UPDATEmutation used a set operation (UNION/UNION ALL/UNION DISTINCT/EXCEPT/INTERSECT) inside a subquery in itsWHEREcondition or in anUPDATEassignment. #110196 (Alexey Milovidov). - Fixed a
ReadBuffer is canceled. Can't read from it.logical error (server abort in debug/sanitizer builds) that could occur while reading a zip archive (e.g. duringRESTOREfrom a zip backup) after a prior read from the same archive failed mid-stream. #110197 (Groene AI). - Fixed slow server shutdown and unresponsive
KILL MUTATIONwhen a mutation withx IN (subquery)was building the subquery set during primary-key analysis; the set build is now cancelled promptly. #110198 (Alexey Milovidov). - Keeper now rejects the coordination settings
max_requests_batch_sizeandmax_requests_append_sizebeing set to0instead of getting stuck in an infinite append-entries loop in a multi-node setup. #110200 (Alexey Milovidov). - Fixed a
NOT_FOUND_COLUMN_IN_BLOCKerror when usingGROUP BY ALLover a tuple expression together withORDER BY. #110206 (Alexey Milovidov). - Fixed a
NOT_FOUND_COLUMN_IN_BLOCKerror onINSERTinto a table that has aCHECKconstraint referencing a subcolumn (such asx.nullof aNullablecolumn orarr.size0of anArray). #110208 (Alexey Milovidov). - Fix reading Iceberg tables whose default sort order references a column that needs quoting (e.g.
@timestamp). Such tables were unreadable because the synthesized storageORDER BYwas built from the raw column name and failed to parse withSYNTAX_ERROR. #110233 (Groene AI). - Fixed
system.tablesfor aDataLakeCatalog(Iceberg/Glue) database aborting the whole query, or silently dropping tables, when a single table’s metadata is unresolvable. Such a table now stays listed by name with default/NULL values for the columns that need the opened storage object (engine,total_rows, etc.), regardless ofdatabase_datalake_require_metadata_access. Direct access to the broken table still reports the error. #110242 (Groene AI). - Fixed a possible crash (heap-buffer-overflow) when a
quantileTDigest-family aggregate-function state column was used as aGROUP BYkey and serialized concurrently by several threads. #110263 (Groene AI). - Fixed
INSERTinto a Microsoft Fabric / OneLakeDataLakeCatalogtable failing withIncorrectEndpointError(HTTP 400) by routing ADLS Gen2 (DFS) writes to the.dfsendpoint host instead of the.blobhost. Note: withremote_url_allow_hosts, both the.blob(read) and.dfs(write) Fabric hosts must be allow-listed forINSERT. #110290 (Mohammad Lareb Zafar). - Fixed a server abort when parsing certain PRQL queries (
SET dialect = 'prql'). A panic inside theprqlccompiler was aborting the process instead of being reported as a query error. #110316 (Groene AI). - Fix silently wrong query results when a projection part written before the projection’s column set changed (for example, after upgrading across versions that materialize an
ALIAScolumn’s source differently, or afterALTER TABLE ... MODIFY COLUMNre-points anALIAScolumn used by a projection) was read through the projection or merged: the missing column was filled with default values instead of the real data. Such parts are now read from the base table, and merges rebuild the projection from the base data. #110328 (Shaohua Wang). - Fixed
ORDER BY ... WITH FILLnot respectingmax_execution_timeand being slow to cancel when generating a large fill range (especially withINTERPOLATE). #110332 (Alexey Milovidov). - Fix a logical error (a server abort in debug/sanitizer builds) when a multi-command
ALTERsuch asUPDATE ..., DELETE ...was issued on an Iceberg table. Such mutations are now rejected with a clearNOT_IMPLEMENTEDerror. #110347 (Groene AI). - Fixed a parser bug where
COMMENTwas incorrectly consumed as an implicit alias when aSELECTquery ended directly after a bare table identifier (e.g.... FROM t COMMENT 'x'), causing a misleading syntax error instead of the comment being applied to the view/table. #110372 (Aditya Kumar). - Fixed a server crash (native stack overflow) when a deeply nested
Array/Tuple/Map/Objectliteral is copied or destroyed, for example a query with a very deeply nested literal at a raisedmax_parser_depth. #110393 (Raúl Marín). - Fixed two cases where vector search could return fewer rows than expected:
vector_search_index_fetch_multipliervalues below 1.0 could truncate the computed fetch count to zero and produce an empty result (such values are now rejected), and the vector search optimization is now skipped forLIMIT ... WITH TIESqueries, because the optimization bounds the search to exactly N candidates and dropped rows tied with the N-th row. #110452 (Tamish Mhatre). #110453 (Tamish Mhatre). - Fix the logical error
Expected CommonSubplanReferenceStep to reference CommonSubplanStep, the errorSubplan cannot be used to build pipeline, and the logical errorTrying to extract chunk from ChunkBuffer before all inputs are finishedforIN (subquery)where the subquery contains a correlated subquery and the set is built during index analysis. #110491 (Alexey Milovidov). - Fix substitution of query parameters inside the definitions of a named
WINDOWclause. Previously, parameters there were silently kept unsubstituted, and an unsetIdentifierparameter could lead to the exceptionLogical error: '!part.empty()'duringEXPLAIN SYNTAX. #110506 (Alexey Milovidov). - Fixed server startup failure for
MergeTreetables on object storage disks when a leftovertxn_version.txt.tmpfile has broken disk-level metadata. #110519 (Alexey Milovidov). - Fix a logical error in the filesystem cache (
Expected file ... not to exist) that could occur when a background cache download failed with a non-filesystem error (for example while runningOPTIMIZEon an Iceberg table), leaving an empty orphan cache file behind. #110549 (Groene AI). - Fixed reading a corrupted
Native-format stream whoseDynamictype count orJSON/Objectpath count is close toSIZE_MAX: such malformed input is now rejected with a clearINCORRECT_DATAerror instead of an uncaughtstd::length_error. #110590 (Alexey Milovidov). - Fixed a server crash in the
MaterializedPostgreSQLdatabase engine that could happen when a table was detached (or its structure changed) while it was still queued for synchronization. #110596 (Alexey Milovidov). - Fixed
SET param_<name>in the client (and--param_<name>flags) misbehaving when the parameter name matches a builtin setting name such aslimit,offset,max_threads, orlog_comment. Depending on the colliding setting, the query failed withCANNOT_PARSE_QUOTED_STRING, the value was silently normalized (e.g.max_threads=0becameauto(N)), or a setting alias name was lost. Such a parameter also broke every subsequentSET param_*in the same session. #110597 (Raúl Marín). - Fix reading subcolumns of a column that has a
DEFAULTexpression and is not materialized in a part (e.g. afterALTER TABLE ADD COLUMNor duringALTER TABLE MATERIALIZE COLUMN): the subcolumn was filled with type default values instead of the evaluatedDEFAULTexpression, and the transposed vector distance functions (cosineDistanceTransposedand others) on suchQBitcolumns failed with theSIZES_OF_ARRAYS_DONT_MATCHerror. This closes #110634. #110636 (Alexey Milovidov). - Fixed a
LOGICAL_ERRORInvalid partition key size: 0that could fail anINSERTinto a partitionedMergeTreetable withnon_replicated_deduplication_windowenabled, when an async insert batch was only partially deduplicated (someinsert_deduplication_tokenvalues were duplicates and some were new). #110651 (Groene AI). - A background asynchronous insert flush now stops promptly when killed with
KILL QUERY; previously a flush of a large buffered payload kept parsing to the end and ignored the cancellation. #110652 (Shaohua Wang). - Fixed wrong results from
GROUP BYwithoptimize_aggregation_in_orderandDISTINCTwithoptimize_distinct_in_orderplaced over apartial_mergeJOIN. The read-in-order optimization was propagated through the partial-merge join, which re-sorts its left input by the join key and therefore does not preserve the left stream’s original order, so rows were grouped incorrectly. #110671 (Groene AI). - Fixed a signed integer overflow in
toStartOfIntervalwith an extremeMONTH,WEEK, orDAYinterval count onDate/Date32/DateTime64values. #110688 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKerror for queries with a subquery inFROMwhen parallel replicas run incustom_key_sampling/custom_key_rangemode. Such queries (e.g.SELECT * FROM (SELECT id, k, v FROM t WHERE id < 20) ORDER BY k) previously failed withNot found column __table2.id in block .... #110690 (Groene AI). - Fixed
readWKTrejecting WKT strings with leading whitespace (e.g.readWKT(' POINT(1 2)')), which are accepted by the typedreadWKTPoint/readWKTPolygon/… readers and by the WKT grammar. #110706 (Groene AI). - Fix a logical error (
Column ... already added for reading, a server abort in debug/sanitizer builds) when the same text-index predicate is used in bothPREWHEREandWHEREof a query over aMergetable on top of aDistributedtable. #110710 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKerror for the transposed distance functions overQBitcolumns (such ascosineDistanceTransposed) called with a scalar-subquery or constant reference vector when parallel replicas are enabled. This closes #110719. #110729 (Alexey Milovidov). - Fix a rare
LOGICAL_ERROR(Unexpected number of parts to remove from parts_queue; a server abort in debug/sanitizer builds) onReplicatedMergeTreewhen two partition operations (for example twoMOVE PARTITION/REPLACE PARTITIONqueries, or one racing a backgroundDROP_RANGE) cancelled the background part check over overlapping ranges at the same time. #110738 (Groene AI). - Fixed a
Hash is not set for serializationlogical error that could occur when a column with aQuantized(...)codec was wrapped inside another serialization, for example in aMergetable over sources whose same-named column has different types (merged into aVariant). #110776 (Groene AI). - Fix a server hang when multiplying a
median/quantileaggregate function state by a huge integer constant (e.g.medianState(x) * 18446744073709551615). The query became unresponsive to cancellation and could run indefinitely. #110779 (Groene AI). - Fix a server crash (integer division by zero) when a quota with a zero-length interval (for example
CREATE QUOTA q FOR INTERVAL 0 SECOND MAX queries = 1000) was consumed. A non-positive quota interval duration is now rejected at quota creation. #110846 (Pedro Ferreira). - Fixed
throwIf(notLike(col, pattern))(and otherthrowIfover a function) throwing unconditionally whencolisLowCardinality. The defaultLowCardinalityimplementation ranthrowIfon the whole dictionary, which always holds the reserved default value even when no row references it, so a non-zero value in that unused slot madethrowIfthrow for data that does not satisfy the condition. #110864 (Groene AI). - Propagate a query’s active roles (
SET ROLEor theroleparameter) to remote nodes on parallel-replica andDistributedreads over a cluster secured with an interserver secret; previously the remote nodes fell back to the user’s default roles, evaluating row policies inconsistently with the initiator. #110867 (Nikolay Degterinsky). - Fixed Iceberg tables producing duplicate field IDs after
ALTER TABLE ... ADD COLUMNwhen the initial schema contains nested fields (Tuple/Array/Map).last-column-idnow records the maximum assigned field ID including nested children, so a subsequently added column no longer reuses a nested field ID and reads no longer fail withICEBERG_SPECIFICATION_VIOLATION(Duplicate field id). #110884 (Groene AI). - Fixed a crash in FIPS builds when using an Ed25519 SSH key (
CREATE USER ... IDENTIFIED WITH ssh_key ... TYPE 'ssh-ed25519', or such a key inusers.xml). Ed25519 is not FIPS-approved; such keys are now rejected with a clearLIBSSH_ERRORerror. #110891 (Konstantin Bogdanov). - Fix the reduced-precision results of the transposed distance functions over
QBitcolumns (cosineDistanceTransposed,L2DistanceTransposed,dotProductTransposed). Values truncated toprecisionbit planes were reconstructed with the dropped bits zero-filled, which biased every reconstructed value towards zero and was degenerate at low precision: forQBit(BFloat16)at precision 1 only the sign bit survives, so every value reconstructed to±0.0and the distance was the same constant for every row, carrying no ranking information. Truncated values are now reconstructed to a bounded midpoint of the remaining precision cell (rawInt8codes to their cell centre; exact zeros and infinities are preserved), so a smallerprecisiontrades accuracy for speed without wildly biased results. Full-precision results are unchanged. This closes #110898. #110911 (Alexey Milovidov). - Fix a server crash (use-after-free) during graceful shutdown after Iceberg tables were queried from sessions that also used temporary tables. #110914 (Miсhael Stetsyuk).
- Fixed a
LOGICAL_ERROR: Cannot sum Bools(a server abort in debug/sanitizer builds) when mergingsumMap/sumMapWithOverflow/sumMapFilteredaggregate states withBoolvalues that were serialized in the old (version 0) state format. The same fix also corrects two silent wrong-result cases with version-0Boolstates: map keys of typeBoolwere not deduplicated across states, and zero-value compaction dropped the wrong entries. #110922 (Groene AI). - Fixed a crash when an aggregate function with the
-Tuplecombinator was used withRESPECT NULLSand produced an intermediate state (-State, distributed aggregation,WITH ROLLUP/WITH CUBE). The combined function was named after the wrong state variant, so its serializedAggregateFunctiontype re-resolved to an incompatible in-memory layout on a round-trip. #110930 (Groene AI). - Fix
PREWHERE(and row-level policies) on an Iceberg column that was renamed by schema evolution silently returning0rows for old data files. Such queries now return the correct rows, matchingWHERE. #110941 (Groene AI). - Fix a
LOGICAL_ERROR(LazyMaterializingTransform: Number of rows in lazy chunk N does not match number of offsets M) that could happen for vector search queries withvector_search_with_rescoring = 1combined with lazy materialization when several distances tie. #111003 (Groene AI). - Fixed reading
Arrow/ArrowStreamdata with empty nestedArray/Mapcolumns produced by Apache Arrow Java < 19.0.0 (bundled with Apache Spark), which were previously rejected with anINCORRECT_DATAerror about the offsets buffer being too small. #111101 (Raúl Marín). - Fix stale reads on
plain_rewritabledisks with the page cache enabled. #111105 (Mikhail Artemenko). - Fix
CANNOT_CONVERT_TYPEerror for constants ofVarianttype (includingGeometry) in distributed queries and queries with parallel replicas. #111136 (Nikita Fomichev). - Fix a bug where reading large files from HDFS could fail or read incorrectly when a single read request exceeded the
hdfsPread32-bit size limit (INT_MAX). #98470 (Arup Chauhan). - Fix incorrect use of the text index for equality comparisons with an empty needle. #108340 (Robert Schulze).
- Fixed a hang in
SYSTEM SYNC MERGESwith theManualmerge selector when a scheduled merge could not be placed into a full background pool. #108770 (Alexey Milovidov). - Fix
ATTACH TABLE ... AS REPLICATEDdiscarding committed data and resurrecting pre-mutation rows when a staletxn_version.txt.tmpfile was left on a data part. #108772 (Alexey Milovidov). - Fix a possible race condition in
ALTER TABLE ... MOVE PARTITION TO TABLEwith non-replicatedMergeTreetables that could produce intersecting data parts, because the commit of moved parts and block number allocation were not under the same lock. #108922 (Mikhail Artemenko). - Fix reading
Icebergtables written by Databricks UniForm, which writes a degenerate placeholder schema (with an empty field list) into manifest files. #108945 (Konstantin Vedernikov). - Fix a use-after-free when reading a non-partitioned
Hivetable with multiple threads. #109164 (Alexey Milovidov). - Fix the console log level not being reverted after server startup when
logger.startup_console_log_levelis set: the level was captured from the wrong configuration key, so the console stayed at the elevated startup level for the lifetime of the server. Closes #103472. #109858 (Garrett Thomas). - Fix snapshot-isolation anomalies in
plain_rewritabledisk metadata transactions. Fixes #92055. #110948 (Mikhail Artemenko). - Fix an abort (
front() called on an empty vector) inclickhouse-client --loginwhen the host was not passed as an explicit--hostargument, for example when it came from--connection, the configuration file, or theCLICKHOUSE_HOSTenvironment variable. Closes #103603. #110279 (Christoph Wurm). - Fix a logical error (
!part.empty()) when a lambda argument is a backtick-quoted identifier whose name contains a dot (for example__table1.). Such a query previously produced a handled exception in release builds and aborted the server in debug and sanitizer builds while formatting an error message. #108735 (Groene AI). - Fix a
LOGICAL_ERROR(No set is registered for key) inALTER TABLE ... DROP COLUMN,ALTER TABLE ... DELETE/UPDATEmutations, and lightweightDELETE FROM, on tables that have anALIAScolumn whose expression uses anINoperator (including through anotherALIAScolumn). #111039 (Pedro Ferreira). - Fixed silent data loss with async inserts and deduplication (
async_insert=1,async_insert_deduplicate=1). When several async-insert entries with distinctinsert_deduplication_tokenvalues were coalesced into one flush that wrote to disjoint partitions, each token was registered in the deduplication log of every partition the flush touched, not only the partition its own rows landed in. A later insert reusing one of those tokens in a partition it never wrote to was then silently deduplicated away. Tokens are now registered only against the partition their rows actually landed in. Closes #111031. #111049 (Groene AI). - Fixed a
LOGICAL_ERRORexception (ScatterExchangeStep should have one source shard, got 8) and duplicated rows when querying aMergetable overDistributedtables or views with the experimental settingmake_distributed_plan = 1. Closes #107946. #108401 (Groene AI). - Serialize a
Nullable(Tuple(...))column as a singleCSVfield instead of flattening it into separate columns. Previously a non-null value was written as severalCSVfields whileNULLwas a single\N, giving a row-dependent column count that brokeCSVWithNames/CSVWithNamesAndTypesheaders and round-trips. #108959 (Groene AI). - Fix a logical error (
KeyCondition uses PREWHERE output) in theParquetv3 reader when a format-level key condition references a column that is not read from theParquetfile. #109267 (Groene AI). - Fix wrong results for table-function reads with
FINALorSAMPLEunderserialize_query_plan = 1. Also fix the aggregation hash-table statistics cache key for table functions so different table functions no longer share the same preallocation entry. #109847 (Azat Khuzhin). - Fixed cleanup of a
BACKUP ... TO Memory(...)that fails before finalization: the failed backup was left registered, so its name could not be reused. #109947 (Julia Kartseva). - Fix extreme interval arithmetic for
WITH FILL STEPand theadd*/subtract*date/time interval functions: out-of-range deltas no longer rely on signed overflow, andWITH FILLwith a hugeYEARstep no longer stalls by running the calendar backward. #110158 (Groene AI). - Fix
411 Length Requirederrors from Azure services: the Poco-based Azure HTTP transport now setsContent-Lengthfrom the request body for SDK clients that do not set it themselves, such as Azure Key Vault. #110299 (Konstantin Bogdanov). - The lazy
FINALoptimization (query_plan_optimize_lazy_final, disabled by default) is no longer applied when the query reads in sorting-key order, because its replacement plan does not preserve that order and could return incorrectly ordered results. It is also no longer applied when aLIMITsmaller than the number of rows to read applies directly to the reading step, where the mandatory set-building pass defeats early termination. #110576 (Nikolai Kochetov). - Fixed
readWKTandreadWKTPointreturning uninitialized (scalar) or stale prior-row (vectorized) coordinates forPOINT EMPTY.POINT EMPTYis now rejected withCANNOT_PARSE_TEXT, since ClickHousePointis a fixedTuple(Float64, Float64)with no empty representation. #110692 (Groene AI). - Fix wrong timezone handling when materializing right-side columns in hash joins. Closes #111033. #111074 (Yarik Briukhovetskyi).
- Fixed wrong
count()results and dropped rows when aString(or narrowerFixedString) key or minmax skip index is filtered by a comparison with a widerFixedStringconstant, e.g.toFixedString('abc', 257) = string_col. Primary-key and minmax pruning built the range from the NUL-padded constant and wrongly skipped matching granules. #111106 (Groene AI). - Fixed asynchronous
Native-format inserts so one buffered entry that becomes incompatible afterALTER ... MODIFY COLUMNno longer causes the whole batch to fail. Closes #111064. #111108 (Mikhail f. Shiryaev). - Fix
CREATE OR REPLACEof a dictionary with an object of another kind: it failed withCANNOT_DETACH_DICTIONARY_AS_TABLEafter the replace was already committed, leaving an orphan_tmp_replace_*table. #111142 (Nikolay Degterinsky). - Fixed
INCOMPATIBLE_TYPE_OF_JOINfor anANYjoin on aJoinengine table when aWHEREfilter on a right-side column allowed the query planner to rewrite the join toSEMIorANTI. AJoinengine table has a fixed declared strictness that cannot be changed, so the conversion is now declined for such tables. #111362 (Groene AI). - Fix the
formattable function returning no columns when the input data parses to zero rows (for example an empty JSON document or a GeoJSONFeatureCollectionwith no features). It now returns an empty result with the correct columns instead of throwingNOT_FOUND_COLUMN_IN_BLOCK. Closes #111390. #111428 (Groene AI).
Build/Testing/Packaging Improvement
- Sanitizer builds now capture the sanitizer report into the global buffer
sanitizer_report, so that the core dump analyzer can read it from the core dump. #109333 (Miсhael Stetsyuk). - Build
muslfrom source instead of using vendored binaries. #97452 (Konstantin Bogdanov). - Use SIMD
memcmp/memcpy/memmove/memset/bcmp/memmemimplementations from LLVM-libc. #107566 (Konstantin Bogdanov). Fix silentmemmovecorruption in-O0debug builds (-DDEBUG_O_LEVEL=0) on machines with AVX-512. #110904 (Konstantin Bogdanov). - Remove usages of the
curllibrary across the codebase and bundled third-party libraries. #108296 (Konstantin Bogdanov). - Updated
mariadb-connector-cto 3.4.9. #108328 (Konstantin Bogdanov). - Update
libsshto 0.12.0. #108329 (Konstantin Bogdanov). - Fix a hang on transaction
COMMITon macOS. #108375 (Raúl Marín). - Added a
COMPRESS_DEBUG_SECTIONSCMake option that compresses DWARF debug sections in object files (-gz), auto-enabled where the compiler supports it, to shrink Debug build directories; final binaries are left uncompressed, so runtime stack-trace symbolization is unaffected. #109306 (Murphy). The bundled LLVM toolchain is now built with zlib, so its clang supports-gz=zlib, and the missingclang++-21symlink was added. #109596 (Murphy). - Debug builds now compile the vendored Rust crates with reduced debug info (
debug = 1, cargo’slimitedlevel) and no incremental cache (REDUCE_RUST_DEBUG_INFO, on by default), shrinking Rust build artifacts (~12 → ~7 GB from scratch) and preventing unbounded cargo cache growth across rebuilds. Set-DREDUCE_RUST_DEBUG_INFO=OFFto restore full DWARF and incremental compilation. #109471 (Murphy). - Support the streaming distributed query exchange and
STREAMreads on macOS. #109769 (Raúl Marín). - Bump
libarchivefrom 3.8.7 to 3.8.8. #109874 (Robert Schulze). - Bump
c-aresfrom 1.34.6 to 1.34.8. #109905 (Robert Schulze). - Update
krb5to fix CVE-2026-40355 and CVE-2026-40356. #109910 (Robert Schulze). - Removed the
libpngthird-party dependency.FORMAT PNGnow uses a small built-in PNG encoder (backed by the bundled zlib) instead. #110051 (Alexey Milovidov). - Track raw C allocations (not going through
operator new) in the memory tracker on macOS by wrapping the jemalloc malloc zone, so memory limits are enforced for them. #110370 (Raúl Marín). - The
-distrolessDocker images forclickhouse-serverandclickhouse-keeperare now built from the shell-free production stage; previously they were built from the debug stage and included/busybox/sh. Closes #105677. #105678 (ashishch432). - Update
abseil-cppto LTS20260526.0. #108991 (Konstantin Bogdanov).
ClickHouse release 26.6, 2026-06-25. Presentation, Video
Backward Incompatible Change
- The change removes
allow_experimental_query_deduplicationfeature. The feature was experimental for a long time, has no tests and not going to be supported (initial tests were unstable and has been removed in #49579). #99398 (Igor Nikonov). - The XRay-based
SYSTEM INSTRUMENTfeature now usesargumentsinstead ofparameters: thesystem.instrumentation.parameterscolumn was renamed toarguments, and theSYSTEM INSTRUMENT ADD ... HANDLER PARAMETERS ...syntax was renamed toSYSTEM INSTRUMENT ADD ... HANDLER ARGUMENTS .... Queries or automation that use the old column or syntax must be updated to use the new names; the old names are no longer supported. #103854 (Pablo Marcos). - The setting
show_data_lake_catalogs_in_system_tableshas been renamed toshow_remote_databases_in_system_tablesand broadened: when its value is 0 (the default),MySQLandPostgreSQLdatabases are also hidden fromsystem.tables,system.columns, andsystem.completions, in addition to data lake catalogs. The old setting name is kept as an alias. #104416 (Pablo Marcos). - The default x86 build now targets x86-64-v3 (AVX2) instead of x86-64-v2 (SSE4.2). This requires a CPU with AVX2 support (Intel Haswell or later, AMD Excavator or later). If your CPU does not support AVX2, use the
amd64compatbuild which targets plain x86-64. #105019 (Raúl Marín). - Reject nested
Dynamic/Variantinmin/maxaggregates andminmaxindexes. Previously only top-levelDynamic/Variantwere checked. Closes #104747. #105468 (Pavel Kruglov). icebergHashandicebergBucketnow rejectInt128,UInt128,Int256,UInt256, andDecimal256arguments with an explicit error. Previously they silently truncated wider values and produced colliding hashes. The Iceberg spec only defines hashing for 32/64-bit integers and decimals with precision up to 38; cast toInt64orDecimal128to keep the previous behaviour for values that fit. #105866 (Raúl Marín).- Added granular control over query echoing in the CLI. The
--echooption now accepts an optional boolean value and works in both interactive and batch mode. New options--echo-formattedand--echo-query-idcontrol whether echoed queries are formatted and whether thequery_idis printed, respectively. The--hilite/--highlightoption now also controls highlighting of echoed queries. As a side effect,--echois now a boolean-value option, so a positional query directly after a bare--echois treated as its value; use--echo --query "..."or--echo=falseinstead. #106191 (Alexey Milovidov). - Removed the experimental KQL (Kusto) functions
array_sort_ascandarray_sort_desc, and their SQL backendskql_array_sort_ascandkql_array_sort_desc. These functions were experimental, implemented with low quality, and the source of correctness and parser bugs. Queries using these names now returnUNKNOWN_FUNCTION. #108101 (Groene AI). ALTER TABLE ... REPLACE PARTITION ... FROM ...no longer silently drops the destination partition’s data when the source table has no parts in the requested partition. Previously such a request removed the destination partition and wrote nothing in its place — a data-loss footgun. It is now rejected withBAD_ARGUMENTSby default. To restore the previous silent-clear behavior, set the new settingallow_replace_partition_from_empty_source = 1, or setcompatibilityto26.5or lower; to explicitly drop destination data, useALTER TABLE ... DROP PARTITION. #104939 (Groene AI).- The default of the server setting
insert_deduplication_versionchanges fromcompatible_double_hashestonew_unified_hash. Insert deduplication now works on the whole inserted block (per insert) rather than per part/partition: a retry of the same insert is still deduplicated, but two different inserts that produce an identical part are no longer cross-deduplicated, and reordered inserts of the same rows are no longer deduplicated. Setinsert_deduplication_version = compatible_double_hashesto restore the previous behavior. Instances upgrading directly from a release that defaulted toold_separate_hashesshould first run withcompatible_double_hashesuntil the longest relevant deduplication window has elapsed before relying onnew_unified_hash. #107886 (Sema Checherinda).
New Feature
- Added support for continuous queries over
MergeTreetables, implemented via a series of snapshot reads. This is a first step toward general support for streaming queries. #105114 (Mikhail Artemenko). - Added hypothetical (what-if) skip indexes. Use
CREATE HYPOTHETICAL INDEX ... ON t (expr) TYPE ...to define a session-scoped virtual skip index, thenEXPLAIN WHATIF SELECT ...to estimate its skip ratio and cost without materializing it. Defined indexes are visible in the newsystem.hypothetical_indexestable. #104608 (Yarik Briukhovetskyi). - Add an embedded
/schemaweb UI toclickhouse-serverthat visualizes the dependency graph between tables, materialized views, refreshable materialized views, dictionaries, distributed tables and views. #105276 (Nikita Mikhaylov). - Added the
PNGoutput format support, allowing query output results to be directly rendered as PNG images. #74691 (Maksim Dergousov). - Added detection of the AI coding agent (Claude Code, Cursor, Codex, Gemini CLI, Goose, etc.) that invoked
clickhouse-clientorclickhouse-local, based on environment variables. The detected agent is reported in the newclient_agentcolumn ofsystem.query_log,system.query_thread_logandsystem.processes. #106619 (Alexey Milovidov). - Added a new system table
system.documentationthat collects the embedded reference documentation of the uniform components of the system (functions, table engines, data types, settings, formats, and others) into a single table, with the documentation rendered as Markdown. #107463 (Alexey Milovidov). - Add the
GeoJSONinput format for reading GeoJSONFeatureCollectiondocuments, producing one row per feature withid(String),geometry(Geometry), andproperties(Nullable(JSON)) columns.Point,LineString,MultiLineString,Polygon, andMultiPolygongeometries are read into ClickHouse’s nativeGeometrytype.GeometryCollectionandMultiPoint, which theGeometrytype cannot represent, raise an exception by default, or can be stored asNULLvia theinput_format_geojson_unsupported_geometry_handlingsetting. Contributes to #91533. #98124 (Mark Needham). - Added functions for serving Mapbox Vector Tiles directly from SQL:
MVTEncodeGeomprojects a geometry into the pixel space of a slippy-map tile and clips it,MVTEncodeaggregates the projected geometries of a group into the binary bytes of a single-layer tile, andMVTBoundingBox/MVTBoundingBoxMercatorreturn the bounding box of a tile for restricting rows to it. Point, line and polygon geometry is supported. Also available under the PostGIS aliasesST_AsMVTGeomandST_AsMVT. #106107 (Saarthak Gupta). clickhouse-localnow supportsSYSTEM START LISTENandSYSTEM STOP LISTENqueries, allowing it to be transformed into a server accepting TCP and HTTP connections. #101143 (Alexey Milovidov).- Added an interactive
helpcommand toclickhouse-clientandclickhouse-local. Typinghelp <name>(also/help,man,/man) shows the documentation of a function, table engine, data type, format, setting, or other component, rendered from Markdown in the terminal with syntax-highlighted SQL. When the word is ambiguous all matches are shown, and when it is not found, similar names are suggested. #108042 (Alexey Milovidov). - Support writing into Azure Data Lake Storage Gen2. #105406 (Konstantin Vedernikov).
- Adding
RowBinaryWithNamesAndTypesAndDefaultsformat to get better support for schema evolution. #105736 (Mark Zitnik). - Implement
ADD ENUM VALUESinALTER TABLEqueries to simplify appending new values to an existingEnumtype without the need to specify all currentEnumvalues again. #93830 (Ilya Golshtein). - Refreshable materialized view now supports
REFRESH DEPENDS ONto trigger refreshes on another RMV’s refreshes instead of time-based schedule. (REFRESH EVERY ... DEPENDS ONalready existed, but couldn’t be used reliably for this use case.) SeeCREATE MATERIALIZED VIEWdocumentation. #104440 (Michael Kolupaev). - Add support for selecting columns by name pattern with
* LIKE '<pattern>'and* ILIKE '<pattern>', including qualified forms such astable.* LIKE '<pattern>'andtable.* ILIKE '<pattern>'.LIKEmatches column names case-sensitively,ILIKEcase-insensitively. #104569 (Yue Ni). - Added
ESCAPEsyntax that defines a custom escape character in aLIKEpattern, allowing you to treat%and_as literal characters instead of wildcards. #99774 (Ilya Yatsishin). - Add
materialize_projections_on_insertandmaterialize_projections_on_mergeMergeTreetable settings. Whenmaterialize_projections_on_insert = 0,INSERTs skip building projection parts, which improves insert throughput for tables with many projections. Whenmaterialize_projections_on_merge = 1, a merge rebuilds a projection that is missing from all of its source parts, so projections can be built during merges instead of on insert. Merges still combine only parts that share the same set of projections. #100993 (Christoph Wurm). - Add a new immutable
MergeTreesettingallow_tuple_element_aggregation, disabled by default. When enabled,SummingMergeTree,AggregatingMergeTreeandCoalescingMergeTreerecursively flattenTuplecolumns and aggregate each leaf element independently during merges, exactly as if it were a top-level column —SummingMergeTreesums it,AggregatingMergeTreemerges its aggregate-function state, andCoalescingMergeTreekeeps its last non-NULL value. The setting must be specified at table creation time and is silently ignored by engines that do not support it. #98039 (johnjing). - New functions
quantizeBFloat16ToInt8anddequantizeInt8ToBFloat16: a scalar codec that compresses embedding components to 8-bit using a 256-level Gaussian Lloyd-Max quantizer, from which Int4/Int2/binary codes can be extracted by bit-truncation. #108102 (Alexey Milovidov). - Add functions
arrayTopKandarrayBottomK: -arrayTopK(k, array)returns the K largest elements in descending order -arrayBottomK(k, array)returns the K smallest elements in ascending order. #104563 (Vitaly Baranov). - Added a new system table
system.iceberg_filesexposing per-file metadata forIcebergtables, with one row per data or delete file in each table’s current snapshot. This closes #98777. #104415 (Asya Shneerson). - Added
system.constraintstable that provides information about allCHECKandASSUMEconstraints across all tables, including constraint name, type, and expression. #105337 (Pedro Ferreira). - Added a new
system.dictionary_layoutstable that lists the available dictionary layouts together with embedded documentation (description,syntax,examples,introduced_in,related). #106182 (Alexey Milovidov). - Added a new
system.dictionary_sourcestable that lists the available dictionary sources together with embedded documentation (description,syntax,examples,introduced_in,related). #106184 (Alexey Milovidov). - Added a new
system.data_skipping_index_typestable that lists the available data skipping index types together with embedded documentation (description,syntax,examples,introduced_in,related). #106186 (Alexey Milovidov). - Added a new
system.disk_typestable that lists the available disk types together with embedded documentation (description,syntax,examples,introduced_in,related). #106187 (Alexey Milovidov). - Implemented
SYSTEM RESTART DISK <name>: it now reloads a disk’s in-memory metadata and re-scans the data parts of readonly-replica tables located on it. This lets a readonly replica of a table on sharedplain_rewritablestorage observe data written by another server on demand, without waiting forrefresh_parts_intervalor restarting the server. #106645 (Jordi Villar). - PostgreSQL-style
expr OP SOME(array)/expr OP ALL(array)(non-subquery right-hand side) is now supported and rewritten tohas/NOT hasfor=/<>, or toarrayExists/arrayAlllambdas for other comparison operators.ANYis not accepted for the array form becauseanyis also an aggregate function; useSOMEinstead. The subquery form ofANY/SOME/ALLcontinues to be lowered toIN/NOT IN. #105129 (Alexey Milovidov). - Added two new
load_balancingstrategies,hostname_longest_common_prefixandhostname_longest_common_suffix, which prefer the replica whose hostname shares the longest common prefix (respectively, suffix) with the initiator’s hostname. They are useful when the data center is encoded as a prefix or suffix of hostnames whose numeric segments have variable length, where the existingnearest_hostnameandhostname_levenshtein_distancestrategies pick the wrong replica. #107360 (Denny [DBA at Innervate]). - Added TLS client certificate information (subjects, serial number, issuer, and validity period) to the
system.session_logtable to improve observability of certificate-based authentication. #107679 (Alexey Milovidov). - Add an optional
external_idcredential forS3role-based access. #106941 (Elian Gidoni). - Added a new
S3Queuesettingafter_processing_move_preserve_path. When enabled together withafter_processing='move'andafter_processing_move_prefix, processed objects are moved while preserving their full source path under the destination prefix instead of being flattened to just the file name. #105354 (Asya Shneerson). - Add
message_queue_disable_insertionserver setting to disable insertion from message queue engines (Kafka,RabbitMQ,NATS) into attached materialized views. Useful for read-only replica scenarios. #104911 (JIaQi Tang). - Added
LOCALTIMEandLOCALTIMESTAMP(SQL-standard / PostgreSQL syntax).LOCALTIMESTAMPis an alias fornow()(returnsDateTime);LOCALTIMEreturns the current time of day as aTimevalue. #106139 (Thomas Cabral). - Added
date_part('unit', expr)as syntactic sugar forEXTRACT(unit FROM expr). Standard interval kinds and the PostgreSQL extras (epoch,dow,doy,isodow,isoyear,century,decade,millennium) are all supported. #105127 (Alexey Milovidov). - PostgreSQL-compatible
EXTRACT(TIMEZONE_HOUR FROM dt)andEXTRACT(TIMEZONE_MINUTE FROM dt)for the hour and minute parts of a timezone offset, andEXTRACT(<unit> FROM INTERVAL n <unit>)/date_part('<unit>', INTERVAL n <unit>)for extracting the value out of an interval. #106227 (Vinayak Joshi). - Added
min_byandmax_byaggregate aliases forargMinandargMax. #105712 (Joey Yu). These aliases are stupid, real engineers use the original ClickHouse names. - Added
REGEXP_SUBSTRas a case-insensitive alias ofregexpExtractfor Oracle/MySQL/Snowflake compatibility. #105122 (Alexey Milovidov). - Added
SESSION_USERas a case-insensitive alias ofcurrentUser()for PostgreSQL / SQL-standard compatibility. #106081 (Takumi Hara). - Support a trailing
NULL/NOT NULLmodifier inALTER TABLE ... ADD/MODIFY COLUMN, mirroringCREATE TABLE. #106150 (Takumi Hara). - You can now use
h3PolygonToCellsWithContainmentfunction from h3 to use their new algorithm which supports center-based, fully-contained, and overlapping containment modes. #104455 (Youssef Kadry). - Adds
IPV4_PREFIX_BITS and IPV6_PREFIX_BITSflags when Keying done byIP_ADDRESSorFORWARDED_IP_ADDRESS. #89270 (Aditya Chopra). formatReadableTimeDeltanow accepts anINTERVALexpression of type other thanMonthandYearas input. #64315 (Francisco J. Jurado Moreno).- User can now specify an optional precision argument to the
formatReadableSize,formatReadableDecimalSizeandformatReadableQuantityfunctions, controlling the number of digits after the decimal point. Default is 2, preserving the prior behavior. #104648 (Antonio Filipovic). - Add
output_format_float_precisionsetting to control the number of decimal digits in floating-point text output. #99721 (phulv94). - Added a setting
output_format_always_write_decimal_point_in_float_and_decimalto always print a decimal point for floating-point andDecimalnumbers in text formats, even when the value is a whole number. For example, output1.instead of1. Disabled by default. #62614 (Ilya Yatsishin). - Add support for new HTTP handler configuration elements
<url_prefix>and<full_url_prefix>(match all paths under a base path, useful e.g. for Prometheus handlers), as well as<url_regexp>,<full_url_regexp>, and<headers_regexp>. The old<url>regex:...</url>form is now obsolete. #107492 (Vitaly Baranov). - Support
basicstatistics, a compact per-column statistic that stores numeric min/max, average string length, and NULL counts where applicable. #106048 (Han Fei). - Support TTL nodes in ClickHouse Keeper, opt-in via the
create_ttlfeature flag. #100397 (Konstantin Vedernikov). - Introduce a memory reservation feature for workloads. See the workload scheduling documentation. #82414 (Sergei Trifonov).
Experimental Feature
- Multi-stage distributed query execution: the planner splits the query plan into stages connected by scatter / broadcast / gather / shuffle exchanges and dispatches the plan fragments to worker nodes. The data between stages is streamed via TCP or passed via temporary files in shared object storage, the path supports distributed shuffle and broadcast hash joins, shuffle aggregation, and distributed sort. The feature is experimental and is disabled by default. #106020 (Alexander Gololobov). The experimental distributed query plan engine (
make_distributed_plan) can now use a different task-dispatch and streaming-exchange port per worker, configured per replica in<remote_servers>withstateless_worker_portandstreaming_exchange_port. When unset, the previous server-level ports (stateless_worker_client.portanddistributed_query.streaming_exchange_port) are used. This makes it possible to run several workers on one host. #107885 (Alexander Gololobov). - Added the experimental
dphypjoin reordering algorithm for inner joins as an option for thequery_plan_optimize_join_order_algorithmsetting, and thequery_plan_optimize_join_order_max_searched_planssetting, which bounds the join-order search and falls back to the next algorithm in the chain when the bound is exceeded; set it to0to keep the previous unbounded search behavior. #98798 (Alexander Gololobov). - Add
aiEmbedfunction for using LLM APIs to generate embeddings from within ClickHouse. #102922 (George Larionov). - Added an experimental Linux OOM canary: a sacrificial child process that the Linux OOM killer targets before the main server process. When enabled with
oom_canary_enable, it sheds memory pressure by purging allocator caches, cancelling queries, cancelling merges, and recording an event insystem.crash_log. The OOM response requires cgroup v2memory.eventsOOM-kill evidence. #101942 (Peng). - The web terminal interface at
/webterminalis now a production feature and is enabled by default. It is controlled by the newenable_webterminalserver setting; the formerallow_experimental_webterminalsetting is deprecated but still honored for backward compatibility. To disable the endpoint, setenable_webterminaltofalse. #106255 (Alexey Milovidov). - PromQL HTTP endpoints now support specifying the database and table via URL query parameters (
database=,table=, ortable=db.table). The previous implicitdefault.prometheustable fallback is removed: if neither the handler config nor the URL specifies a table, the handler now returnsThe time series table name is not set. To keep the old behavior, configure<table>default.prometheus</table>or passtable=...in the URL. #107553 (Vitaly Baranov). - Added support for the PromQL
histogram_quantilefunction inprometheusQueryandprometheusQueryRangetable functions. This enables computing quantiles over classic Prometheus histogram buckets identified by thelelabel. #103477 (Joe Smith). - Added lazy posting list apply mode for the text index. When enabled via
SET allow_experimental_text_index_lazy_apply = 1andSET text_index_posting_list_apply_mode = 'lazy', posting lists are decoded on demand at packed-block granularity using a cursor-based approach instead of being fully materialized into Roaring Bitmaps, reducing memory usage and CPU time for selective text index queries. #100035 (Peng). - Added support for the AssemblyScript ABI for WebAssembly UDFs. You can try the AssemblyScript ABI without installing the toolchain locally by using the browser-based playground, which compiles AssemblyScript code and loads the resulting WebAssembly module into local ClickHouse. #104606 (Vladimir Cherkasov).
- Allow for attaching Prometheus handlers on the main HTTP port with an optional prefix. #104975 (James Cunningham).
- Added an experimental
MergeTreesettingpacked_skip_index_max_bytesthat bundles small skip-index substreams into a singleskp_idx.packedarchive per part, reducing inode pressure when many skip indices are defined on a table. The decision is per substream at write time: substreams whose serialized size stays under the threshold go into the archive, anything larger keeps the standaloneskp_idx_<name>.idx2/.mrk2layout. A single part can mix layouts. Full-text indices are not supported and are always per-file. Default is 0 (packing disabled). #105321 (Raúl Marín). - Support
Buffersserialization for WebAssembly UDFs usingABI BUFFERED_V1, and addwebassembly_udf_enable_fuelas a persisted WASM UDF function setting. #105574 (Antonio Andelic). - Add an experimental
use_reader_executorsetting (default off) that routes reads through a new pipeline-basedReaderExecutorinstead of the legacy chain of read buffers. #106570 (Sema Checherinda). Added observability metrics for the experimentaluse_reader_executorread path, including a modeled read-cost KPI (ReaderExecutorModeledCostMsPerRequestedMiB). #106968 (Sema Checherinda). Introduced theChainedBuffersbuffer behind the experimentaluse_reader_executorread path, with aReaderExecutorChainedBufferBytesmetric. #107210 (Sema Checherinda). - Descending sort order in
MergeTreesorting keys (e.g.ORDER BY (time DESC, key)) is now always supported and no longer requires the experimental settingallow_experimental_reverse_key, which became obsolete. #106440 (Nikita Mikhaylov). Nullable(Tuple(...))is now Beta. Disabled by default, setenable_nullable_tuple_type = 1to use it. #107754 (Nihal Z. Miaji).
Performance Improvement
- Various changes to Keeper that make it around 2x faster overall (better batching, pipelining messages to leader, pipelining log appends). #101757 (Michael Kolupaev).
- Reduce per-query overhead for simple
SELECTqueries (parsing, analysis and planning). For example,SELECT count() FROM hitsfrom a single connection is roughly 50% faster. #104513 (Raúl Marín). - Optimize primary key index analysis for long and high-cardinality primary keys. For a long primary key, the run time of index analysis now mainly depends on the complexity of the query’s filter (the key columns it actually uses), not on the length of the primary key — so extending the sorting key has negligible extra overhead on index analysis for queries that filter on only a few of its columns. For a high-cardinality primary key, where ClickHouse keeps only a selective prefix of the key columns in memory and does not load the trailing ones, index analysis now works on just that in-memory prefix instead of the whole key. The optimization is enabled by default and can be turned off with the new setting
use_lightweight_primary_key_index_analysis. Closes #65103. #91836 (Nihal Z. Miaji). - The default x86 build now targets x86-64-v3 (AVX2) instead of x86-64-v2 (SSE4.2). This requires a CPU with AVX2 support (Intel Haswell or later, AMD Excavator or later). If your CPU does not support AVX2, use the
amd64compatbuild which targets plain x86-64. #105019 (Raúl Marín). - Use
ipnsortanddriftsort(stable sorting) — C++ ports of the Rust standard library’s sort implementations — for the general-purpose comparison sorts. Speeds upORDER BYon non-numeric columns and stable sorts, and removes a worst case on reverse-sorted input. #106650 (Alexey Milovidov). - New
GROUP BYoptimization for high cardinality evenly distributed keys that scatters rows across threads by hashing the grouping key, so each thread aggregates a disjoint subset of keys without a merge phase. Setenable_sharding_aggregator = 1to enable it. #104233 (Nihal Z. Miaji). - Enable hash table prefetching for string key
GROUP BYqueries, improving high-cardinality string aggregation performance by ~8%. #101007 (Le Zhang). - Reduced peak memory usage when merging partial two-level aggregation results with large aggregate states (e.g.
groupArray), by freeing each bucket’s source states incrementally during the merge instead of keeping them all alive until the merge completes. #102330 (Yuri Fedoseev). - Memory representation of
EnumDataTypewas optimized. Memory footprint of tables that haveEnumtype in it can improve up to 10x times forEnumcomponent. Operation time to retrieve name by value(number) is similar or faster. Search by name is slightly slower, but this access direction is less common. #95668 (Ilya Yatsishin). - Add identifier resolution caching to prevent duplicate identifier resolution during query analysis. #88043 (Max Justus Spransy).
- Improve performance of query analysis for queries over tables with many columns: avoid computing column node hashes (which include the whole source table expression) when not needed. Analyzing nested
SELECT *subqueries over a table with ~1200 columns is now about 50 times faster. #106957 (Dmitry Novik). - Sped up query analysis for queries with many or deeply nested function calls by removing a redundant query-tree hash from the function resolution cache. #107516 (Dmitry Novik).
- Fixed long login and query-startup stalls with replicated access storage when many access entities (row policies, roles, quotas, settings profiles) change at once. Each per-entity cache now recomputes once per notification batch instead of once per changed entity, removing quadratic work that could hold the access lock for minutes. #107672 (Azat Khuzhin).
- Share the hash join’s
FixedHashMapas the join runtime filter on the probe side. When the build-side hash table is (or can be converted to) aFixedHashMap, it is published as the runtime filter and replaces theSet/BloomFilterthatBuildRuntimeFilterStepwould otherwise install. Controlled by the new settingjoin_runtime_filter_from_fixed_hash_table(defaulttrue). #105640 (Xiaozhe Yu). - Lazy application of selector and replication indexes in case of
JOINfollowed by a selectiveLIMITorTopNor anotherJOIN. To control the number of payload columns for enabling lazy selector indexes use the settingquery_plan_min_columns_for_join_lazy_indexing(0 means the optimization is disabled). To control theLIMITfor which the optimization is applied use the settingquery_plan_max_limit_for_join_lazy_indexing. #106566 (Hechem Selmi). - DP (dynamic programming) JOIN reordering is now allowed with parallel replicas. #105889 (Nikita Taranov).
- Improved query plan when JOIN uses runtime filters (default-on
enable_join_runtime_filters): the join-reorder cost model now sees throughWindowTransform(and other row-preserving plan steps) on the right subtree and uses the underlying row count and per-column NDV instead of falling back to no statistics. #107229 (UnamedRus). - De-virtualize the emission of non-joined rows in RIGHT and FULL join by batching them. #105679 (Hechem Selmi).
- Support packed
keys32andkeys64methods inHashJoin. #107202 (Nikita Taranov). - Support packed
keys32andkeys64methods inSet. #107564 (Nikita Taranov). - More optimal handling of nullable columns in aggregation. #106015 (Nikita Taranov).
- Improve performance of
LIMIT BYqueries. #103349 (Nihal Z. Miaji). - Speed up
ORDER BY ... LIMIT BYqueries by runningLIMIT BYinside each parallel sorted stream duringSortwhenLIMIT BY’s columns are a prefix of theORDER BY. This reduces the number of rows flowing through the final sort merge and any downstream pipeline steps. This optimization is controlled by the new settingquery_plan_push_limit_by_into_sort(enabled by default). #104000 (Nihal Z. Miaji). - Speed up
SELECT ... LIMIT N BY <cols>queries when<cols>are a prefix of the table’s sorting key, or become one afterWHERE col = constfixes leading columns. With this enabled theMergeTreereads data in primary-key order andLIMIT BYfirst filters in streaming mode with O(1) memory per sorted stream which filters out most of the data, then finally running normalLIMIT BYon reduced data to get the final result. Controlled by the new settingoptimize_limit_by_in_order(enabled by default). #105135 (Nihal Z. Miaji). - Speed up
LIMIT BYqueries on partitionedMergeTreetables by runningLIMIT BYinside each partition’s stream in parallel, instead of merging all streams into one before applying the limit. This applies when the partition expression is a deterministic function of theLIMIT BYcolumns, so noLIMIT BYgroup can span two partitions. Controlled by the new settingallow_limit_by_partitions_independently(enabled by default). #105126 (Nihal Z. Miaji). - Speed up
LIMIT BYqueries by removing redundant key expressions: a key that is a deterministic function of the other keys is dropped (e.g.LIMIT 5 BY x, f(x)becomesLIMIT 5 BY x), and an injective function of a key is replaced by its argument (e.g.LIMIT 5 BY toString(x)becomesLIMIT 5 BY x). This evaluates fewer and cheaper expressions per row. Controlled by the new settingsoptimize_limit_by_function_keysandoptimize_injective_functions_in_limit_by, both enabled by default. #106818 (Nihal Z. Miaji). - Speed up sharded aggregation,
grace_hashjoin bucketing, and parallel window partitioning by replacing per-chunk column hashing with a kernel that uses hardware CRC32C. #106538 (Harikrishnan Prabakaran). - Optimize
L1Distance,L2Distance,L2SquaredDistance,LinfDistance, andcosineDistancefor array arguments with multi-target auto-vectorization on x86-64-v4/v3. For non-const array arguments, all of these exceptLpDistance, which usesstd::powwith a runtime exponent, can now use compiler-vectorized kernels. The existing AVX-512 and Sapphire RapidsBFloat16const-argument fast paths forL2DistanceandcosineDistanceare preserved. #101310 (Peng). - Improved performance of the
{Norm}DistanceanddotProductfunctions. #106007 (Nikita Taranov). - Improved performance of the
arrayNormfunction. #106211 (Nikita Taranov). - The performance of
dotProductimproved in some cases. #106210 (Nikita Taranov). - Improved performance of the AVX-512 const-left paths for
L2DistanceandcosineDistanceonArray(Float32),Array(Float64), andArray(BFloat16)when the array length is exactly divisible by the vectorized processing width. #104625 (Sergey Kuznetsov). - Enabled AVX-512 codegen for amd and better codegen for
arrayDistance. #106505 (Nikita Taranov). - Improved performance of the
L2DistanceTransposedandcosineDistanceTransposedfunctions for theQBitdata type. #106701 (Raufs Dunamalijevs). - Improve performance of the
encrypt,decrypt,tryDecrypt,aes_encrypt_mysql, andaes_decrypt_mysqlfunctions by up to an order of magnitude, recovering the performance lost in the BoringSSL to OpenSSL 3.x migration (24.4). #107339 (Konstantin Bogdanov). - Improve performance of the
encrypt,decrypt, andhalfMD5functions by avoiding implicit per-row OpenSSL provider lookups in OpenSSL 3.x. #99105 (Konstantin Bogdanov). - Add SIMD implementation of
SHA1that hashes multiple inputs in parallel using AVX-512, improving throughput. #105459 (Joanna Hulboj). - Added an AArch64 ASIMD/NEON backend for the multi-buffer
MD5implementation. #105563 (Venkata Vineel ). - Squash source blocks before calculating projection during
MATERIALIZE PROJECTIONto reduce the number of temporary projection parts and merge overhead. ~3.4x speedup on a 50M-row table. #100047 (Amos Bird). - Reduced
INSERTlatency forMergeTreetables with skip indices onORDER BYcolumns by avoiding redundant column permutations during part writing (~17% on traces-shaped workloads). #101101 (Amos Bird). - Enabled Arrow’s SIMD code paths (NEON on ARM, SSE4.2/AVX2/AVX512 on x86) and used them to speed up decoding of
BYTE_STREAM_SPLIT-encoded ParquetFLOAT/DOUBLEcolumns. #106376 (Raúl Marín). - Improved insertion performance for
LowCardinalitycolumns withbloom_filterindexes. #106410 (Michael Jarrett). - Parallelize blob copies in
DiskObjectStorageTransaction::copyFileusing a per-disk thread pool. #105089 (Asya Shneerson). - Avoid reading file contents when using the
Oneinput format with file-like table functions such asfileands3. #105157 (Yue Ni). - Speed up
clickhousestartup on macOS by about 3x by not exporting dynamic symbols, which the dynamic linker would otherwise process on every launch. #107768 (Raúl Marín). - Speed up filesystem cache loading on startup by avoiding a redundant directory open per cache key. #107414 (Alexey Milovidov).
- Speed up filesystem cache loading on startup by letting directory-listing threads help load cache metadata once listing is finished, instead of leaving half the threads idle. #107416 (Alexey Milovidov).
- Reduced
clickhouseprocess startup overhead by updating the bundled WasmEdge library, which no longer generates a random hash secret in a global initializer at every startup. #107869 (Raúl Marín). - The
MergeTreeprimary key and skip indexes can now prune granules for filters whereifNullorcoalescewraps a condition, such asifNull(key = 0, 0)orcoalesce(key = 0, 0). Such predicates — often emitted by query generators to turn a possibly-NULLcomparison into a definite boolean — were previously opaque to index analysis and could not skip granules. This extends the existingallow_key_condition_coalesce_rewritesetting (enabled by default). Closes #106264. #106272 (Andy Zhao). - Skip index evaluation on
DateTime64types should consume lesser CPU in 26.6. #107707 (Shankar Iyer). - Improved performance of text index analysis in multi-token searches by optimizing handling of rare tokens. #98226 (Anton Popov).
- Use a cache for the posting-list compressed segments of the text index. #106299 (Anton Popov).
- Improved the performance of generic exclusion search for queries that select large consecutive ranges of the table. #93813 (Michael Jarrett).
S3clients with the same endpoint and bucket share a cache, avoiding duplicate region discovery. Closes #92482. #96802 (Andrey Zvonov).- If a query contains a
has(<constant array>, <expr>), the analyzer will transform the node to use a fasterinimplementation if it is feasible to do so. #97341 (Shankar Iyer). - When a new job is scheduled in
ThreadPool, wake the most recently idle worker thread (LIFO) instead of an arbitrary one. This reduces memory fragmentation from per-thread allocator caches. The order in which jobs are processed is not changed. #100177 (Alexey Milovidov). - Improved performance of approximate runtime filters and bloom filter indexes. #100201 (Christoph Viebig).
- Allow
ASOF JOINto use theparallel_hashjoin algorithm, parallelizing the build across distinct equality-key values. PreviouslyASOFwas unconditionally opted out ofparallel_hash. #105375 (Greg Maher). - Avoid reading unbounded inputs for
INTERSECTandEXCEPTqueries when an empty input makes the result known to be empty. #105393 (Yue Ni). - Add
constinitfor variousMemoryTrackerblockers. #105490 (Azat Khuzhin). - Improve performance of
bitmapContainsfor non-UInt64groupBitmapstates by avoiding repeatedrb_maxcalls during range checks. #105960 (Yue Ni). - Faster discontinuous queries for
LowCardinalitycolumns backed by a single dictionary. #103662 (Ivan Babrou). - Added a fast path for the
HashJoinprobe when the block has a single row. #106008 (Nikita Taranov). - Predicates from queries like
SELECT ... FROM view(SELECT ... FROM remote(...)) WHERE ...are now pushed into the query sent to the remote shard. The optimizationallow_push_predicate_ast_for_distributed_subquerieslacked a case for table functions. #105986 (Nikolai Kochetov). - Turn on
enable_join_transitive_predicatesby default. #103724 (Alexander Gololobov). - Added support for functions
multiSearchAny,multiSearchAnyUTF8, andmultiMatchAnyin text indexes. Also improved text index analysis for the functionmatch: now patterns with alternative groups can skip more granules. #106279 (Anton Popov). - Allow filters introduced after the initial PREWHERE selection (predicate pushdown, runtime filters, or explicit PREWHERE plus a WHERE set by the planner) to be merged into the existing PREWHERE on a second optimizer pass instead of staying as a separate Filter step above the
MergeTreeread. #105445 (Yarik Briukhovetskyi). - The
QueryConditionCachenow records individually filtered-out granules even within read batches that partially pass PREWHERE, reducing the number of marks re-read by subsequent queries with the same condition. #105335 (Han Fei). - Added Keeper setting
nuraft_use_bg_thread_for_snapshot_io, enabled by default, to makeNuRaftread snapshot objects from a background thread instead of Raft worker threads. #106285 (Antonio Andelic). - Reduce peak memory usage when applying received snapshots in ClickHouse Keeper with
KeeperMemoryStorage. #105851 (Antonio Andelic). - Route LLVM/JIT allocations to a dedicated jemalloc arena. Reduces RSS fragmentation caused by interleaving long-lived JIT bookkeeping with short-lived query allocations. Adds new asynchronous metrics
jemalloc.jit_arena.active_bytes,jemalloc.jit_arena.dirty_bytes,CompiledExpressionCacheBytesMax, andCompiledExpressionCacheCountMaxfor observability.SYSTEM DROP COMPILED EXPRESSION CACHEnow also drops the underlying CHJIT instances and purges the JIT arena. #104113 (Raúl Marín). - Fix excessive memory reservation when reading sparse dictionary-encoded
Nullable(String)columns fromParquetwith the native V3 reader. #102805 (Francisco). - Fixed
CREATE TABLE ... CLONE AS (and REPLACE / ATTACH PARTITION ... FROM)on encrypted disks copying data instead of hardlinking it. #106731 (Nikita Mikhaylov). - Improve cardinality estimation in the query plan optimizer: a column produced by a deterministic single-argument function (e.g.
toYear(date)) now inherits its argument’s number of distinct values as an upper bound instead of being left without statistics, leading to more accurate join reordering. #107757 (Alexander Gololobov). - Reduced CPU overhead of asynchronous logging under high log rates by notifying the log consumer only on the empty-to-non-empty queue transition instead of on every message. #107352 (Nikita Mikhaylov).
- Remove duplicate calculations during query execution in more scenarios. #106113 (Yarik Briukhovetskyi).
- Parallelize the processing of a recursive CTE’s result: a
GROUP BYor other operation over a largeWITH RECURSIVEresult is no longer limited to a single thread. #107694 (Alexey Milovidov). - Improved the performance of case-insensitive substring search (
positionCaseInsensitiveUTF8,ILIKE,multiSearchAnyCaseInsensitiveUTF8, and related functions) by adding a NEON SIMD path on ARM and a wider AVX2 kernel on x86. #107882 (Raúl Marín). - Fixed a ~16% throughput regression of the
FPCfloating-point codec on ARM that was introduced when its predictor tables started usingVectorWithMemoryTracking. #108182 (Groene AI).
Improvement
- The background
MemoryWorkernow periodically updates the server’s hard memory limit based on the current memory usage and the amount of memory the kernel reports as available, so ClickHouse leaves room for other processes running on the same host. The formula is(resident memory + system MemAvailable) * max_server_memory_usage_to_ram_ratio. The samemax_server_memory_usage_to_ram_ratioserver setting controls both the startup cap and the dynamic adjustment; set it to0to disable both. To keep only the static startup/reload cap (the behavior of previous versions), set the new server settingmemory_worker_dynamic_hard_limitto0. #104964 (Alexey Milovidov). - Support C# PostgreSQL client in
PostgreSQLprotocol. This closes #18611. #80785 (Konstantin Vedernikov). - Mutations now use the analyzer. #98884 (Nikolai Kochetov).
- Added granular control over query echoing in the CLI. The
--echooption now accepts an optional boolean value and works in both interactive and batch mode. New options--echo-formattedand--echo-query-idcontrol whether echoed queries are formatted and whether thequery_idis printed, respectively. The--hilite/--highlightoption now also controls highlighting of echoed queries. As a side effect,--echois now a boolean-value option, so a positional query directly after a bare--echois treated as its value; use--echo --query "..."or--echo=falseinstead. #106191 (Alexey Milovidov). - Support schema evolution together with concurrent consistency checks for data lake catalogs. #106102 (Konstantin Vedernikov).
- Allow cache disk for datalake table engines. #102017 (RinChanNOW).
- Fix
DataLakeCatalogdatabases withcatalog_type = 'onelake'reading table data by using the OneLake Blob endpoint (.blob.fabric.microsoft.com) by default. Setonelake_use_blob_endpoint = falseto keep the previous DFS endpoint (.dfs.fabric.microsoft.com) behavior. #106843 (Konstantin Vedernikov). - Update default of
S3(Azure)Queuesettingpersistent_processing_node_ttl_secondsfrom1 hourto6 hours(which stands for cleanup time due to service unclean restart etc). The previous default was fine for processing nodes ttl, but it is also used for bucket lock ttl, which can be hold for longer time, therefore 1 hour was not enough. #106838 (Kseniia Sumarokova). - Decreased the default size of the
Icebergmetadata cache from 1 GB to 128 MB. #106492 (Konstantin Vedernikov). - Propagate the
S3Queuestreaming taskquery_idto dependent table inserts. #106494 (Christoph Wurm). - Populate
used_storagesinsystem.query_logwith the storage engine name when querying tables viaDataLakeCatalog. #100706 (Melvyn Peignon). - You can check which ‘operation’ and what ‘summary’ Iceberg’s snapshots have. Useful for testing and debugging. #106246 (Den Kalantaevskii).
- Complete the final
S3multipart upload request asynchronously via the task tracker, so it can overlap with the last part upload instead of running serially in finalize. #105487 (Asya Shneerson). - Added four new
MergeTreetable settings to control default parameters of text indexes:text_index_dictionary_block_size,text_index_dictionary_block_frontcoding_compression,text_index_posting_list_block_size, andtext_index_posting_list_codec. These settings allow tuning text index behavior at the table level without specifying parameters in every index definition. Explicit per-index arguments still take precedence. #100626 (Anton Popov). - Allow projections to override additional
MergeTreesettings (compression, part format, serialization) beyond justindex_granularity, with an allow-list of allowed settings and validation. #101170 (Amos Bird). - Add
current_projection,current_projection_progress,projections_completed, andprojections_remainingcolumns tosystem.mergesto expose projection merge progress. #102611 (Amos Bird). - Fixed
PREWHEREwithINsubquery on primary key columns not using primary key index for granule pruning, causing full table scans instead of reading only relevant granules. #102570 (Nikita Mikhaylov). - Function
h3PolygonToCellsnow enforces the maximum array size across all polygons of aMultiPolygon, validates the underlying H3 library return codes, and rejectsMultiLineStringarguments instead of silently returning an empty result. #106399 (Raúl Marín). - Add a new keeper-only
system.keeper_snapshotstable with information about local ClickHouse Keeper snapshots. #105571 (Miсhael Stetsyuk). - Add a new keeper-only
system.keeper_changelogstable with information about local ClickHouse Keeper changelog (Raft log) files. #105617 (Miсhael Stetsyuk). - Add a keeper-only
system.keeper_clustertable. Contains one row per Raft cluster member as seen by the current Keeper. #105646 (Miсhael Stetsyuk). - Add more Keeper profile (server-side + client-side) events for watches. Closes #97703. #105336 (Konstantin Vedernikov).
- Added Keeper
coordination_settingsforNuRaftuncommitted log entry admission limiting and append-entries backward-probe throttling. #106108 (Antonio Andelic). - Add
enable_compressionsetting for themysqltable function, theMySQLtable engine, theMySQLdatabase engine, dictionarySOURCE(MYSQL), and named collections. When enabled, ClickHouse negotiates MySQL protocol-level compression for all data transferred over the connection. #103229 (Bernard Lim). - Reduced cancellation latency for queries running over the PostgreSQL wire protocol:
KILL QUERYnow interrupts output serialization within a single chunk instead of waiting for the entire chunk to be sent to the client. #106535 (Roman Vasin). - Reduced cancellation latency for queries running over the MySQL wire protocol:
KILL QUERYnow interrupts output serialization within a single chunk instead of waiting for the entire chunk to be sent to the client. #107228 (Roman Vasin). - Fixed reading of the
auth_responselength in the MySQL handshake, where a length byte>= 128was interpreted as a multi-gigabyte value because it was read as a signedchar. #107384 (uwezkhan). MaterializedPostgreSQLnow maps PostgreSQLnumeric(p, 0)columns with precision greater than 76 (e.g.numeric(78, 0)used for 256-bit integers) to ClickHouseInt256instead of failing with “Precision too big”. Values that do not fit intoInt256are rejected with a clear error. #107431 (Alexey Milovidov).- Send an exception to the client when TCP connection setup fails. #107317 (Nikolai Kochetov).
- Users can now insert
AvroFixedfields for 8-bit/16-bit/32-bit/64-bit integer variants. #98139 (Patrick Pichler). - The
AvroConfluentformat now retries the Confluent Schema Registry HTTP client on transient failures (transport timeouts, connection refused, DNS errors, HTTP5xx/408/429) with exponential backoff, instead of aborting the INSERT on the first network glitch. New settingsformat_avro_schema_registry_max_retries(default5) andformat_avro_schema_registry_retry_initial_backoff_ms(default100) control the policy. Schema-validation errors (HTTP409, malformed Avro JSON) remain fatal. #106661 (Groene AI). - Record privileges in
system.query_log.used_privilegesfor all granted access checks, including those that go through the non-throwingisGrantedpath (checkAccessWithFilter). Previously only privileges checked via throwing entry points (checkAccess/checkGrantOption) were recorded, which madeREAD ON FILE/READ ON S3/READ ON AZURE/READ ON URLinvisible in the audit log forDESCRIBE,CREATE TABLE AS, and similar queries that usefile/s3/azure/urltable functions. Access enforcement is unchanged. #104693 (Alexey Bakharew). - Added asynchronous metrics
TotalUncompressedBytesOfMergeTreeTablesandTotalUncompressedBytesOfMergeTreeTablesSystem, reporting the total uncompressed size of data stored in MergeTree-family tables. #106364 (Alexey Milovidov). - Adds the
GlobalMemoryLimitExceededprofile event so operators can monitor when the server-wide memory limit is hit. #106466 (Sacheendra Talluri). - Populate the
ExecutableUserDefinedFunction*ProfileEventscounters forexecutable_poolUDFs. Per-call invocation count, wall and pool-wait time, child-process CPU and peak memory, and stdin/stdout bytes are now visible insystem.query_log.ProfileEvents. #105010 (Xu Jia) #105618 (Ilya Andreev). - Added asynchronous metrics
ExecutableUserDefinedFunctionMemoryResidentBytesandExecutableUserDefinedFunctionProcesses, reporting the resident memory (VmRSS) and number of live processes ofexecutableandexecutable_pooluser-defined functions, including descendant processes and idle pool workers. #107300 (Hanzi Jiang). - Added three Linux-only async metrics —
MemoryThreadStacksCount,MemoryThreadStacksVirtual, andMemoryThreadStacksResident— that report pthread stack memory separately from the rest of anonymous memory. Enabled viaasynchronous_metrics_enable_heavy_metrics. Requires Linux 5.17+ (prctl(PR_SET_VMA_ANON_NAME)) and readable/proc/self/smaps; otherwise the metrics are absent and the limitation is reported insystem.warnings. #106230 (Raúl Marín). - Expose the
MemoryThreadStacks*asynchronous metrics (resident/virtual size and count of thread stacks) on macOS. #107752 (Raúl Marín). - Table engines now carry embedded documentation, introspectable via the new
description,syntax,examples,introduced_in, andrelatedcolumns of thesystem.table_enginestable. #106177 (Alexey Milovidov). - Database engines now carry embedded documentation, introspectable via the new
description,syntax,examples,introduced_in, andrelatedcolumns of thesystem.database_enginestable. #106178 (Alexey Milovidov). - Data types now carry embedded documentation, introspectable via the new
description,syntax,examples,introduced_in, andrelatedcolumns of thesystem.data_type_familiestable. #106180 (Alexey Milovidov). - Input/output formats now carry embedded documentation, introspectable via the new
description,examples,introduced_in, andrelatedcolumns of thesystem.formatstable. #106181 (Alexey Milovidov). - Aggregate function combinators now carry embedded documentation, introspectable via the new
description,syntax,examples,introduced_in, andrelatedcolumns of thesystem.aggregate_function_combinatorstable. #106185 (Alexey Milovidov). - Added the
--chimecommand-line option toclickhouse-client,clickhouse-local, and the embedded client. When a query finishes (on success or on error) after running for at least N seconds, the client writes the ASCIIBELcontrol character (\x07) to stderr. Terminals decide whether to make a sound or a visual flash based on the user’s preferences. Enabled by default with a 5-second threshold; pass--chime Nfor a custom threshold or--chime 0to disable. Closes #92718. #104545 (Groene AI). - In
clickhouse-client, when the terminal does not support bracketed paste, embedded newlines from a pasted multi-line query are now folded into the same edit buffer instead of switching to the continuation prompt for every line. The pasted query stays under a single prompt and the arrow keys navigate across its lines. This is a best-effort improvement that relies on the typical TTY-buffered paste behavior. #104299 (Alexey Milovidov). Now also works with syntax highlighting disabled (--highlight 0). #106665 (Alexey Milovidov). - Add MySQL-style runtime pager control for
clickhouse-client/clickhouse-local. #105706 (Azat Khuzhin). clickhouse-clientnow respects non-UTF-8 terminals: when the terminal character encoding is not UTF-8 (e.g. withLANG=C), thePrettyformats fall back to ASCII grid borders instead of printing Unicode box-drawing characters that would corrupt the terminal. #106213 (Alexey Milovidov).- Sanitize server-supplied display strings in
clickhouse-client’sHellopacket handling (server name, time zone, display name, password-rule patterns and messages) so a hostile server cannot inject bytes that the client renders verbatim, and cap their size to defend against unbounded allocation. #105243 (Raúl Marín). - The Web UI now displays the result as an image when a query uses an image output format such as
FORMAT PNG, instead of showing the raw bytes as a table. #107638 (Alexey Milovidov). - Add setting
output_format_pretty_use_nbsp_for_paddingto render table-layout padding in table-stylePrettyformats asU+00A0NO-BREAK SPACE whenoutput_format_pretty_grid_charsetisUTF-8. This helps copiedPrettyoutput keep table alignment in tools that collapse regular spaces. The setting is disabled by default, andASCIIcharset output keeps regular spaces. #103559 (Ashrith Bandla). - The universal install script now also installs
clickhousectlinto~/.local/binon Linux and macOS, with achctlsymlink. SetCLICKHOUSE_ONLY=1to skip. #105399 (Alasdair Brown). - Fixed a spurious
Syntax error: Unterminated quoted stringthat could occur intermittently when installing ClickHouse viacurl https://clickhouse.com/ | shwhile aclickhousebinary already existed in the current directory. #106417 (Alexey Milovidov). - Fix the left panel height on the
play.htmlpage when the web terminal is open, so the terminal toggle button at the bottom stays visible. #105087 (Alexey Milovidov). - Avoid selecting the only query in the Web UI after running it. #105711 (Joey Yu).
- The Web SQL UI now expands the query editor when a query is at most 30% taller than the current editor height. #105713 (Joey Yu).
- In the Web UI, lay out the bottom menu icons (Web Terminal and GitHub) horizontally when the left panel is expanded, giving the list of databases and tables more vertical space. #106427 (Alexey Milovidov).
- In the Web UI (
play.html), pressingEscapenow deactivates the currently selected result-table cell. #107777 (Alexey Milovidov). - Improvements to the database panel in the Web SQL UI (Play): a tooltip on the database icon, a button to hide the panel, full-width clickable database/table names, and a fix for the panel width shifting when the scrollbar appears. #108013 (Alexey Milovidov).
- Add a server setting (
min_allocation_size_to_throw_on_memory_limit) to allow any allocation to throwMEMORY_LIMIT_EXCEEDED, this should help with preventing OOMs. #105265 (Azat Khuzhin). - Allow
NONEauthentication for SSH (prevents asking password forno_passwordusers). #105476 (Azat Khuzhin). - Reset the supplementary group list in
clickhouse subefore dropping privileges, matching the behavior of/bin/suandsudo. Previously the dropped process inherited the invoker’s supplementary groups. #105247 (Raúl Marín). - Add
BFloat16support for numeric predicate (isFinite,isNaN) functions. #105391 (Mohamed Hussain S). - Reduce memory usage of polygon dictionaries (
polygon_index_cell,polygon_index_each) and makesystem.dictionaries.bytes_allocatedcorrectly reflect the lookup index they build. #105431 (Raúl Marín). - Fixes Kafka table engine consumers that kept using a short poll interval after partition assignment, so they return to the configured
kafka_poll_timeout_msand avoid excessive empty polls, smaller inserted parts, and extra merge overhead after rebalances. #100431 (sugaf1204). - Identify columns by position (instead of by name) when removing unused columns in the query plan. This enables unused-column removal when duplicated column names are present. #100586 (János Benjamin Antal).
- ClickHouse throws a proper exception for attempts to use
table_readonlyfor replicated engines, with better exception handling for DDL queries (andDatabaseReplicated) related to this setting. #100950 (alesapin).OPTIMIZE TABLE ... ON CLUSTERand other DDL no longer hang when the target table hastable_readonly = 1. The setting now throws a new dedicated error codeTABLE_IS_PERMANENTLY_READ_ONLY, whichDDLWorkertreats as non-retriable (distinct from the transientTABLE_IS_READ_ONLYthat arises during temporaryReplicatedMergeTreeZooKeeper disconnects). Thetable_readonlysetting is also now explicitly rejected forReplicatedMergeTree, both at creation and viaALTER MODIFY SETTING. Follow-up to #97652. #105109 (Alexey Milovidov). - Fixed refreshable materialized view refreshes that could fail with
UNKNOWN_TABLEafter the target table had been replaced (for example viaEXCHANGE TABLESor drop-and-recreate): the refresh now resolves the target table by name instead of relying on a stale UUID. #102724 (Seva Potapov). - Added a setting
wait_for_part_commit_in_dependent_materialized_views(defaultfalse). When a materialized view’sSELECTreads back from its own source table (for example via anINNER JOINto the source), the cascade could miss the row currently being inserted, because the inserted part is committed only after the dependent views run. Enabling this setting commits the part before the dependent views are triggered, so they observe the in-flight row, at the cost of less insert parallelism. #105943 (Elmi Ahmadov). - Do not swallow fatal errors (e.g.
MEMORY_LIMIT_EXCEEDED) intryDeserialize. #106808 (Azat Khuzhin). - Check
CREATE TEMPORARY TABLEgrant lazily inInverseDictionaryLookupPass. #107098 (Azat Khuzhin). - Fix an
ILLEGAL_TYPE_OF_ARGUMENTerror for distributed queries withserialize_query_plan = 1that contain a lambda with a constant argument (e.g.arrayMap(t -> t.2, ...)). Constant columns ofActionsDAGINPUTnodes are now preserved during query plan serialization. #107124 (Alexey Milovidov). - Deserialization of the states of the
contingency,cramersV,cramersVBiasCorrected, andtheilsUaggregate functions now validates that the stored counts form a consistent contingency table and throws aCORRUPTED_DATAexception otherwise. Closes #106899. #107185 (Nihal Z. Miaji). - Preserve original error codes for exceptions wrapped in
arrow::Status. #107267 (Azat Khuzhin). - Support
keyed_by_normalized_query_hashfor quotas defined in the static server configuration (users.xml), matching the existingCREATE QUOTA ... KEYED BY normalized_query_hashDDL syntax. #107654 (Alexey Milovidov). - The compatibility setting no longer applies obsolete settings, so it does not mark them as changed or produce obsolete-setting warnings. #107737 (Maxim Orlovsky).
- Async inserts no longer log the full list of
query_ids attrace/debuglevel, which since 26.2 could blow uptext_logon services with heavy async insert traffic. Detailed lines are now attestlevel. #107852 (Sema Checherinda). - Filesystem cache improvement: stop invalidated priority entries from pinning
KeyMetadata. Follow up to #106387. #107903 (Kseniia Sumarokova). FileCachemetrics improvement. #106116 (Kseniia Sumarokova).- Do not print the “Stack trace (when copying this message, always include the lines below):” preamble in exception messages when the stack trace is actually empty. #106524 (Alexey Milovidov).
- Fix a potential overflow in
roundUpToMultiplewhen computing filesystem cache boundary alignment for very large offsets. #92579 (Bharat Nallan). EXPLAIN SYNTAXnow formats operators as function calls consistently in explain output (for exampleplus(1, 2)instead of1 + 2). #94681 (Mohamed Abdelhalim ).- Improved table name hints in error messages: no longer suggests the exact same name, and includes the database name in the suggestion (e.g., “Maybe you meant
other_db.my_table?”). #95116 (Mathuranath Metivier). - Improved error message for unresolved identifiers in queries without a
FROMclause to suggest adding one. #101769 (Yash ). - Add
EXPLAIN PIPELINEoption to compact repeated processor chains. #104662 (Yue Ni). - Fix a heap-buffer-overflow read in syntax-error message construction (
UTF8::computeWidthImplviaparseQuery.cpp) that occurred when the parser had backtracked past the first semicolon / end-of-stream token; release builds were splicing bytes from neighboring heap memory into the displayed error, ASan builds aborted. #105086 (Groene AI). - Make hive partition strategy a default under compatibility setting
file_like_engine_default_partition_strategy. #86746 (Kseniia Sumarokova). - Use a larger (8 MiB) thread stack on macOS to match the Linux default, fixing rare server crashes from stack overflow during JIT compilation. #107033 (Raúl Marín).
- The temporary storage size limit of
clickhouse-localis no longer hard-coded to 1 GiB. The default is raised to 1 TiB and can be configured with themax_temporary_data_on_disk_sizeserver setting. #106689 (Alexey Milovidov). - Add
read-checksumscommand toclickhouse-disks. It reads thechecksums.txtfile of aMergeTreeDataPartand prints it as a human-readable, tab-separated table. #106901 (Asya Shneerson). - Added a
read-bitmapcommand toclickhouse-disks. #107834 (murphy-4o). - Chdig: enable TLS for secure connections (previous leads to either “unknown setting
skip_verify” or “connection reset by peer”). #105864 (Azat Khuzhin). chdigv26.5.1. #105918 (Azat Khuzhin).chdigv26.6.1 -{asynchronous_,}metric_log, query patterns, heatmaps, logs/traces stored on disk (previously it can use >40GiB for 1 hour of traces). #107678 (Azat Khuzhin).- The server config (
programs/server/config.xml) now setskeep_alive_timeoutto 30 (formerly 10), aligning with the actual documented and implemented default. #107779 (Dan Checkoway). - The default for the server setting
disk_connections_rcvbufchanged from0(kernel TCP autotuning) to204800(200 KB), capping the per-socket TCP receive buffer for object-storage (S3/Azure/GCS) disk connections. #107859 (Sema Checherinda). - The
PREWHEREoptimizer now groups conjuncts that reference the same column set before estimating selectivity, so that conditions likea > 2500 AND a < 2502are evaluated together as a combined range rather than as two independent predicates, producing a more accurate selectivity estimate. #106337 (Han Fei). - Add silk fiber aware secure and plain socket implementations. #107680 (Miсhael Stetsyuk).
- Fixed a garbled error message (swapped arguments) and a typo in the
nestedfunction. #108031 (Alexey Milovidov). - Added a
sedcommand toclickhouse-disksthat applies a sed expression to a given path, in-place. #107131 (Asya Shneerson). - Added the create-time
materialized_postgresql_use_extended_date_and_time_typessetting for theMaterializedPostgreSQLdatabase engine. By default (enabled), PostgreSQLdate/timestampcolumns are inferred asDate32/DateTime64; setting it to0atCREATE DATABASEtime infers the narrowerDate/DateTimetypes. #107428 (Alexey Milovidov).
Bug Fix (user-visible misbehavior in an official stable release)
- Make possible to drop detached parts with the
tryNsuffix. #58957 (János Benjamin Antal). - Fix a
MULTIPLE_EXPRESSIONS_FOR_ALIASexception for queries with duplicate projection aliases (for exampleSELECT *, day + 365 AS day) inside nested subqueries when running with parallel replicas. #80310 (Alexey Milovidov). - Fix a bug with
splitMultipartQuerythrowing an “Empty query” error for queries that end with comment after semicolon. #85491 (Yarik Briukhovetskyi). - Fix an exception with
ARRAY JOINs:Function writeSlice expects same column types for GenericArraySlice and GenericArraySinkwhich happens whenLowCardinalitynumeric types are used (issue #57243). #91784 (Jimmy Aguilar Mena). - Fix
NOT_FOUND_COLUMN_IN_BLOCKexception when usingLIMIT BYwith constant columns alongsideDISTINCTandORDER BYwith the new analyzer. #93195 (Ashrith Bandla). - Fix
NOT NULLcolumns being silently created asNullablewhendata_type_default_nullable = 1and the table is created in aReplicateddatabase or viaON CLUSTER. #97572 (xiaohuanlin). - Fixed HiveCatalog connection stability by adding automatic retry mechanism and reconnection logic for handling TTransportException errors when communicating with Hive Metastore. #98471 (Dmitriy Borisenko).
- Fixed
nestedfunction (used internally byARRAY JOIN) strippingLowCardinalityfrom column types, causingArray(LowCardinality(String))to becomeArray(String)in output. Closes #95582. #98974 (Yash ). - Fix “Distributed task iterator is not initialized” exception when using
url,s3, or similar table functions in queries with parallel replicas enabled. #100146 (Alexey Milovidov). - Fix logical error exception when reading Iceberg tables whose format version was upgraded by an external tool (e.g. Spark). #100407 (Alexey Milovidov).
- Functions
like,ilike,notLike,notILike, andmatchnow support constant haystack with non-constant needle (e.g.'foo' LIKE pattern_column), which previously threwILLEGAL_COLUMN. #100479 (Yash ). - Fixed wrong row count returned by a
MaterializedViewquery withquery_plan_enable_optimizations = 0when the view maps an integer column to aBoolcolumn. #100692 (Maksim Moisiuk). - Fix an exception (
LOGICAL_ERROR: 'PREWHERE passed to format that doesn't support it') when reading Iceberg tables containing ORC data files with PREWHERE optimization enabled. #101206 (Groene AI). - Fix race in RestCatalog. #101216 (Smita Kulkarni).
- Fix
NOT_FOUND_COLUMN_IN_BLOCKerror when selecting from a VIEW over a table with a normal projection. #101218 (Amos Bird). - Fix stale metadata in FileLog when a file is deleted and recreated. #101408 (Azat Khuzhin).
- Fix join reordering silently dropping unmatched rows of a
RIGHT/LEFT JOINwhen it is comma-joined (cross) with another table, e.g.t1 RIGHT JOIN t2 ON t1.c = t2.c, t3. The query previously returned the inner-join result instead of the outer-join one. #101684 (Groene AI). - Fixed
FORMATclause being consumed byINSERTinstead of applying toEXPLAINoutput inEXPLAIN INSERT INTO ... SELECT ... FORMAT .... #101772 (Yash ). - Fixed incorrect compression codec selection for
MergeTreeparts when the table-leveldefault_compression_codecsetting was explicitly configured. Parts written on insert, during merges, and for projections used the server-wide default codec instead of the table-level setting (the empty part produced by a fully-deleting mutation is now covered as well). #101784 (Yash ). - Reject negative
Float64values (e.g.-100.5) in workload settings likemax_bytes_per_second,max_cpus, etc. Previously only negative integers were validated, allowing negative floats to silently create broken scheduler nodes. Closes #101825. #101842 (Groene AI). - Fix a
LOGICAL_ERROR(“Port is not connected”, code 49) that could occur when executing queries involving a VIEW with aggregation inside a JOIN. #102574 (Jimmy Aguilar Mena). - Fix inconsistent part metadata after mutations of columns with non-default serializations. #102817 (Eduard Karacharov).
- Fix updating metadata before executing mutation resolves #96806. #102882 (Smita Kulkarni).
- Fix SELECT queries being significantly slower when concurrent INSERTs are running. Previously an INSERT pipeline reserved CPU slots up to
max_threadsat query start even when most slots were never used, starving concurrent SELECTs. CPU slot allocation is now demand-driven: the pipeline only requests slots as it actually pushes parallelizable work. Applies both to concurrency control and to the preemptive CPU scheduler for workloads. New server settingconcurrent_threads_lazy_allocation(defaulttrue) acts as a rollback lever. #102928 (Seva Potapov). - Fix
NULLpropagation when reading subcolumns extracted fromNullable(Tuple(...))columns. For example, fortup Nullable(Tuple(s Nullable(String))),SELECT tup.snow correctly returnsNULLin rows where the outer tuple isNULLinstead of garbage values. This covers all element types that can representNULL:Nullable,Dynamic,VariantandLowCardinality(Nullable(...)). Closes #105356. #102942 (Nihal Z. Miaji). - Throw
INCORRECT_DATAinstead ofLOGICAL_ERRORwhen client-supplied data in the Native format is truncated or malformed. #102975 (János Benjamin Antal). - Added cancellation check to ObjectStorage read operation. Closes #98165. #103016 (Smita Kulkarni).
- Respect
input_format_binary_max_type_complexityin decoding aggregate function parameters. Closes #102903. #103026 (Pavel Kruglov). - Fix nullable inference for geo columns in Arrow-based Parquet reader. Closes #101845. #103032 (Pavel Kruglov).
- Fixed
recursiveRemoveLowCardinalityerasing custom geometry type names (e.g.LineStringvsRing,MultiLineStringvsPolygon), which caused misinterpretation of the geometry type. Closes #103207. #103041 (Joanna Hulboj). - Fixed
input_format_max_block_size_bytesbeing silently ignored duringINSERTparsing whenmax_insert_block_size_bytesis0(the default). The setting now correctly limits the size of blocks produced by row input formats. #103068 (Kirill Kopnev). - Fixed ClickHouse occasionally producing invalid GSSAPI tokens due to incorrect stripping of trailing null bytes. #103114 (Michael Jarrett).
- Fix analyzer-time constant folding for short-circuit functions (
if,multiIf,and,or, etc.) so that statically unreachable branches no longer raise exceptions at analysis time. For example,WITH 0 AS n SELECT multiIf(n = 0, 0, intDiv(100, n))now correctly returns0instead of failing with a division-by-zero error. #103157 (Peng). EXPLAIN SYNTAXexpands parameterized views. #103263 (Jordi Villar).- Fix data corruption when writing Parquet (and other trailer-bearing formats such as ORC and Arrow) to HDFS via
INSERT INTO FUNCTION hdfs(...). Since 26.1,WriteBufferFromHDFSdid not flush its working buffer onfinalize(), so the last up toDBMS_DEFAULT_BUFFER_SIZEbytes of every file were silently lost, including the ParquetPAR1footer. Reading such files returnedNot a Parquet file (wrong magic bytes at the end of file). #103268 (Groene AI). - Fix wrong results and a possible logical error for correlated subqueries when a join size limit (
max_rows_in_join/max_bytes_in_join) is set together withjoin_overflow_mode = 'break'. The join created internally to evaluate a correlated subquery now ignores those user limits, so it can no longer stop early and drop rows. #103322 (Groene AI). - Fix a bug where
ALTER TABLE ... MODIFY SETTINGon anEmbeddedRocksDBtable could persist an invalid setting value to the table metadata file even when the server rejected the query. On the next server restart the table would fail to attach withCANNOT_PARSE_BOOL(or a similar parsing error), and in databases where load failures are fatal the server would refuse to start. Invalid setting values are now rejected before any metadata is written. #103417 (Groene AI). - Fixed a server abort when creating a table with an object-storage engine (
AzureBlobStorage,DeltaLakeAzure,S3,HDFS) using an unsupported number of arguments. The server now returns a cleanNUMBER_OF_ARGUMENTS_DOESNT_MATCHerror instead of aborting in debug/sanitizer builds. #103544 (Groene AI). - Fix a server crash in
JSONandDynamicdata type parameter parsing when the abstract syntax tree (AST) was structurally malformed (for example produced by the AST fuzzer): theequals(name, value)parameter expression could be left with fewer than two children, whichDataTypeObjectandDataTypeDynamicthen dereferenced without bounds checking. #103545 (Groene AI). - Fix logical errors in analyzer with column names collision in lambda used in prewhere. Closes #103584. #103627 (Pavel Kruglov).
- Fix sporadic
Logical error: 'Database <name> not found'fromDataLakeConfiguration::getCatalogwhen anIcebergengine table is loaded inside a regular database during async metadata loading. #103775 (Groene AI). - Fix
MULTIPLE_EXPRESSIONS_FOR_ALIASerrors thrown by remote replicas when running queries that reference projection aliases insidePREWHERE/WHERE/HAVING/QUALIFY(e.g.SELECT x AS a, y AS b, (a AND b) AS c FROM t PREWHERE c) orSELECT *over self-joins with overlapping column names, with parallel replicas andparallel_replicas_local_plan = 0. Closes #74324. #103806 (Groene AI). - Fix server abort when a query uses nested
coalesce/ifNullcomparisons (e.g.WHERE coalesce(a, b, coalesce(c, d), e) = const) on aMergeTreetable with multipleminmaxskip indexes anduse_skip_indexes_for_disjunctions = 1. The skip-index rewrite of<op>(coalesce(...), const)is now applied recursively to inner coalesce arguments, so the per-indexKeyConditionRPN matches the template’s RPN as the disjunction-tracking code already assumes. #103929 (Groene AI). - Fix
max_rows_to_transferandmax_bytes_to_transferbeing silently ignored forGLOBAL INandGLOBAL JOINqueries under the new analyzer. The settings now raiseSET_SIZE_LIMIT_EXCEEDED(or break, depending ontransfer_overflow_mode) when the materialised external table exceeds the configured limit, matching the behavior of the old analyzer. Closes #103333. #104119 (Groene AI). - Fix excessive catalog/S3 metadata reads when an INSERT or DDL statement references a non-existent table in a DataLake catalog database with
show_data_lake_catalogs_in_system_tablesenabled. The typo-hint suggestion path loaded full per-table Iceberg metadata for the whole catalog, which could exhaust memory on large catalogs. #104124 (DQ). - Fix a crash (
LOGICAL_ERROR“Columns are assumed to be of identical types, but they are different in Nullable” in debug builds, aColumnString::compareAtnull-pointer SIGSEGV in release builds) and a wrong result that could occur in queries usingdirectjoin_algorithmwith aMergeTreeright-side table when the lookup plan reordered columns during optimization. The right-side columns could land in wrong-named slots, so a filter or comparison on the join key saw a column of the wrong type. Surfaced by AST fuzzer as STID 2139-5111 and reported in #107272. #104174 (Groene AI). - Reject out-of-range integer partition ID for
Dateinstead of silent overflow orLOGICAL_ERRORonALTER. #104250 (Azat Khuzhin). - Disable
additional_table_filterswith parallel replicas and the analyzer without query plan serialization. Previously it could lead to incorrect results. #104296 (Azat Khuzhin). - Fix
dictGetOrNullsilently overwriting other columns in theSELECTprojection withNULLwhen called with aNullablekey column whose values are missing in the dictionary. The function was mutating an input-aliased null map in place; it now deep-clones the result column before mutation. Closes #73633. #104327 (Groene AI). - Fix a broken patch part after
ALTER TABLE ... DROP PARTITION ID 'patch-...'followed byDETACH/ATTACH TABLE. Previously the empty covering part was written withoutpartition.datandsource_parts.dat, leading to abroken-on-start_patch-...entry insystem.detached_partsafter the next attach or server restart. Closes #93132. Closes #102103. #104353 (Groene AI). - Fixed streaming
INSERTwithinput_format_max_block_wait_msfor theHTTPinterface and forINSERT SELECT FROM input, so partial input blocks are flushed before the request finishes. #104534 (Alexey Milovidov). - Fixed a bug where queries combining
arrayJoinwithORDER BY ... LIMITafter aJOINcould silently return zero rows. The query plan optimization that lifts function evaluation above theSortingStepno longer applies when the lifted expression containsarrayJoin, sincearrayJoincan change the number of rows. Closes #82279. #104558 (Groene AI). - Fix a rare server abort during
MergeTreefamily table destruction. The abort could occur whenshutdownraised an exception before the background-job scheduler was fully stopped: a background task firing in that narrow window would dispatch a virtual call through a partially-destroyed storage object and hit__cxa_pure_virtual. #104561 (Groene AI). - Fix inconsistent result in
JSONcombined subcolumn with a type hint containing null value. #104584 (Pavel Kruglov). - Fix wrong results or missed projection when an aggregate projection contains multiple
sumIfaggregates with differentIN (...)conditions. #104765 (Jimmy Aguilar Mena). - Fix wrong row count from
arrayJoin()used insideJOIN ON: the result was multiplied by the array length an extra time. #104785 (Shaohua Wang). - Fix
deltaSumTimestampreturning wrong results for signed integer types crossing zero. Resolves #104750. #104830 (Konstantin Bogdanov). - Fix block structure mismatch in UnionStep after filter push-down with NULL constants. Closes #104821. #104853 (Pavel Kruglov).
- Fix
Logical error: 'Metadata is not initialized'raised byDELETE FROMon a freshly-attachedIceberg,DeltaLake, orHuditable whose metadata file is corrupted or unloadable. A regular user-facing exception is reported instead, and the server keeps running. Closes #104891. #104917 (Groene AI). - Fixed the
max_memory_usage_soft_limitwas not updated on-the-fly when the configuration changed. The soft memory limit was calculated once at startup and cached, so subsequent config reloads had no effect. After this fix, the limit is recalculated and applied immediately on every config reload, no Keeper restart required. #104940 (Kai Zhu). - Fix JIT symbol resolution on macOS so that sort, expression, and aggregate JIT compilation no longer fail with
CANNOT_COMPILE_CODE: Could not find symbol _<name>. #104946 (Alexei Fedotov). - Fix an exception (
Received signal 6 (abort)in vector hardening, observable asTuple::back()on an empty vector) when executing a query of the formSELECT ... FROM <Distributed table> WHERE/HAVING/GROUP BY ... (sharding_key_column IN tuple())withoptimize_skip_unused_shards_rewrite_inenabled under the new analyzer. #104966 (Alexey Milovidov). - Fix a
Logical error: 'Inconsistent AST formatting'server abort (STID 1941-1bfa) on queries likeCREATE TABLE t (c0 Int CODEC(not((not(materialize(1), materialize(2)))), ZSTD)) ENGINE = Memoryin debug / sanitiser builds. The formatter no longer emits redundant outer parens around a multi-argumenttuple(...)function call that appears insideCODEC/STATISTICS/BACKUP_NAMEargument lists (where the operator form(a, b)is disabled), keeping the format-parse-format round-trip stable. #104991 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKthrown byALTER TABLE ... MATERIALIZE INDEXon parts that were created in 25.8 and contain a skip index over a column that was added with a separateALTER TABLE ... ADD COLUMN. The mutation now correctly reads every column required by every pre-existing skip index and projection on the part during force-recalculation. Closes #104872. #105039 (Groene AI). - Fixed two
LOGICAL_ERROR: Reading from materialized CTE 'X' before it has been materializedshapes thrown by queries withenable_materialized_cte: (1) a reused materialized CTE filtered byIN (subquery)over another materialized CTE, and (2) a materialized CTE referenced both directly and inside aWHERE ... IN (...)filter that hits a MergeTree primary key through a nested IN-subquery.EXPLAINon the same queries was affected too because the bugs fired during plan optimization. Closes #101940, closes #102320. #105041 (Dmitry Novik). - Fix
countminstatisticsPREWHEREselectivity estimation forFloat32columns. Two bugs causedcountminstatistics to silently produce wrong estimates forFloat32columns:ConditionSelectivityEstimatorskipped statistics entirely when the column type (Float32) was narrower than the literal type (Float64), falling back to default selectivity and ignoring the sketch; andStatisticsCountMinSketch::estimateEqualhashed the first N bytes of aFieldobject, butFieldstoresFloat32asFloat64(NearestFieldType<Float32>=Float64), so the byte pattern used at query time differed from the actualFloat32bytes stored during build. #105047 (Han Fei). ATTACH TABLE name <clauses>;queries that supply storage clauses (ORDER BY,PARTITION BY,PRIMARY KEY,SAMPLE BY,TTL,UNIQUE KEY, or engineSETTINGS) without anENGINEnow throwBAD_ARGUMENTSinstead of silently re-attaching the table with its stored definition and discarding the user-supplied clauses. Query-level sessionSETTINGS(such aslog_comment) are still applied. UseATTACH TABLE t;to re-attach with stored metadata, orALTER TABLE t MODIFY SETTING ...afterATTACHto change settings. #105068 (Groene AI).- Fixes a use-after-free in
runningAccumulatewhen called on a column whose aggregate function returns its own state (e.g.uniqStateOrDefaultState,sumStateOrDefaultState,uniqStateForEachState). #105085 (János Benjamin Antal). - Fixed a bug in the Web UI (
play.html): running a query while the cursor was past the only trailing;reported “empty query” instead of running the query. #105107 (Alexey Milovidov). - Fix
LOGICAL_ERROR: 'No user in current context, it's a bug'when aCREATE TABLE ... AS SELECTinside aReplicateddatabase reads fromsystem.current_rolesorsystem.enabled_roles. The query now succeeds and returns an empty result set in this internal DDL worker context. #105150 (Groene AI). - Fixed
ILLEGAL_TYPE_OF_ARGUMENTwhen mergingquantileExactWeightedInterpolated,quantileDD, orquantilePrometheusHistogramaggregate states with their pluralquantilesXxxMergecounterparts (and vice versa). The singular and plural variants of these three quantile families share the same internal aggregate state but were not listed in the internal name-mapping table, so cross-function state merge — and the function-fusion optimization for these families — were rejected. #105189 (Groene AI). - Fix incorrect results of
toStartOfWeek,toLastDayOfWeek,toMonday,toStartOfMonth,toLastDayOfMonth,toStartOfQuarterandtoStartOfYearforDate32andDateTime64arguments whose result falls outside theDaterange: instead of overflowing into arbitrary dates, results before1970-01-01are now clamped to1970-01-01and results after2149-06-06are clamped to2149-06-06. This also fixes wrong query results (incorrectly pruned parts and granules) when such functions were used inWHEREover aDate32orDateTime64key containing out-of-range values. #105244 (Yarik Briukhovetskyi). - Fix a logical error in
arrayRemovewhen the first argument is an array ofVariantwhose alternatives are all incompatible with the type of the second argument andvariant_throw_on_type_mismatchis disabled. The function now treats the comparison as “never equal” and returns the array unchanged instead of triggering a server-sideassertTypeEqualityfailure. #105248 (Groene AI). - Query can be executed successfully even if
FileCachefails to create some directory on disk for caching. #105250 (Den Kalantaevskii). - Fix server abort with
Assertion 'px != 0' failedinExtremesTransformwhen a query withextremes = 1hits an exception (for exampleMEMORY_LIMIT_EXCEEDED) while the transform is building its extremes columns from the first chunk. The client now receives the original exception instead of crashing the server. #105264 (Groene AI). LEFT ANTI JOINnow correctly returns the right-side join key column with default values for unmatched rows, instead of duplicating the left key value. Previously,SELECT a.x AS l, b.x AS r FROM a LEFT ANTI JOIN b ON a.x = b.xcould returnr = a.xfor the unmatched rows when it should return the default (0forInt32,''forString,NULLforNullable). Only the join key column was affected; non-key right columns were already defaulted correctly. The same bug appeared inRIGHT ANTI JOINwhenever the optimizer swapped sides. Closes #99959. #105278 (Groene AI).- Fix data loss in
clickhouse-localwhen started repeatedly with a non-default--default_database(for exampleclickhouse-local --path X -- --default_database=mydb): the lookup for the persisted database UUID was hardcoded tometadata/default, so each restart minted a fresh UUID and the previous run’s tables became invisible. Closes #101831. #105284 (Groene AI). - Fix a logical error
Mutation ofMemorytable produced incomplete outputraised when runningALTER TABLE <memory_table> APPLY PATCHESorALTER TABLE <memory_table> APPLY DELETED MASK.Memorytables do not own patch parts or deletion masks, so both commands are now correctly treated as no-ops. #105286 (Groene AI). - Fix long-running queries with Unity Catalog by passing a
table_idparameter in the query request. #105303 (Konstantin Vedernikov). - Fix
CANNOT_CONVERT_TYPEforMergeoverMergeoverDistributedwithdistributed_group_by_no_merge=1. #105330 (Azat Khuzhin). - Fix
clickhouse localandclickhouse clientsilently ignoring--query/-qwhen a positional file argument was also given. Both forms now produceBAD_ARGUMENTSconsistently. #105334 (Raúl Marín). - Fix
REPLACE TEMPORARY TABLEsilently creating a new table when the target didn’t exist. It now throwsUNKNOWN_TABLE, matchingREPLACE TABLEsemantics. UseCREATE OR REPLACE TEMPORARY TABLEto keep the create-or-replace behavior. #105373 (Groene AI). - Fixed long-running reads (e.g.
INSERT ... SELECT) from aDataLakeCatalogdatabase withcatalog_type = 'glue'failing with anExpiredTokenerror once the STS session credentials captured at table-metadata load time crossed their expiry. The AWS STS credentials are now refreshed mid-query, so such reads continue past the token’s expiry. #105381 (Pratima Patel). - Fix logical error in negative
LIMIT BYin some cases when used withARRAY JOIN. #105403 (Nihal Z. Miaji). - Fix inflated
read_bytes(and the derived bytes/s shown insystem.query_log, progress bar, etc.) when reading Parquet files. The previous implementation reported the row group’s total compressed size on every chunk, so reading K of N columns overcounted byN / K. It is now summed only across the selected columns. Also fixes file-level progress tracking for Iceberg tables, which previously never reported the data file size. #105413 (Groene AI). - Fixed a possible server segfault in cluster table functions (
s3Cluster,urlCluster,fileCluster, …) when the planner produces aSELECTwith therecursive_withflag set but noWITHexpression. Closes #105370. #105433 (Groene AI). - Fix wrong result of
countDistinct/uniqExactonNullablecolumns whencount_distinct_optimization = 1(the NULL group was incorrectly counted). #105439 (Raúl Marín). - Fixed a heap-buffer-overflow when reading Arrow or ArrowStream files with corrupted intermediate offsets in a binary or string column, and a null-pointer dereference when reading geo-tagged Arrow columns. #105449 (Raúl Marín).
- Validate
Dynamic/Varianttypes in windowPARTITION BY, it was not checked before whenallow_suspicious_types_in_group_byis disabled. Closes #105028. #105450 (Pavel Kruglov). - Fix
input_format_json_empty_as_defaultnot working in JSONStrings* formats. Closes #104913. #105453 (Pavel Kruglov). - Fix
NULLinsert intoVariantcolumn viaVALUESformat during expression parsing. Closes #104909. #105455 (Pavel Kruglov). - Fix
dictGetOrDefaultthrowingCANNOT_INSERT_NULL_IN_ORDINARY_COLUMNwhen the default argument is aNullableexpression andshort_circuit_function_evaluationis enabled with a mix of found and not-found dictionary keys. #105461 (Raúl Marín). - Fix silent value truncation in
Dynamiccolumns when theQuoted(Values) text reader falls back toStringfor incomplete inferred types likeMap(Array(Nothing), ...). Previously the fallback wrapped the raw field with naive'...'concatenation, so an inner single quote (always present for such fallbacks) prematurely terminated the quoted string and the rest of the value was lost. #105463 (Groene AI). - Fix SIGSEGV when reading
Dynamicsubcolumns from compressedMemorytable afterALTER. Closes #104901. #105464 (Pavel Kruglov). - Fix
toFloat64/toUInt32/toString/etc. onDynamicignoringcast_keep_nullable. Closes #104789. #105467 (Pavel Kruglov). - Include
skip_first_linesin schema cache key forWithNamesformats. Closes #104527. #105469 (Pavel Kruglov). - Fix a server segfault in
uniqStateOrNull/uniqStateOrDefault/uniqOrNullState(and similar combinator chains overuniq) when used withGROUP BY ... WITH ROLLUP,WITH CUBE, orWITH TOTALSand a Nullable argument. #105470 (Groene AI). - Fix
NOT_FOUND_COLUMN_IN_BLOCKexception when combiningORDER BY ... WITH FILL INTERPOLATEandLIMIT N BYwith the analyzer enabled. Closes #103474. #105481 (Yakov Olkhovskiy). - Fix
toStartOfMillisecondandtoStartOfMicrosecondreturning a result off by nearly a second for negative (pre-epoch)DateTime64values, and fixUndefinedBehaviorSanitizersigned-integer-overflow intoStartOfSecond,toStartOfMillisecond, andtoStartOfMicrosecondforDateTime64inputs nearINT64_MIN. #105482 (Groene AI). - Add a new compatibility setting
analyzer_compatibility_prefer_alias_over_subcolumn(disabled by default). When enabled, the new analyzer prefers the alias-prefix interpretation overTuple-subcolumn / dotted-column matches for multi-part identifiers, restoring the previous interpreter’s behavior. This avoidsAMBIGUOUS_IDENTIFIER(and related) errors when a query joins a table whose name matches an inner table of a CTE/subquery that usesSELECT *over a join, where asterisk-renamed columns (e.g.b.id) would otherwise leak the inner table identifiers into the outer scope. #105491 (Vladimir Cherkasov). - A vector search query executed with the index only optimization now returns the correct value for
L2Distance()if it is in theSELECTlist. The function was incorrectly returning the L2-squared distance value. Note that the vector search query was returning the correctly ranked results, only applications explicitly retrieving and interpreting theL2Distance()value would have seen the squared value. #105495 (Shankar Iyer). - Fixed a rare issue in new Kafka table engine where messages could be incorrectly handled during topic partition reassignment, potentially leading to skipped messages after offset rollback. #105500 (János Benjamin Antal).
- Fix an exception (
Trying to execute PLACEHOLDER actionlogical error) when aMATERIALIZEDCTE whose body is a correlated subquery is used as the right-hand side ofIN. Such a CTE is now rejected at analysis time, consistent with how the same pattern is already rejected when the CTE is referenced directly inFROM. #105518 (Groene AI). - Fix stdout/stdin compression not applied when format is explicitly specified. Closes #104441. #105528 (Pavel Kruglov).
- Fix SEGFAULT in
singleValueOrNulldeserialization forJSONtype. Closes #103630. #105535 (Pavel Kruglov). - Fix
clickhouse-format --backslashsilently droppingINSERTVALUESdata. Closes #103533. #105536 (Pavel Kruglov). - Fix
variant_throw_on_type_mismatch/dynamic_throw_on_type_mismatch=falsenot catching exceptions during function execution. Closes #103484. #105543 (Pavel Kruglov). - Fix ignoring
input_format_try_infer_datetimesduring insertion into shared data inJSON. Closes #103221. #105544 (Pavel Kruglov). - Fix
histogramproducing wrong results for small unsorted inputs. Closes #103109. #105548 (Pavel Kruglov). - Fix
DateTimewrapping around for out-of-range values inJSONExtractand text deserializations. Closes #103094. #105551 (Pavel Kruglov). - Fix usage of insertion table in table functions when
optimize_trivial_insert_selectis enabled. Closes #103083. #105555 (Pavel Kruglov). - Fix
CASEexpression returning theELSEbranch instead of the matchingTHENwhen both the expression and aWHENvalue wereNULL. #105556 (Raúl Marín). - Fixed a crash in
replxxcaused by hitting theFD_SETSIZElimitation ofselect(now replaced withpoll). Previously, with SSH or the web terminal enabled, this could crash the server. #105559 (Azat Khuzhin). - Materialize subcolumns in
executePartitionByExpressionbefore executing expression. Closes #103057. #105573 (Pavel Kruglov). - Fix
NOT_FOUND_COLUMN_IN_BLOCKexception whenTTLexpression references a subcolumn. #105578 (Pavel Kruglov). - Fix a server crash (SIGSEGV) reachable by any user with
CREATE TABLErights when sendingCREATE TABLE ... TO INNER UUID '...'without anENGINEclause over HTTP or the native protocol. The same bug also crashed the client. The parser now reports a properBAD_ARGUMENTSerror instead of dereferencing a null pointer. #105579 (Groene AI). - Fix
estimateCompressionRatiowindow function losing accumulated data between rows. Closes #101738. #105581 (Pavel Kruglov). - Fix crash when inserting tuples of different sizes in the same VALUES clause into a
Stringcolumn. Closes #101727. #105582 (Pavel Kruglov). - Hive partition value extraction now honors the
cast_string_to_date_time_modesetting and accepts ISO 8601 timestamps with timezone suffixes (e.g.+0000,+00:00,Z) in partition keys by default. #105584 (Alexey Milovidov). - Fixes
NOT_IMPLEMENTEDerror ontoStringfromDateTimewith Timezone containingNULLvalue. Closes #103712. #105587 (Yarik Briukhovetskyi). - Fix OOB read in flattened
DynamiccolumnNativedeserialization. #105666 (Pavel Kruglov). - Fix a
LOGICAL_ERROR(Unexpected return type from if) raised during query planning forifexpressions whose result type isVariantand whose second-or-third branch is a constant-conditionifover aUInt64literal that fits intoInt64. Closes #105649. #105680 (Groene AI). - Fix wrong results when reading an Iceberg table with
iceberg_use_version_hint = 1after another writer (such as theicebergLocal/icebergS3table function) without the setting advances the table.version-hint.textis now kept in sync by every writer once the file exists, so subsequent readers using the hint see the latest snapshot. #105682 (Groene AI). - Fixed a silent under-count in
SELECTqueries whenuse_query_condition_cache = 1(default). A query of the shapePREWHERE pk_prefix = X WHERE non_pk IN (...)against a column with a bloom-filter skip index poisoned theQueryConditionCachefor thepk_prefix = Xpredicate, so a subsequent benignSELECT count() ... WHERE pk_prefix = Xreturned an incorrect, under-counted result. Affected all 26.x releases. #104781. #105686 (Groene AI). - Fixed
singleValueOrNullMergereturning a concrete value instead ofNULLwhen merging a state that had already observed multiple distinct values. #105734 (Minh Vu). - Fix
Templateinput format error recovery after malformed rows. #105735 (Yue Ni). - Fix a crash in the
mongodbtable function, MongoDB storage and MongoDB dictionary source when the collection name is empty or contains NUL bytes. #105776 (Raúl Marín). - Fix
Keepersnapshot cleanup after failed writes so partial snapshots are cleaned up safely and failed writes can be retried without advancinglatest_snapshot_meta. #105779 (Antonio Andelic). - Fix
ALTER TABLE ... CLEAR COLUMNbeing rejected for explicitSummingMergeTreeandCoalescingMergeTreecolumns_to_sumcolumns. #105785 (Antonio Andelic). - Fixed an assertion in
DatabaseCatalog::tryGetDatabase(and resultingUNKNOWN_DATABASEerror in release builds) when creating a parameterized view whose database name is supplied via a query parameter, for exampleCREATE VIEW {db:Identifier}.v AS SELECT {p:UInt64}. Parameters in the DDL parts of theCREATEstatement are now substituted at create time, while parameters in the SELECT body remain available for substitution at view-call time. #105799 (Groene AI). - Fix
Bad get: has Decimal32, requested Decimal128fromsumMapandsumMapWithOverflowover aNested(... Nullable(Decimal(P, S)))column when the aggregate state is serialised (e.g. parallel replicas,sumMapStatevia a binary-state formatter, external aggregation). #105816 (Groene AI). - Fix
Expected ColumnLowCardinality, got String/Bad cast from type DB::ColumnString to DB::ColumnLowCardinalityerrors whenapply_mutations_on_fly = 1is used on a table with pending on-flyUPDATE/DELETEmutations queued before anALTER MODIFY COLUMN ... LowCardinality(...)mutation. #105847 (Raúl Marín). - Iceberg writes now preserve NULL values in
Nullable(T)partition columns. Previously, a NULL written by ClickHouse showed up as the default value of the inner type (0forint) when read back by Spark or other Iceberg readers. Closes #105852. #105862 (Groene AI). - Fixed
ParquetandORCfilter pushdown forIN (subquery)predicates, allowing row-group/page/bloom-filter pruning to work forfile,url,s3, and object-storage reads. #105863 (Arsen Muk). - Fix read-in-order for
Mergetables (with a new analyzer). #105867 (Nikolai Kochetov). - Fixed Iceberg v2 merge-on-read position deletes returning wrong rows when a single delete file references multiple data files and several such delete files apply to the same data file. The streaming reader (
use_roaring_bitmap_iceberg_positional_deletes = 0) now filters delete-file rows byfile_pathin C++ instead of relying on Parquet row-group pruning, restoring the ascending-positions invariant. #105888 (Groene AI). - Fix
Cannot find columnerror for distributed queries withIN Array(...)filter for the new analyzer. #105894 (Nikolai Kochetov). - Fix a SIGSEGV in
ALTER TABLE ... MODIFY COLUMN ... Nullable(...)onMergeTreetables when a column withSTATISTICSis concurrently dropped by anotherALTER. Closes #105912. #105917 (Groene AI). - Fixed a server crash that could occur when a query reading from PostgreSQL — via the postgresql table function, the PostgreSQL table engine, or a dictionary with a PostgreSQL source — was cancelled (for example with KILL QUERY) and cancelling the remote PostgreSQL query failed. #105949 (Rory Shanks).
- Fix
SYSTEM INSTRUMENT ADDformatting so handler arguments are separated by a single space, and reject invalidSLEEPinstrumentation argument lists with more than two values or a range where the minimum is greater than the maximum. #105984 (Pablo Marcos). - Fix possibly wrong results for queries that combine an outer join with a subsequent inner join referencing the outer join’s null-supplying side. Join reordering could pick a plan that pulled inner-join conditions into the outer join’s ON clause. #105992 (Vladimir Cherkasov).
- Fixed a possible crash due to a too-large string literal sent within the query. #105996 (Nikita Taranov).
- Fix
INVALID_WITH_FILL_EXPRESSIONexception when usingINTERPOLATE ()(empty) with a sorting prefix inORDER BYanduse_with_fill_by_sorting_prefixenabled. Sorting prefix columns are now correctly excluded from the implicit interpolation set, matching the behavior of explicitly namedINTERPOLATE (col). #106001 (Yakov Olkhovskiy). - Fix
ALTER TABLEpartition operations silently failing forBoolpartition keys. Closes #101722. #106004 (Pavel Kruglov). - Fix
JSONExtractRawandJSONHasfor typedJSONpaths with default values. Closes #101721. #106005 (Pavel Kruglov). - Fix incorrect ’/‘-prefix addition on empty basepaths in data lake configurations. Closes #105989. #106013 (thewisenerd).
- Fix
IcebergLocaltable engine becoming read-only after aDETACH+ATTACHcycle or a server restart, which made every subsequentINSERTfail withLocal object storage Local is readonly. (READONLY). #106016 (Groene AI). - Fix
Keeperfailures during follower catch-up when the new request dispatcher response queue could fill before the response thread started. #106049 (Antonio Andelic). - Better compatibility with the old analyzer. If the table has columns like
x.a Array, x.b Array, x String, prefer arrays forARRAY JOIN x. #106069 (Nikolai Kochetov). - Fixed the filesystem cache being silently disabled for Azure Blob Storage (e.g. Delta Lake tables over Azure) because object metadata did not include the blob ETag. #106091 (thewisenerd).
- Fix
system.dictionariesreturning 0 rows with partialSHOW DICTIONARIESrevoke. #106105 (Pavel Kruglov). - Fixed a server crash when querying DeltaLake tables with
allow_experimental_delta_kernel_rsenabled and a credential or option that contained invalid bytes (the Rust FFI panicked across theextern "C"boundary). #106109 (Raúl Marín). - Fix incorrect results for queries against tables whose
ORDER BYcontains a monotonically decreasing function such as(c0 / -42)orintDiv(c0, -42). Predicates on the underlying column (for example,c0 < 0) could wrongly prune granules that contained matching rows, producing missing results. Closes #106084. Closes #106124. Closes #106080. #106136 (Nihal Z. Miaji). - Fix support for using
WASMSQL UDFs inMATERIALIZED VIEWdefinitions. #106161 (Yue Ni). - Iceberg partition pruning now correctly handles
WHERE partition_col = (SELECT ... FROM ...)filters where the analyzer wraps the scalar subquery result in an internal_CAST(Const, 'TargetType')with matching source and target types. Previously such filters disabled partition pruning and triggered a full table scan. #106204 (Groene AI). - Fix clickhouse local’s
--query_idparameter to allow it to specify custom query id. #106205 (Yue Ni). - Fixed the S3 storage class (
s3_storage_class/s3_storage_class_name) being ignored for objects written via multipart upload onS3disks and object storage, which caused large objects to be created with the defaultSTANDARDclass. The option name is now accepted both ass3_storage_classands3_storage_class_namefor disks, object storage and backups. #106214 (Alexey Milovidov). - Fixed Keeper sometimes getting stuck on startup when setting
nuraft_max_log_gap_in_streamis set to non-default value (default is 0, i.e. disable pipelining ofappend_entriesrequests). #106220 (Michael Kolupaev). - Validate corrupted
DDSketchaggregate-function state (bin keys) on insertion instead of accepting malformed data. #106236 (Yarik Briukhovetskyi). - Fixed coordinator mode mismatch when subqueries override in-order settings. #106243 (Nikita Taranov).
- Fix
optimize_skip_unused_shardsdid not apply (andforce_optimize_skip_unused_shardsfalsely failing) when aDistributedtable is queried through aMergetable or themergetable function, with the predicate applied above it. #106250 (Nikolai Kochetov). - Fix
INTERPOLATE ()throwingINVALID_WITH_FILL_EXPRESSIONwhenORDER BYcolumns are aliased in theSELECTlist with the old analyzer. Closes #106248. #106252 (Yakov Olkhovskiy). - Fixed an abort when deserialising a malformed
AggregateFunction(uniqTheta, ...)state fromRowBinaryinput or a query parameter. The bad input is now rejected withCORRUPTED_DATAinstead of escaping as astd::exceptionand aborting the process viaabortOnFailedAssertion. #106260 (Groene AI). - Reject out-of-range
IntervalKindbytes duringRowBinaryWithNamesAndTypestype decoding (input_format_binary_decode_types_in_binary_format = 1) with a clearINCORRECT_DATAerror instead of constructing aDataTypeIntervalwith an invalid kind that could subsequently trip undefined behavior in hash paths. #106261 (Groene AI). - Fix
SLRUdowngrade failure rollback issue in26.1+. FixSystem/Datacache split priority withkeep_free_space_ratiofeature. #106286 (Kseniia Sumarokova). - Read the
nullsubcolumn as aJSONpath inNullable(JSON)instead of the null-map. Closes #106085. #106295 (Pavel Kruglov). - Fix
RestCatalog::emptyreturning the wrong result when an Iceberg REST catalog contains tables. #106301 (Lefteris). - Fixed an exception for
INNER JOINqueries with an empty leftMergeTreetable whenenable_parallel_replicas,query_plan_use_new_logical_join_step, andquery_plan_optimize_join_order_algorithm = 'greedy'are enabled. #106338 (Nikolai Kochetov). - Fixed an incorrect conversion of subnormal
Float16values toFloat32(e.g. when reading them from Numpy.npyfiles), caused by an off-by-one mantissa shift. #106343 (Joanna Hulboj). - Fix a crash and a possible
NOT_FOUND_COLUMN_IN_BLOCKerror when constraint-based optimization (optimize_using_constraints) is used with correlated subqueries. #106349 (Raúl Marín). - Fixed an out-of-bounds read in
sipHash64Keyed,sipHash128KeyedandsipHash128ReferenceKeyedwhen hashing a column whose arrays are all empty and the key is not constant. #106355 (Raúl Marín). - Fixed
SYSTEM RELOAD CONFIGdiscarding per-endpoint Azure Blob Storage settings (such asuse_native_copy), which caused a disk’s configured settings to be ignored forBACKUP/RESTOREuntil the server was restarted. #106357 (Julia Kartseva). - Fix
regexpExtract(haystack, pattern)so that patterns without a capturing group return the whole match instead of throwingINDEX_OF_POSITIONAL_ARGUMENT_IS_OUT_OF_RANGE. #106374 (Groene AI). - Fix
LOGICAL_ERRORexception during cache predownload when a remote S3 object is overwritten with shorter content between listing and reading. #106375 (Nikita Fomichev). - Fix memory usage growth in filesystem cache. #106387 (Kseniia Sumarokova).
- Fix multiple heap out-of-bounds reads in the Arrow IPC format reader (
ArrowColumnToCHColumn). A malformed Arrow file could declare more rows than its buffers contain, declare list/struct/map child lengths inconsistent with their parent, supply non-monotonic list offsets, or truncate a child validity bitmap, causing reads past the end of heap allocations. This is reachable by any user withSELECTprivilege viafile(),format(), table functions, or ArrowFlight inputs. All data, offsets, view-struct, and validity-bitmap buffers are now validated before any raw pointer access, and list/struct/map shapes and offsets are checked for consistency. #106395 (Raúl Marín). - Fixed backups failing with
FILE_DOESNT_EXISTwhen a refreshable materialized view’s REPLACE target is collected on a Replicated or Shared database whose materialized view isn’t yet instantiated on the backup-initiating replica. #106411 (Julia Kartseva). - Fix a logical error
Column identifier ... is already registeredwhen a mutation (DELETE/UPDATE) predicate contains anIN/EXISTSsubquery that reads from a default table expression nested in another subquery. #106414 (Alexey Milovidov). - Fix a logical error (
Left and right columns have same names) in the join order optimizer that could occur for joins executed with parallel replicas when two relations in the join graph share column names. #106418 (Alexey Milovidov). - Fix a logical error when building a polygon dictionary from source data containing
NaNor infinite point coordinates. Such coordinates are now rejected with a clear error. #106423 (Alexey Milovidov). - Fixed a bug where the
used_privilegesandmissing_privilegescolumns ofsystem.query_logcould contain privilege strings leaked from unrelated earlier queries of a different user, database, or session. #106425 (Alexey Milovidov). - Functions
base58Encode,base58DecodeandtryBase58Decodenow respectmax_execution_timeand query cancellation on large inputs, and reject inputs larger than 10 KB instead of running for a very long time. The limit is configurable via the new settingfunction_base58_max_input_size(0disables it). #106428 (Alexey Milovidov). - Fix sporadic incorrect results for
ORDER BY ... DESCqueries when reading wide parts in reverse order withread_in_order_use_virtual_row_per_block = 1and a smallmax_block_size. #106429 (Vladimir Cherkasov). - Fixed a
NOT_FOUND_COLUMN_IN_BLOCKexception when querying an Iceberg or S3 table with a compoundWHEREcontainingIS NOT NULLon a column that is not in theSELECTlist, using the Parquet V3 native reader. #106443 (Shaohua Wang). - Allows user to specify headers for
HTTPDictionaryusing named collections. #106459 (Jan Rada). - Fix a case where a worker thread could stay attached to a stale thread group after
CurrentThread::attachToGroupfailed part way through, causing later tasks on the same thread to fail withThread is already attached to a group. #106462 (Mikhail f. Shiryaev). - Fixed an exception when a vector search query uses a vector index and uses another skip index like
minmaxanduse_skip_indexes_on_data_read = 1. #106473 (Shankar Iyer). - Malformed
Avroenum values are now validated and rejected with an error instead of causing an out-of-bounds read and abort when deserializing corruptedAvrodata. #106476 (Miсhael Stetsyuk). - Fix inflated progress reporting when reading from Iceberg tables with
_fileor_pathfilters. Previously,total_bytes_to_readprogress included all files from the manifest regardless of filtering. #106491 (Pedro Ferreira). - Fixed a
Bad cast exceptionfor Redis dictionaries that useSTORAGE_TYPE 'simple'with acache/directlayout and a single string (complex) key; such dictionaries now work, and composite keys oversimplestorage report a clear error. #106501 (Vladimir Cherkasov). - Fix wrong-results bug where
WHERE c0 = constreturned no rows for tables withORDER BY f(c0)whenf(const)evaluates to NaN, e.g.ORDER BY sqrt(c0)with a negative constant. The primary-key analysis incorrectly pruned every granule and poisoned the query condition cache for subsequent queries. #106507 (Groene AI). - Fix
LIMIT WITH TIESand fractionalLIMIT WITH TIESnot respecting the collation fromORDER BY ... COLLATEwhen determining ties. Rows that are equal according to the collation (for example'1'and'01'under numeric collation) were compared byte-wise, so some tied rows were wrongly dropped from the result. #106539 (Nihal Z. Miaji). - Fix
DISTINCTin order andLIMIT BYin order optimizations (including negativeLIMIT BY) returning wrong results when the input is sorted with a collation (ORDER BY ... COLLATE). Rows that are equal according to the collation (for example'a'and'A'under a case-insensitive collation) are ordered by collation key and are not adjacent by value, so the in order optimization is now skipped when a collator is used. #106564 (Nihal Z. Miaji). - Fixed wrong results for
SELECT c, count() FROM t WHERE c GROUP BY cagainst tables with the implicit_minmax_count_projection, an explicit aggregate projection, or a normal projection: every group used to collapse into one row with a constant key and the total row count. #106590 (Groene AI). - Fixes a bug where users could not use scalar subqueries in the first argument of
INwhere the second argument is a non-constant tuple. #106610 (Yarik Briukhovetskyi). - Fix exception
Mutation ofMemorytable produced incomplete outputraised when runningALTER TABLE <memory_table>commands that have no per-row data effect on aMemoryengine, namelyAPPLY PATCHES,APPLY DELETED MASK,MATERIALIZE STATISTICS,MATERIALIZE INDEX,MATERIALIZE PROJECTION, andREWRITE PARTS.Memorytables do not own those structures, so such commands are now treated as no-ops. #106621 (Groene AI). - Fix
session_timezonebeing ignored when serializingLowCardinality(DateTime)columns to text formats (CSV, TSV, JSONEachRow, etc.). Previously, after the first write of aLowCardinality(DateTime)column on a server, every subsequent query that wrote such a column rendered the wall-clock string in whichever timezone was first seen, regardless ofsession_timezone. #106634 (Groene AI). - Fixed a
LOGICAL_ERROR“Trying to get name of not a column:ExpressionList” raised by queries that pass an asterisk insidemultiIfto a table function argument, e.g.numbers(multiIf(*, ...), 2). The query now rejects the unresolvable matcher withUNSUPPORTED_METHOD. #106647 (Groene AI). - Fix server failing to start with
Too many marks in file ...skp_idx_idx.cmrk4, marks expected 0 (bytes size 0)when aMergeTreetable has a skip-index part with zero granules and a non-empty marks file on disk. #106675 (Groene AI). - Reject pathological
fileglob patterns that would cause unbounded recursion in directory listing. A maximum recursion depth of 1000 is now enforced; queries that exceed it raiseTOO_DEEP_RECURSIONinstead of crashing the server with a stack overflow. #106676 (Groene AI). - Fix server abort
Bad cast from type DB::ColumnNothing to DB::ColumnVector<char8_t>inFunctionIf::executeForConstAndNullableConditionwhen theif/multiIfcondition constant-folds toConst(Nullable(Nothing))(for example, an out-of-range subscript on an empty array, likearraySort(x -> x, [])[toNullable(1)]). #106678 (Groene AI). - Fix exception
'Trying to read from input() twice.'raised when the table functioninputis wrapped in a non-MATERIALIZED CTE that is referenced from more than one place in the query. The query is now rejected with a cleanINVALID_USAGE_OF_INPUTerror at planning time.inputis a one-shot client stream and can only be consumed by a single source in the query plan. #106682 (Groene AI). - Make
FORMATapply to theEXPLAINoutput ofEXPLAIN ... INSERT ... SELECT ... FORMAT ...also whenSETTINGSprecede theFORMATor the output format isValues. Follow-up to #101772. #106686 (Alexey Milovidov). - Fixed a rare spurious
RESOURCE_ACCESS_DENIEDerror (“Scheduler queue with resource request is about to be destructed”) for a query that was actually granted access to a workload resource, caused by a reused thread-local request object retaining a previous request’s failure. #106690 (Alexey Milovidov). - Fix a race between destroying
INATSConsumerobjects and callingINATSConsumer::onMsgon them via callbacks in the NATS library. #106692 (Miсhael Stetsyuk). - Fixed
match,extract,extractAllandcountMatchesreturning wrong results for regular expressions containing hex or octal escapes. #106709 (ofeliacode). - Keeper’s internal Raft TLS now honors the
openSSL.client.verificationModesetting. Previously peer certificate verification was always enabled for inter-Keeper Raft communication regardless of this setting, sononewas silently ignored. Nownoneexplicitly disables Raft peer-certificate verification, while an absent setting keeps the previous secure-by-default behavior. Configurations that explicitly setnonewill stop verifying Raft peer certificates after upgrade, matching the configured intent. #106726 (Antonio Andelic). - Fix logical error in startup scripts in
SYSTEM RELOAD CONFIG. Additionally, load startup scripts onSYSTEM RELOAD CONFIG(currently private-only functionality). #106727 (Miсhael Stetsyuk). - Revert a change that made
sumMap/ the-Mapcombinator reject custom-named numeric value types (such asSimpleAggregateFunction(sum, T)andBool) withILLEGAL_TYPE_OF_ARGUMENT: Values for -Map cannot be summed, breaking previously-working aggregations. #106729 (Nikita Fomichev). - Fixed multiple memory-safety and resource-exhaustion issues in format readers reachable from untrusted input: a heap out-of-bounds read in the native Parquet reader’s
DataPageV2definition/repetition level-length handling, a stack overflow on Parquet files with deeply nested schemas, and allocations that ignoredmax_memory_usagewhen parsing GeoParquet WKB/WKT geometry and Avro strings/bytes. #106739 (Raúl Marín). - Fixed a heap buffer overflow (server crash) in
decodeHTMLComponentwhen decoding strings containing the expanding HTML entities≫⃒or≪⃒, reachable by any user with a singleSELECT. #106741 (Raúl Marín). - Reject
CREATE TABLE,ALTER TABLE ADD INDEX, andCREATE INDEXwithGRANULARITY 0for skipping indexes with a clearBAD_ARGUMENTSerror. Previously this triggered anInconsistent AST formattingexception in debug builds. #106783 (Groene AI). - Fixed Azure BACKUP/RESTORE ignoring endpoint settings for legacy-form
azure_blob_storagedisks. #106784 (Julia Kartseva). - Fixed a
Bad castexception while pruning parts byMinMaxstatistics when a key column isLowCardinalityand the predicate constant isLowCardinality(Nullable(...)). #106793 (Groene AI). - Fix inconsistent columns (that leads to
LOGICAL_ERRORlater) on exception (i.e.MEMORY_LIMIT_EXCEEDED) during parsing. #106802 (Azat Khuzhin). - Fix after configuring
keeper_server.http_control.secure_port, the server returned an HTTP response when making requests to HTTPS clients. #106822 (linjiayu1025-collab). - Fix logical error in
parseDateTimewith non-ASCII input bytes. #106856 (Pavel Kruglov). - Fix
SHOW CREATE ROW POLICYemittingrestrictive/permissivein lowercase instead of uppercase, inconsistent with other keywords. #106865 (Valery Petrov). - Fixes the case when parallel replicas wasn’t applied for view with
UNIONdue to empty table in theUNION. #106900 (Igor Nikonov). - Fix server crash (SIGSEGV) when reading truncated
Protobufdata withinput_format_allow_errors_num > 0. #106905 (Andrey Tsarevskiy | Андрей Царевский ). - Fix
THERE_IS_NO_COLUMNexception for distributed queries involvingoptimize_rewrite_aggregate_function_with_ifoptimization when the aggregate function argument requires a cast toNullabletype. #106908 (Yakov Olkhovskiy). - Fix an exception (
LOGICAL_ERROR) in the join runtime filter when the join key contains aVariantorDynamictype nested inside aTuple,Array, orMapand the right side of the join has a single distinct value. #106931 (Groene AI). - Fixed a signed integer overflow (undefined behavior) in
arrayLevenshteinDistanceWeightedandarraySimilaritywhen the weight arrays contain large integer values. The weighted distance is now accumulated in a wide integer for integral weights, so large integer weights no longer overflow and stay exact. #106934 (Groene AI). - Fix a server crash (null pointer dereference) when running
TRUNCATEorDROPon anEmbeddedRocksDBtable whose RocksDB handle was released, for example aread_onlytable whose data directory was emptied by a priorTRUNCATE. #106940 (Groene AI). - Fix an exception (
std::length_errorreported as aLOGICAL_ERROR) when reading from a*Clustertable function such asurlClusterwith a very largemax_streams_for_files_processing_in_cluster_functionssetting. The number of streams is now bounded to a sane value. #106946 (Groene AI). - Fix a server crash (null pointer dereference of
DB::IConnections) inRemoteQueryExecutorwhen a distributed query is cancelled right before it is sent to a shard. #106950 (Groene AI). - Fixed
elapsed_usalways being zero, andread_rows/read_bytesbeing undercounted, insystem.processors_profile_logandsystem.query_logfor asynchronous insert flush (AsyncInsertFlush) queries. #106982 (Christoph Wurm). - Fix a crash (
Source column is not Map/SIGSEGV) when merging sorted blocks that contain aVariantcolumn with aMapvariant whose local storage order differs from its global order. #107011 (Groene AI). - Fix a logical error
conflicted_part_name.has_value()raised during a synchronous insert into aReplicatedMergeTreetable when the inserted block was fully deduplicated and the conflicting part’s deduplication node had already been removed (for example by a concurrentDROP PARTITION). #107026 (Groene AI). - Fixed an exception (logical error
this->visited_views == right->visited_views) onINSERTwhen two materialized views on the same source table write to the same target table and a dependent view reads that target, withmaterialized_views_squash_parallel_insertsenabled. #107027 (Groene AI). - Fixed a
Block structure mismatch in UnionStep streamlogical error (server abort on debug/sanitizer builds,Code: 49on release builds) that occurred when one branch of aUNION/INTERSECT/EXCEPTread aSparse-serialized column while the sibling branch read the same column as a full one (for example when pushing to a materialized view). #107041 (Groene AI). - Fixed a
LOGICAL_ERRORexception when inserting into a DeltaLake table with columns that do not match its write schema (for example aNestedcolumn that flattens to subcolumns, or a table function with an explicit column subset). Such inserts now fail with a user-facingINCOMPATIBLE_COLUMNSerror instead. Closes #87402. #107058 (Groene AI). - Fix
TYPE_MISMATCHerror (“Cannot convert string … to type …”) forORDER BY <numeric column> ... LIMIT nqueries when lazy materialization placed another column before the sort column. The top-K threshold is now read from the correct sort column. #107060 (Groene AI). - Fixed a syntax error when a
FORMAT,SETTINGS, orINTO OUTFILEclause followsSHOW ROW POLICIESorSHOW MASKING POLICIES(e.g.SHOW ROW POLICIES FORMAT TabSeparated). #107061 (Groene AI). - Fix a compound
ALTER TABLE ... RENAME COLUMN a TO b, RENAME COLUMN c TO athat reuses a freed column name (a “swap”) between columns of different types. The materialized part recorded the wrong column type, so a laterSELECTfailed withConversion between numeric types and IPv6 is not supported(or aborted on part load in debug builds). #107064 (Groene AI). - Fixed non-deterministic results of the
roundDownfunction when the boundaries array containsNaN. The same input value could return a finite boundary orNaNdepending on the surrounding rows in a batch.NaNboundaries are now ignored, so the result depends only on the finite boundaries. #107065 (Groene AI). - Fixed
quantileTDigestandquantileTDigestWeightedthrowingDECIMAL_OVERFLOWforDateandDateTimearguments when the interpolated quantile is fractional but in range (for examplequantileTDigestWeighted(date, weight)on values that all fit in the type). The fractional result is now truncated to the result type, matchingquantilesTDigestWeighted; genuine out-of-range values still raise an error. Closes: #106722. #107066 (Groene AI). - Fix
trimLeft,trimRight, andtrimBoth(and aliasesltrim,rtrim,trim) throwingTOO_LARGE_STRING_SIZEwhen the custom trim character set is longer than 16 characters. Trim sets of any length are now supported again. #107071 (Nikita Fomichev). - Fixed silent truncation of out-of-range integer values in
Enum8/Enum16type definitions.Enum8('a' = 200)now throwsARGUMENT_OUT_OF_BOUNDinstead of silently creatingEnum8('a' = -56). #107081 (Groene AI). - Fix wrong row order (and a
LOGICAL_ERROR“Rows are not sorted with permutation” in debug builds) for multi-columnORDER BY ... LIMITqueries that sort byNullablecolumns when several rows tie on the leading columns. #107094 (Groene AI). - Fix a
LOGICAL_ERROR(Expected the argument N to have X rows, but it has Y) when executing a function over aDynamiccolumn built by a JOIN overDynamic(for example the non-joined rows of aRIGHT/FULL JOIN, or a correlatedEXISTSsubquery decorrelated into a join). #107095 (Groene AI). - Fix spurious ZooKeeper session recreation on config reload. #107096 (Azat Khuzhin).
- Do not hold mutex across ZooKeeper reads in access entities refresh. #107097 (Azat Khuzhin).
- Fix a
Logical error: Too large size passed to allocatorexception onINSERTinto aMergeTreetable whenadaptive_write_buffer_initial_sizeis set to an extremely large value. The adaptive write buffer initial size is now clamped to the buffer maximum. #107104 (Groene AI). - Fix
LOGICAL ERROR(Bad cast from type DB::ColumnString to DB::ColumnLowCardinality) when aVariantconstant containing aLowCardinalitymember is compared to a key column whose key expression is a non-monotonic deterministic function (for example aminmaxskip index oversipHash64(col)). #107111 (Groene AI). - Fix a
Bad cast from type DB::IColumn const* to DB::ColumnNullable const*logical error when a qualified asterisk (t.*) over aJOIN ... USINGkey is passed to an aggregate function and the other side of an outer JOIN has aNullablekey (withjoin_use_nulls = 0). #107129 (Groene AI). - Fix
ALTER TABLE ... ON CLUSTERbatches that mixMODIFY SETTING/RESET SETTINGwith a comment change (for exampleMODIFY COMMENT 'x', MODIFY SETTING old_parts_lifetime = 123) being applied only on the leader replica, leaving the other replicas diverged. Also fix a positional or per-column-SETTINGSMODIFY COLUMN ... COMMENTbeing misclassified as a local comment-only metadata change, which left the column reorder out of the replicated metadata and could causeINCOMPATIBLE_COLUMNSon replica restart. #107142 (Groene AI). - Fix a
LOGICAL_ERROR(“Table expression … data must be initialized”) raised when a qualified asterisk matcher (for examplex.*) referenced a recursive CTE by name inside its own recursive term. Such matchers now expand the recursive table’s columns, the same way a qualified column (x.a) or an unqualified matcher (*) already does in that position. #107144 (Groene AI). - Fixed wrong query results caused by the query condition cache when on-fly mutations (
apply_mutations_on_fly) or patch parts filtered rows beforePREWHERE. A query reading withapply_mutations_on_fly = 1could poison the cache so that a later query withapply_mutations_on_fly = 0and the same predicate skipped marks it should have read and returned too few rows. The same fix also covers row-level security policies, which are prepended as a filter ahead ofPREWHERE: a query run under a restrictive row policy could poison the cache for a later query that uses the same predicate without that policy. #107145 (Groene AI). - Fixed
BACKUPtoAzureBlobStorage: copying a data file inside a backup wrote the destination object outside the backup directory. Backup object existence checks onS3destinations now use exactHeadObjectrequests instead of prefix listing, preventing false matches of similarly-prefixed keys. #107153 (Pablo Marcos). - Fixed a signed integer overflow in
quantileExactExclusive,quantilesExactExclusive,quantileExactInclusiveandquantilesExactInclusivethat could produce a wrong result forInt64inputs spanning a large range. #107154 (Groene AI). - Fixed a
LOGICAL_ERROR(“Unexpected exception in refresh scheduling”) that could put the server into a crash-loop on restart when a refreshable materialized view has aREFRESH ... DEPENDS ON <name>dependency whose unqualified name matches a temporary table or a CTE name. #107156 (Groene AI). - Make sure we don’t run startup scripts on config reload, as that is semantically wrong and unexpected by users - and has been known to be error-prone. #107187 (Miсhael Stetsyuk).
- Cap the max value for
queue_sizefor pre-reserve. #107205 (Elian Gidoni). - Fix the
Argument ... of GROUPING function is not a part of GROUP BY clauseerror for queries that use thegroupingfunction with thegroup_by_use_nullssetting enabled. #107206 (Nikolai Kochetov). - Fix incorrect result order for
ORDER BYoverUNION ALLwithoptimize_read_in_orderenabled when the union pipeline was narrowed due tomax_streams_for_union_stepsettings; narrowing is now skipped when the plan relies on sorted UNION output streams. Closes #106880. #107208 (Vladimir Cherkasov). - Fixed a possible null pointer dereference while resolving proxy configuration during late server shutdown. #107231 (Pedro Ferreira).
- Fix lightweight
UPDATEqueries with legacy parallel replicas enabled for non-replicatedMergeTreetables. #107246 (Groene AI). - Fixed a server abort (
std::out_of_rangelogical error) when inserting into anIcebergtable whose write block column names do not match the field ids of the latest schema (for example after a concurrent writer renames a column within theiceberg_metadata_staleness_mswindow). The insert now fails with a clean query error instead of crashing the server. #107279 (Groene AI). - Fix the stuck shutdown bug on server and local due to static thread pools keeping idle threads indefinitely if
max_*_thread_pool_free_size > 0. #107291 (Miсhael Stetsyuk). - Fix the
s3table function silently ignoring a lowercase positionalpartition_strategy(e.g.hive). #107297 (Julia Kartseva). - Fix
low_cardinality_allow_in_native_format=0handling in parallel blocks marshalling. #107319 (Azat Khuzhin). - Fix wrong (often empty) results from
ORDER BY <col> LIMIT nwhen theuse_skip_indexes_for_top_koptimization is active and a part with aminmaxskip index on the sort column has had rows removed by a lightweightDELETE. The optimization no longer ranks the stale minmax of lightweight-deleted parts ahead of the parts that hold the live top rows. #107320 (Groene AI). - Fixed a bug in ClickHouse Keeper where the snapshot metadata reported via
last_snapshot(andzk_latest_snapshot_sizeinmntr) could move backwards after a stale or duplicated snapshot install, which could also let a same-index local snapshot overwrite a registered snapshot file in place while it was still being streamed to a peer or uploaded to S3. #107321 (Antonio Andelic). - Fixed possible server stack overflow (crash) when reading a deeply nested schema or value in the
MsgPack,BSON,ORC,Parquet,JSON,DeltaLake,IcebergandPaimonformats. Such deeply nested input is now rejected with an exception. #107341 (Raúl Marín). - Fix a possible logical error in
SYSTEM SYNC DATABASE REPLICA ... STRICTand make theSTRICTmodifier actually take effect for database replicas. #107344 (Pedro Ferreira). - Fixes a server abort in debug/sanitizer builds when reading a
DeltaLaketable whose ClickHouse schema names a column that is absent from the Delta column mapping, for example after a column was renamed or dropped in the Delta log. The query now fails with a catchableINCORRECT_DATAerror instead. #107347 (Groene AI). - Fix
ORDER BY ... WITH FILLproducing extra rows when anORDER BYcolumn before the fill column uses aCOLLATEcollation. The rows are now grouped by the sorting prefix using that collation, matching the sort order. #107365 (Groene AI). - Fixed a crash (
LOGICAL_ERRORin debug builds) and a silent wrong-results bug (in release builds) when reading an Iceberg table whose metadata re-binds an existingschema-idto a different schema across metadata versions. Such metadata is now rejected withICEBERG_SPECIFICATION_VIOLATION. #107370 (Groene AI). - Fix a
LOGICAL_ERROR(Variant N (T) has size X, but expected Y) when a function such astoStringorconcatis applied to aVariantorDynamiccolumn that holds a single non-empty variant together with NULLs, and the function returns its input column unchanged. #107374 (Groene AI). - Fix
Logical error: 'Duplicate announcement received for replica number N'that could occur with parallel replicas when a scalar subquery contained nested subqueries reading the same table. #107381 (Groene AI). - Fix
getServerSettingto return the live effective value for runtime-changeable server settings (such asmax_server_memory_usage,mark_cache_size,max_concurrent_queries, thread pool sizes, etc.), matching whatsystem.server_settingsreports. #107388 (Alexey Milovidov). - Fix
arrayResizewith aDecimalsize argument: the size is now interpreted by its real value (e.g.arrayResize([1, 2, 3], 1.5::Decimal(2, 1))returns one element) instead of the raw unscaled representation. #107389 (Alexey Milovidov). - Fix a
LOGICAL_ERROR(block.rows() == getRows()) raised on an asyncINSERTinto anAliastable whenuse_strict_insert_block_limitswas enabled. #107400 (Groene AI). - Fix a logical error (
Unexpected return type from equals. Expected Nullable(UInt8). Got UInt8) when the disjunction (partial predicate) push-down optimization pushes a condition over aUSINGkey whose type is widened by the JOIN. Also fix a server crash (segmentation fault) in the analyzer when resolving identifiers inJOIN ... USINGqueries that contain constant-foldableif/multiIfbranches referencing unknown identifiers. #107407 (Groene AI). - Fixed a heap buffer overflow (server crash) in
windowFunnelwhen finalizing a crafted aggregate-function state with an out-of-range event type, reachable by any user with a singleSELECT. #107412 (uwezkhan). - Fixed undefined behavior when a non-finite floating-point value (such as
nanorinf) is passed as the timestamp/duration argument of theprometheusQuery/prometheusQueryRangetable functions. Such an argument now raisesBAD_ARGUMENTSinstead of producing a garbage timestamp. #107417 (Groene AI). - Fix
MaterializedPostgreSQLsilently stopping replication of changes when the PostgreSQL database or table name contains upper-case letters (thepgoutputconsumer requested an unquoted, lower-cased publication name that did not match the case-preserving publication). #107423 (Alexey Milovidov). - Fix an exception (
Logical error: Not-ready Set is passed as the second argument for function 'in') when a key expression (ORDER BY,PRIMARY KEY,PARTITION BY, or a skipINDEX) contained anINoperator with a table on the right-hand side, e.g.ORDER BY (x IN some_table). Such key expressions are now rejected at table creation time. #107424 (Groene AI). - Fix incorrect results from the
optimize_rewrite_aggregate_function_with_ifoptimization for aggregate functions that preserveNULLpayload values (the*_respect_nullsfamily:anyRespectNulls,first_value_respect_nulls,anyLast_respect_nulls,last_value_respect_nulls). The optimization no longer rewritesf(if(cond, x, NULL))into the-Ifform for such functions. #107430 (Groene AI). - Fix a spurious
filesystem error: in last_write_time: No such file or directoryexception when listing a local-disk object storage directory (e.g. an Iceberg table on alocaldisk) while files are being concurrently replaced. A concurrently removed entry is now omitted from the listing instead of aborting it. #107432 (Groene AI). - Fix
THERE_IS_NO_COLUMNerror whenoptimize_if_transform_strings_to_enum = 1and the optimizedif/transform-over-string-literals expression is aGROUP BYorORDER BYkey over a Distributed table or parallel replicas. #107455 (Groene AI). - Fixed a rare server crash in
DISTINCTprocessing that could occur when an allocation failed (for example, when hitting a memory limit) while the set of distinct keys was being initialized. #107467 (Groene AI). - Fix
LOGICAL_ERROR: Unexpected return type from materialize(and similar type-mismatch errors) whenapply_mutations_on_fly = 1is used on a table with a pending on-flyUPDATEwhose target column is also read as a function input by an earlier on-flyUPDATE, before anALTER MODIFY COLUMN ... LowCardinality(...)mutation. #107475 (Groene AI). - Fixed stale AWS STS credentials when reading
DeltaLaketables overS3: the engine now keeps the freshly-credentialedS3client when refreshing its snapshot, so long-running reads no longer fail after the STS token’s TTL expires. The STS assume-role credentials provider now also honors credential refresh for anyS3access using STS. #107480 (Elmi Ahmadov). - Fixed
SELECT ... FINALandOPTIMIZE TABLE ... FINALreturning duplicate rows afterCREATE TABLE ... CLONE AS,ATTACH PARTITION ... FROMorMOVE PARTITION ... TO TABLEadopted parts from a plainMergeTreeinto aReplacingMergeTree,SummingMergeTreeorAggregatingMergeTree. The adopted part’s merge level is now reset to 0 when the source and destination engines differ, so the destination deduplicates it on the next merge. #107481 (Groene AI). - Fix an integer underflow in the PostgreSQL wire protocol parser where a message with a length field smaller than 4 caused a
size - 4wraparound and an oversizedresize/ignore. #107485 (uwezkhan). - Query cancellation is now better tracked while waiting for the quorum in ReplicatedMergeTree. #107513 (Nikita Taranov).
- Fixed a
Not-ready Set is passed as the second argument for function 'in'(LOGICAL_ERROR) when querying a table with aPARTITION BYkey and anIN/NOT INsubquery wrapped inside a larger expression, for exampleWHERE (c0 IN (SELECT ...)) != 0. #107515 (Groene AI). - Fixed
currentUser(),user(),SESSION_USERandauthenticatedUser()evaluating to an empty string on the asynchronous insert flush path (withasync_insert = 1). This affectedDEFAULT/MATERIALIZEDcolumn expressions and materialized views that reference these functions, which silently stored an empty string instead of the inserting user. #107541 (Groene AI). - With
enable_analyzer = 1(the default), querying a table by its bare name when it only exists in another database now suggests the right table, e.g.SELECT * FROM functionsreportsMaybe you meant system.functions?. Previously the new analyzer gave a hint-lessUnknown table expression identifiererror, while the old analyzer already produced the helpful suggestion. #107550 (Groene AI). - Account memory used by the rapidjson library (in
prettyPrintJSON,JSONMergePatchand the rapidjson JSON parser) against the memory tracker, so pathological inputs are rejected withMEMORY_LIMIT_EXCEEDEDinstead of allocating without bound. #107555 (Raúl Marín). - Fix a
LOGICAL_ERROR(updateFormatPrewhereInfo called more than once) raised when querying afile(),url(), or object-storage source with both an explicitPREWHEREand aWHEREwhileoptimize_prewhere_after_pushdownwas enabled. #107568 (Groene AI). - Fix a crash (null pointer dereference) that could happen when a distributed query plan was executed locally (
make_distributed_plan+distributed_plan_execute_locally) withlog_formatted_queries = 1. #107570 (Groene AI). - Fixed a server abort (
std::terminate, signal 6) during teardown of a distributed-plan query (make_distributed_plan = 1) when a worker status-check failed to re-schedule the next check (for exampleCANNOT_SCHEDULE_TASKon shutdown orMEMORY_LIMIT_EXCEEDED). The query now fails cleanly and the server keeps running. #107575 (Groene AI). - Added missing bounds checks in Elf and DWARF parsing. #107579 (Michael Kolupaev).
- Added missing bounds checks in ORC reader. #107580 (Michael Kolupaev).
- Fixed an exception (
Digest does not matchlogical error) that could happen onRENAME TABLE,RENAME DATABASE, orCREATE OR REPLACE TABLEinvolving aTimeSeriestable inside aReplicateddatabase. Renaming aTimeSeriestable is now supported. #107583 (Groene AI). - Fix an unauthenticated memory-exhaustion denial of service on the MySQL protocol port. #107599 (Shaohua Wang).
- Fix
DROP TABLEof aTimeSeriestable in aReplicateddatabase, which previously leaked the inner tables and left the background drop task retrying forever (DROP TABLE ... SYNCwould hang). #107604 (Groene AI). - Fixed two path-traversal issues in the replicated part fetch protocol that could let a malicious replica write files outside the part directory. #107606 (Antonio Andelic).
- Fixed ‘Account must be specified error’ when reading a Delta Lake table over Azure. #107620 (Smita Kulkarni).
- Fixed
ALTER TABLE ... REPLACE PARTITIONon a plainMergeTreetable resurrecting the replaced-out parts after a server restart, which made the table return both the replacement rows and the stale replaced rows. #107623 (Groene AI). - Fix a server crash when reading a materialized view whose target is a
Distributedtable while the query runs withenable_analyzer = 0. #107653 (Groene AI). - When several quotas are assigned to the same user or role, all of them are now enforced together (a query is rejected if any of them is exceeded), instead of only one quota being enforced and chosen non-deterministically.
SHOW QUOTAandsystem.quota_usagenow show all quotas enforced for the current user. #107664 (Alexey Milovidov). - Fixed
s3and other object storage table functions throwingLOGICAL_ERRORinstead ofBAD_ARGUMENTSwhen a key-value argument is duplicated, e.g.s3('http://...', format = 'CSV', format = 'TSV'). #107670 (Groene AI). - Fixed the MySQL interface being unusable with
MySQL Connector/J8.2.0 and newer (including 9.x). Theinfofield of theOKpacket is now length-encoded, matching the MySQL server, so the JDBC driver can connect. #107693 (Alexey Milovidov). - Fixed a
LOGICAL_ERROR(“Input nodes size mismatch in dag”) when a query withmake_distributed_plan = 1joins on a function-wrapped key whose two sides have no common type (for exampleON intDiv(-1, t1.key) = t2.keywith aUInt64right key). #107701 (Groene AI). - Reading Arrow/ArrowStream data with empty
String/Binarycolumns produced by Apache Arrow Java < 19.0.0 (including Apache Spark) no longer throwsINCORRECT_DATA. #107764 (Raúl Marín). - Fixed a
BAD_GETexception (“Bad get: has String, requested UInt64”) fromcountmincolumn statistics estimation when a query compares a column against a literal of a different type that is not pre-coerced, such asnumeric_col IN (SELECT '5')orstring_col IN (SELECT 5). #107793 (Groene AI). - Fixed the
odbcandjdbctable functions hanging for minutes and ignoring query cancellation (KILL QUERY,max_execution_time) when the bridge becomes unresponsive while inferring the remote table structure. #107809 (Alexey Milovidov). - Fixed an exception (
Logical error: 'index >= result.start') when formatting a malformed query that mixes the positional and named secret-argument forms of thes3/gcstable functions, e.g.s3('url', 'a', 'b', secret_access_key = 'c'). #107818 (Groene AI). - Fix set skip index not pruning granules over
LowCardinalitycolumns. #107868 (Konstantin Bogdanov). - Fixed insert deduplication computing wrong hashes for
StringandArraycolumns with the server settinginsert_deduplication_version = new_unified_hash: identical inserts could fail to deduplicate because the deduplication hash depended on the row’s position within the inserted block. #107915 (Sema Checherinda). - Fix incorrect results of
ORDER BYoverNullablecolumns with multiple sort keys on macOS (Apple Silicon), caused by a missing sign-extension in the JIT-compiled sort comparator. #107973 (Raúl Marín). - Fix performance regression when reading
Dynamiccolumns with multiple threads. Caused by #100730. Closes #107942. #107997 (Pavel Kruglov). - The deprecated data lake setting
storage_catalog_urlis now correctly rejected by the catalog guard (previously onlystorage_catalog_typeandstorage_aws_access_key_idwere checked), and the error message lists all deprecated settings. #108040 (Alexey Milovidov). - Fix a
Bad cast from type DB::ColumnSparse to DB::ColumnVector<char8_t>logical error when aLIKEquery reads from atextindex via the direct-read fallback path over a column stored sparse. #108068 (Groene AI). - Always run access cache batch-finished handlers, even on empty batch. #108124 (Azat Khuzhin).
- Fixed a
LOGICAL_ERROR(Column identifier is already registered) for some queries withUNION ALL. #100770 (Shaohua Wang). - Fixed a use-after-free of the workload storage mutex during server shutdown. #101447 (Tuan Pham Anh).
- Fixed a deadlock in
ALTER DATABASE MODIFY COMMENTwith theSharedcatalog. #103683 (Nikolay Degterinsky). - An empty Unicode-quoted identifier now raises a
SYNTAX_ERRORinstead ofCANNOT_PARSE_QUOTED_STRING. #104173 (leonard9893). - Preserve the original parameter types of
timeSeries*aggregate functions so thatAggregateFunctiontypes round-trip correctly across table reattach and parallel replicas. #104812 (Vitaly Baranov). - Fixed a
LOGICAL_ERRORfor a materialized CTE underserialize_query_planwith parallel replicas. #104896 (Igor Nikonov). - Fixed signed integer overflow in the
timeSeries*ToGridfunctions when the staleness (window) parameter is nearINT64_MAX. #105319 (Groene AI). - A
compatibilitysetting value no longer revertsapply_row_policy_after_finaltofalse, so row policies are always applied correctly withFINAL. #105637 (Yarik Briukhovetskyi). - Fixed
clickhouse chdig clientby honoringSETPGROUP/RESETIDS/SETSIGDEFin theposix_spawnstub. #105858 (Azat Khuzhin). - Fixed an exception during merge-tree sanity checks on projections when the merge/mutate executor was not initialized. #105919 (Mikhail Artemenko).
- During index analysis on projections, the
minmaxindex is now loaded from the projection itself rather than from the parent part, producing correct results. #105940 (Mikhail Artemenko). - Fixed an exception in
addMonotonicChainformaterialize(monotonic_chain(...)). #106050 (Nikolai Kochetov). - Fixed
RESTOREfailing on backups that includeMASKING POLICYdependents. #106086 (Julia Kartseva). - Fixed possible memory corruption when expanding SQL user-defined functions with
prefer_column_name_to_aliasenabled. #106121 (Nikolai Kochetov). - A dictionary using the bridge connection is now reloaded after a server restart, re-establishing the connection. Closes #106151. #106152 (Pedro Ferreira).
- Fixed the filesystem cache for
LocalObjectStorage. #106239 (Kseniia Sumarokova). - Fixed the lazy remote source for table functions with
use_delayed_remote_source. #106470 (Nikolay Degterinsky). - Fixed
timeSeriesLastToGridfor timestamps before the grid start and out-of-window timestamps. #106504 (Vitaly Baranov). #106577 (Vitaly Baranov). - Fixed a
LOGICAL_ERROR(Inconsistent AST formatting) on a function name containing query parameters. #106635 (Vitaly Baranov). - Fixed a logical error when a table is dropped before distributed plan task deserialization. #106944 (Alexander Gololobov).
- Use exact comparison for
NullableGROUP BYkeys. #107050 (Nikolai Kochetov). - Fixed a
LOGICAL_ERROR(Trying to get name of not a column) raised when a table-function argument was not a column expression (for example an unresolved*matcher frommultiIf/CASE). #107411 (Alexey Milovidov). - Fixed unbounded growth of the time-zone cache (
DateLUT) when many distinct invalid time-zone names are processed. #107464 (Alexey Milovidov). - Write the
part_logentry before reporting a plainMergeTreemutation as done. #107741 (Azat Khuzhin). arrayFoldnow sanity-checks its array argument against malformed input. #107932 (Michael Kolupaev).- Fixed a rare data race and possible use-after-free on the cached skip-index archive reader of a
MergeTreepart, which could happen when a query read skip indices while the part was being moved or renamed. #107995 (Raúl Marín). - Fix performance regression for
Mapsubcolumns withPREWHERE. #107988 (Pavel Kruglov). - Fix
parseDateTimeBestEffortwith a timezone throwingCANNOT_PARSE_DATETIMEon NULL rows oftoString(Nullable(DateTime64)). #108310 (Yarik Briukhovetskyi). - Fixed the
ArrowFlighttable function and engine rejecting a named collection that omits the optionaldatasetkey with aNo such key 'dataset'error. #108041 (Alexey Milovidov). - Fixed an
Inconsistent AST formattinglogical error for a no-argument window function inside aCODECor engine declaration (e.g.CODEC(cume_dist() OVER (...))); such a function now keeps its parentheses so the query survives a format/parse round-trip. #107806 (Alexey Milovidov). - Fix
hasTokenwith a separator-containing needle silently returning results via a text index instead of raisingBAD_ARGUMENTS. #108189 (Jimmy Aguilar Mena). - The setting
use_skip_indexes_on_data_readcan now be reverted to its pre-26.1 default (false) via thecompatibilitysetting, providing an escape hatch for a performance regression where the on-data-read path defeatsminmax/set/bloom_filterskip-index mark-range pruning. #108330 (egor romanov). - Fixed a possible crash (null pointer dereference) when the
database/dboverride of a named collection passed toremote/remoteSecureis not a constant database name, e.g.remote(nc, database = (SELECT 1)). The query now fails with a clear error instead of crashing. #108271 (Groene AI). - Fixed refreshable materialized view getting stuck if the ZooKeeper connection is lost at the wrong moment. #108234 (Michael Kolupaev).
- Fix
Bad cast from type DB::ColumnVector<...> to DB::ColumnTuplewhen reading anArray(Tuple(...))column whose value is filled with defaults, e.g. afterALTER TABLE ... ADD COLUMNor after an unfinishedALTER TABLE ... CLEAR COLUMNmutation applied on the fly. #107232 (Groene AI). - Fix a
Bad cast from type DB::ColumnDynamic to DB::ColumnNullablelogical error when an explicit reference to aJOIN ... USINGkey whose common supertype isDynamicis passed to an aggregate function, for examplecount(t.key) IGNORE NULLS. #107289 (Groene AI). - Fix silent data loss on plain (non-replicated)
MergeTreewhenREPLACE PARTITION,MOVE PARTITION,DETACH PARTITION, orDETACH PARTis run on a partition that still has unapplied lightweightUPDATEpatches. These operations now reject the command, asReplicatedMergeTreealready does. #107386 (Groene AI). - Fix a crash (SIGSEGV in release builds, type-mismatch assertion in debug builds) in
hasover aMapwith aDynamickey when the lookup argument isLowCardinality, e.g.has(map('a'::Dynamic, ...), toLowCardinality('b')). #107956 (Groene AI). - Fixed a
LOGICAL_ERROR(“Block structure mismatch … betweenConvertingTransformandRemovingReplicatedColumnsTransform”) when inserting into a materialized view whoseTOtarget table declares a column with a widerEnumthan the view’sSELECTproduces. The validEnumwidening is now applied. #107648 (Groene AI). - Fix
NUMBER_OF_COLUMNS_DOESNT_MATCHerror when querying aDistributedtable (or using parallel replicas) that has severalALIAScolumns expanding to the same expression and referencing them together withORDER BY/GROUP BY/HAVING. #107913 (Yakov Olkhovskiy). - Fixed undefined behavior (null pointer passed to
memcpy) in thedetectCharsetanddetectLanguageUnknownfunctions when the input string is larger than 32768 bytes and no character set can be detected. #108250 (Groene AI). - Fix
signed integer overflow(undefined behavior) indateDiffwithhourandminuteunits on extremeDateTime64values close to theInt64range limits. #108229 (Groene AI). - Fix
Too many marksfor a text index on an empty merged part. #106867 (Azat Khuzhin). - Fix a
LOGICAL_ERROR(“Unexpected return type from if”) when reading a column underapply_mutations_on_fly = 1after anALTER UPDATE col = ... WHERE <cond>with a non-constant or false condition followed byALTER MODIFY COLUMN col <new type>. #108128 (Groene AI). - Fix a server abort (
Logical errorinIColumn::insertFrom) when casting anArray(Dynamic)orArray(Variant)toQBitwithaccurateCastOrNull, e.g.accurateCastOrNull(CAST(range(114), 'Array(Dynamic)'), 'QBit(Float32, 114)'). #108288 (Groene AI). - Fixed a syntax error when an alias follows a subquery in
DESCRIBE TABLE (...) AS .... #100205 (Yarik Briukhovetskyi). getClientHTTPHeaderis now correctly treated as non-deterministic, so its result is no longer incorrectly reused by the query result cache. #108029 (Alexey Milovidov).
Build/Testing/Packaging Improvement
- Build
delta-kernel-rswith thedefault-engine-native-tlsfeature so that its own HTTP client (reqwest) can reuse the OpenSSL that ClickHouse already links in. This is only a partialnative-tlsenablement:object_storestill forcesreqwest/rustls-tls-native-roots, soreqwestends up with both thenative-tlsandrustlsbackends.delta-kernel-rsremains disabled under MSan for now becauseringis still compiled in viaobject_store(both transitively throughrustlsand directly for AWS request HMAC signing), and its hand-written assembly does not generate the symbols MSan requires (tracked upstream at arrow-rs-object-store#585). #96856 (Austin Bonander). - Add PGO (Profile-Guided Optimization) and BOLT (Binary Optimization and Layout Tool) post-link optimization for the
clickhousebinary. Profiles are collected from CI workloads and applied as a best-effort step during release builds — both stages fall back to non-optimized output if a profile is stale or incompatible. As of today, there are no benefits from PGO. #100938 (Alexey Milovidov). - Add
--storagemode toclickhouse keeper-benchthat benchmarksKeeperStoragein-process (no network, no raft, no state machine), using the samesetup/generatorconfig sections as the network mode. #103081 (Michael Kolupaev). - Fix build with
ENABLE_AWS_S3=OFF. #105390 (Yue Ni). - Update
mongo-cxx-driverto r4.3.0. #105522 (Konstantin Bogdanov). - Fix build against RapidJSON. #105674 (Ilya Golshtein).
- Speed up the build by removing transitive includes from widely-used base/ headers and stripping unused code from the vendored
Poco/Logger.h. #105702 (Raúl Marín). - Updated
libxml2from 2.15.1 to 2.15.3. #105985 (Konstantin Bogdanov). - Use
expat2.8.1 inside Poco. #105988 (Konstantin Bogdanov). - Bump
thrifttov0.23.0. #105993 (Konstantin Bogdanov). - Use
postgrestagREL_18_4. #105994 (Konstantin Bogdanov). - Upgrade
krb5to 1.22.2. #106076 (Konstantin Bogdanov). - Update bundled
curlto 8.20.0. #106077 (Konstantin Bogdanov). - Bumped
mariadb-connector-cto 3.1.29. All the ClickHouse-relevant patches preserved. #106287 (Nikita Mikhaylov). - Bump distroless base image digests for libssl3t64 CVE fixes. #106360 (Rahul Nair).
- Use
wasmtimev45.0.1. #106836 (Konstantin Bogdanov). - Bump
opensslto 3.5.7. #106844 (Konstantin Bogdanov). - Distroless Docker build now also updates the
:X.Y-distrolessand:X.Y.Z-distrolessfloating tags, not just the full-version tag. #106932 (Rahul Nair). - Disable unused
curlfeatures, such as NTLM auth, cookies, alt-svc, HSTS, DNS-over-HTTPS, netrc, MIME, AWS SigV4. #107226 (Konstantin Bogdanov). - Updated
NuRaftwith a fix for a snapshot-install livelock that occurred when snapshot IO ran on a background thread. Thenuraft_use_bg_thread_for_snapshot_ioKeeper setting remains disabled by default; CI now randomizes it to cover both modes. #107338 (Antonio Andelic). - Fix building
abseilwhen the ClickHouse checkout path contains a substring matching a header extension. #107349 (zhiqiang). - Determine the L2 cache size from
CPUIDon x86_64 instead of the glibc-specificsysconf(_SC_LEVEL2_CACHE_SIZE), which is not available under musl libc. #107469 (Konstantin Bogdanov). - Increase the stack size for musl builds to 8 MiB to support deeply-nested queries. #107470 (Konstantin Bogdanov).
- Derive the set of C library symbols localized in Rust static libraries from the actual reference libraries instead of a hand-maintained allowlist, so all compiler-rt builtins and platform libm functions are covered. #107571 (Raúl Marín).
- Switch the distroless server and keeper images to
gcr.io/distroless/base-nossl-debian13so they only ship the libraries ClickHouse actually links against and stop pulling in ones we statically link ourselves. #107837 (Rahul Nair). - Re-enable 50 stateless tests on macOS (
arm_darwin) that were stale-skipped, and usefsyncinstead ofF_FULLFSYNCfor directory syncing on macOS. #107887 (Raúl Marín).
ClickHouse release 26.5, 2026-05-21. Presentation, Video
Backward Incompatible Change
- Changed defaults of
date_time_input_formatandcast_string_to_date_time_modefrombasictobest_effort. Queries that previously failed to parse non-basic datetime strings (e.g.2024 April 4,Apr 15, 2020 10:30:00) may now succeed by default. To keep the old strict parsing behavior, set these settings tobasic(or usecompatibility). #89334 (Alexey Milovidov). - Tuple element name
nullis now forbidden because it conflicts with the subcolumn name used for Nullable null maps, causing ambiguous subcolumn resolution. #98377 (Alexey Milovidov). - Add a setting
dynamic_disk_allow_from_env,dynamic_disk_allow_from_zk,dynamic_disk_allow_includeto disallow usage offrom_env,from_zk,includein dynamic disks. Backward Incompatible Change because prohibits by default the behaviour which used to be allowed by default. #99138 (Kseniia Sumarokova). - You can no longer use the obsolete Arrow-based Parquet reader and writer. The native implementation will be used instead. #100949 (Alexey Milovidov).
SHOW CREATE TABLE tnow prefers the temporary table when both a permanent and a temporary table namedtexist and no database is specified, matching the existing behavior ofDESCRIBE TABLE. Additionally,DESCRIBE TEMPORARY TABLEsyntax is now supported. #100966 (Alexey Milovidov).- Reduced default
http_max_fieldsfrom 1,000,000 to 1,000 andhttp_max_field_name_sizefrom 128 KB to 4 KB to limit pre-authentication memory usage by HTTP connections. Addedhttp_max_request_header_sizeandhttp_headers_read_timeoutsettings. Users who rely on the previous higher limits can restore them via settings. #103285 (Sema Checherinda). - Added a
histogramsnested column tosystem.metric_logthat snapshots every registered histogram metric per row, with a newsystem_metric_log_show_zero_values_in_histogramssetting to control zero-value emission. Deprecates thesystem.histogram_metric_logtable. #103770 (Miсhael Stetsyuk). CASTtoDateTimeorDateTime64without an explicit time zone now preserves the time zone of its source argument (when the source is aDateTime/DateTime64with an explicit time zone), matching the behavior of thetoDateTime/toDateTime64functions. Closes #55072. #104433 (Alexey Milovidov).- Removed the
kqltable function. UseSET dialect = 'kusto'to run queries in the KQL dialect. #105101 (Alexey Milovidov). - The window functions
RANKandDENSE_RANKnow reject arguments and throwNUMBER_OF_ARGUMENTS_DOESNT_MATCH, in line with the SQL standard. Previously, queries such asRANK(x) OVER (ORDER BY id)were silently accepted with the argument ignored. To restore the previous lenient behavior, setallow_rank_dense_rank_arguments = 1. Closes #49526. #104324 (Groene AI).
New Feature
- Added a new setting
max_bytes_ratio_before_external_join, mirroringmax_bytes_ratio_before_external_group_byandmax_bytes_ratio_before_external_sort. It expresses the spill-to-disk threshold for hash joins as a fraction of available memory; combined with the absolutemax_bytes_before_external_join, the smaller resulting threshold applies. #103862 (Alexey Milovidov). Thenew max_bytes_ratio_before_external_joinsetting is now enabled by default at 0.5, mirroringmax_bytes_ratio_before_external_group_byandmax_bytes_ratio_before_external_sort. Hash joins automatically spill to grace hash join once the right-side data exceeds half of the available system memory (when memory limits are configured). #104285 (Alexey Milovidov). - Add table function
filesystem. It allows to represent directory structure as a table, to query files’ metadata and contents with SQL. Originally #42039 by @perst20. See #42039. See #50208. #53610 (Alexey Milovidov). - Allow passing bare function names to higher-order functions like
arrayMap,arrayFilter, etc. For example,arrayMap(negate, [1, 2, 3])is now equivalent toarrayMap(x -> negate(x), [1, 2, 3]). #101033 (Alexey Milovidov). - Add setting
send_table_structure_on_insert_with_inline_dataand--inline-insert-dataclient option to allow the server to parse inline INSERT data itself over the native protocol, avoiding the round-trip to receive table structure and improving performance for many small inserts. #101034 (Alexey Milovidov). - Add
tokenizeQueryandhighlightQueryfunctions for SQL query tokenization and syntax highlighting.tokenizeQueryreturns lexer tokens with byte offsets and token types;highlightQueryreturns parser-based syntax highlighting ranges with highlight categories (keyword, identifier, function, number, string, etc.). #101054 (Alexey Milovidov). - Add
url_basesetting to resolve relative URLs in theurltable function andURLtable engine, following RFC 3986 semantics. #101113 (Alexey Milovidov). - Support negative values in the
LIMIT BYclause to select rows from the end of each group instead of the beginning. For example,LIMIT -2 BY idreturns the last two rows perid. Negative offsets (LIMIT -1 OFFSET -1 BY id) and mixed signs (LIMIT -2 OFFSET 1 BY id) are supported as well. #103222 (Nihal Z. Miaji). - Support
json_valuefunction to output withtupleandarrayto improve performance of multiple json query. #78362 (kevinyhzou). Support multi-pathTuple/ArrayJSONPath argument inJSON_VALUE,JSON_EXISTS, andJSON_QUERY, by @KevinyhZou. #101102 (Alexey Milovidov). - A new
kafka_autodetect_client_rackparameter is introduced. If set, discover the Availability Zone via cloud facilities and propagate it as theclient.rackparameter oflibrdkafkato avoid cross-zone communications. #81323 (Ilya Golshtein). - Add
Readevent type tosystem.blob_storage_logfor tracking object storage read operations, controlled by new settingenable_blob_storage_log_for_read_operations. #96867 (Alexey Milovidov). - Users can now see ZooKeeper watches issued by
clickhouse-serverusing the newsystem.zookeeper_watchestable. #99277 (Den Kalantaevskii). - Added
Shardsprofile event that counts the number of shards involved in distributed queries, summed across all tables. #99470 (Alexey Milovidov). WASMUDFs can be declaredDETERMINISTICand become a subject of constant folding. #100005 (Vasily Chekalkin).- Add
parallel_replicas_prefer_local_replicasetting: when disabled, parallel replicas are selected purely by the load balancing algorithm, allowing evenmax_parallel_replicas = 1queries to be directed to another host. #100139 (Alexey Milovidov). - Add
{disk,storage,http}_connections_rcvbufand{disk,storage,http}_connections_sndbufserver settings to control TCP socket buffer sizes on outgoing HTTP connections, allowing operators to override kernel autotuning and cap per-connection memory usage. #100478 (Sema Checherinda). - Support
CREATE OR REPLACE MATERIALIZED VIEWwith the same atomic swap semantics asCREATE OR REPLACE TABLE. Works with inner tables,TOtables,POPULATE,REFRESH, andON CLUSTER. #100539 (DQ). - Add
s3_read_request_duration_microsecondsands3_read_request_byteshistogram metrics to observe S3 GET request connection lifetime and bytes consumed, visible insystem.histogram_metricsand the Prometheus endpoint. #102058 (Sema Checherinda). - Add
Paimon,PaimonS3,PaimonAzure,PaimonHDFS, andPaimonLocaltable engines with incremental read support backed by Keeper snapshot progress tracking. Incremental mode returns only new rows since the last committed snapshot. Targeted snapshot delta reads are available viapaimon_target_snapshot_id, and per-query snapshot caps viamax_consume_snapshots. Background metadata refresh is configurable withpaimon_metadata_refresh_interval_sec. Gated byallow_experimental_paimon_storage_engine. #102343 (XiaoBinMu). - Added a new Kafka table setting
kafka_map_virtual_columns_on_write. When enabled, columns named_key,_timestamp,_headers.nameand_headers.valuein the Kafka table schema are produced as the corresponding Kafka message key, timestamp and headers onINSERT, and are excluded from the message payload. #103243 (Alexey Milovidov). - Added
SYSTEM PAUSE VIEW [db.]nameandSYSTEM PAUSE VIEWSqueries for refreshable materialized views. UnlikeSYSTEM STOP VIEW,SYSTEM PAUSE VIEWdoes not interrupt the currently running refresh — the in-flight refresh is allowed to complete and only subsequent refreshes are prevented. Undone bySYSTEM START VIEWorSYSTEM START VIEWS, which now uniformly clear both the stopped and paused states. #103252 (Nikita Mikhaylov). - Added function
regexpPosition(with PostgreSQL-compatible aliasesregexpInstrandregexp_instr) that returns the byte position of the N-th regex match in a string. Supports start offset, return-after-match mode, regex flags, and capture-group selection. #104172 (Abhinav Agarwal). - New functions
isPrimeandisProbablePrimefor primality checks.isPrimereturns an exact result for unsigned integers up toUInt64.isProbablePrimealso supportsUInt128andUInt256; for those wider types,0means definitely composite and1means probably prime. The optional second argument ofisProbablePrime,rounds, controls the confidence (capped at256); the default of25rounds bounds the false-positive rate for a random composite below10^-15, andisProbablePrimeis cancellable. #104234 (Nihal Z. Miaji). #104639 (Alexey Milovidov). #104806 (Nihal Z. Miaji). clearand/clearnow clear the terminal in the clickhouse command-line tools instead of running as a mistaken query. #104318 (Tyler Hannan).- Allow the
filetable function to accept anArray(String)of paths inSELECTqueries. #104442 (Yue). - Add
deterministicandhigher_ordercolumns tosystem.functionstable. #104479 (Pedro Ferreira). - Add an optional encoding variant parameter to
bech32Encode(bech32/bech32m) and a raw decode mode tobech32Decodefor non-SegWit address encoding (e.g. Cosmos SDK, Injective, Osmosis). #98986 (Yash ). - You can now write data in
AvroConfluentformat, which was previously input-only. This enables producing Confluent Schema Registry-framed Avro messages directly from ClickHouse, for example when writing to Kafka. The schema is automatically registered with the registry. Use the newoutput_format_avro_confluent_subjectsetting to specify the subject name. #101935 (János Benjamin Antal). - Added the
prettyPrintJSONfunction to format a JSON string into a human-readable form. Useful for dashboards or reports where prettifying previously required an extra step on the client side. Closes #62523. #102594 (Dmitry Prokofyev). - Added
STRING_AGGas a case-insensitive alias ofgroupConcatfor PostgreSQL / SQL-standard compatibility. #105125 (Alexey Milovidov). - Individual subquery results can now be cached independently using
SETTINGS use_query_cache = trueon specific subqueries, without caching the entire outer query. A new settingquery_cache_for_subqueries = trueenables bulk propagation ofuse_query_cacheinto all subqueries. Note:use_query_cacheon the outer query no longer auto-propagates to subqueries. #99804 (Vincent Voyer). - Added lexer-based syntax highlighting to the query editor in the Web UI (
play.html), modelled afterclickhouse-clientcolors. #105105 (Alexey Milovidov).
Experimental Feature
- Added an experimental web terminal interface at
/webterminalthat provides an interactiveclickhouse-clientsession in the browser over WebSocket. Disabled by default; enable with theallow_experimental_webterminalserver setting. See it here. #100277 (Alexey Milovidov). #105191 (Alexey Milovidov). #105059 (Alexey Milovidov). - The
Kafka2engine (experimental, with Keeper-based offset storage) now supports directSELECTqueries and thekafka_commit_on_selectsetting. #100276 (Alexey Milovidov). WASMUDFs can now coerce more numeric types: smaller integers to wider integers (e.g.Int8toUInt64), and any integer to floating point (e.g.Int32toFloat32). #100435 (Vasily Chekalkin).- Support
LIKEfunction inDELETE FROM system.webassembly_modulesquery. #104397 (Vladimir Cherkasov). - Support geo types for
Iceberg. #103113 (Konstantin Vedernikov). - Add prepared statements functionality to ArrowFlight SQL server. #103047 (Yakov Olkhovskiy).
- Improved KQL parser (for the Kusto language support) robustness by preserving parser depth and backtracks counters across KQL parser stages, so parser limits are tracked consistently for complex KQL queries. #103528 (Yakov Olkhovskiy).
Performance Improvement
- Reuse the Parquet footer metadata cache when reading local Parquet files via the
filetable function orFiletable engine. Previously the cache was only consulted for object-storage backends. #104260 (Alexey Milovidov). - Push
ORDER BY ... LIMIT nthroughLEFT/RIGHTjoins when the sort key only references columns from the side preserved by the join, restricting how many rows the preserved-side input must produce before joining. Controlled by the new settingquery_plan_top_k_through_join(default enabled). #104268 (Alexey Milovidov). - Enable
use_top_k_dynamic_filteringanduse_skip_indexes_for_top_ksettings by default to improve performance ofORDER BY ... LIMIT Nqueries. #99537 (Alexey Milovidov). Restrictuse_top_k_dynamic_filteringto fixed-length sort columns by default, avoiding regressions onORDER BY <var-length-column> LIMIT Nqueries where the per-row threshold comparison cost exceeds the I/O savings. The previous behavior is available via the newuse_top_k_dynamic_filtering_for_variable_length_typessetting. #104216 (Alexey Milovidov). - Use the oversize-arena feature of
jemallocto reduce page faults. #103958 (Nikita Taranov). - Limit simultaneously active streams in
UNION ALLto reduce peak memory usage. #100176 (Alexey Milovidov). - Slightly optimize the userspace page cache. #100300 (Alexey Milovidov). Now the userspace page cache is always better than the OS page cache.
- Cold reads of object storage through the userspace page cache (
use_page_cache_for_object_storage = 1) are now significantly faster, because consecutive cache misses are coalesced into a single HTTP request instead of one request perpage_cache_block_sizeblock. #104230 (Alexey Milovidov). - Speed up the index analysis involving type casting and function application. Closes #55653. #100366 (Alexey Milovidov).
- Speed up huge queries on
Mergetables over a huge number of underlying tables. Closes #32465. #100369 (Alexey Milovidov). - Remove vtable from setting field types, reducing
Settingscopy size by ~28x and improving cache locality via typed-array layout for all settings types. #102269 (Raúl Marín). - Add
max_threads_min_free_memory_per_threadandmax_insert_threads_min_free_memory_per_threadsettings to automatically reduce query parallelism when the server is low on free memory. #100383 (Alexey Milovidov). - Reduce memory usage on low-memory systems (< 4 GiB). #100389 (Alexey Milovidov).
- Added
OptimizeTrivialGroupByLimitPass. For trivialSELECT ... FROM t GROUP BY k LIMIT nqueries (noHAVING,ORDER BY, or window functions), the analyzer now setsmax_rows_to_group_by = n + offsetwithgroup_by_overflow_mode = 'any', so aggregation stops oncendistinct keys have been produced instead of grouping the entire input. Controlled by the new settingoptimize_trivial_group_by_limit_query(enabled by default). #104473 (Amos Bird) (Alexey Milovidov). - Granule-level implicit min-max index for the
_part_offsetand_block_numbervirtual columns, including for projections. Enables fast pruning of granules based on virtual column predicates. #103952 (Mikhail Artemenko). #104746 (Mikhail Artemenko). #105137 (Mikhail Artemenko). - For the
prealloc_serializedfamily of aggregation methods, precompute per-row hashes during the batch-serialization pass and use them to (a) skip rehashing inemplaceKey/findKeyand (b) software-prefetch the next row’s bucket. Speeds up multi-key string/serialized aggregation by hiding hash-table cache-miss latency. #104475 (Amos Bird) (Alexey Milovidov). - Query condition cache for
Icebergtables. #102115 (Konstantin Vedernikov). - Optimize
cramersV,cramersVBiasCorrected,theilsU, andcontingencywhen used with window functions. Closes #83521. #93384 (Nihal Z. Miaji). - Added a query optimization that rewrites
tupleElement(dictGet('dict', ('a', 'b', 'c'), key), N)intodictGet('dict', 'a', key), avoiding fetching unnecessary dictionary attributes. Controlled by theoptimize_dictget_tuple_elementsetting (enabled by default). #100186 (Alexey Milovidov). - Enable buffering for sorting steps on the initiator for distributed queries with sorting. #100661 (Nikita Taranov).
- Performance improvement for
partial_mergeJOIN. #100945 (Artem Zuikov). - Slightly reduced memory over-allocation in
partial_mergeJOIN. #100963 (Artem Zuikov). - Optimize allocations/deallocations by caching sampling settings instead of traversing the entire memory-tracker hierarchy. #101267 (Azat Khuzhin).
- Reduce memory allocation overhead during S3 multipart uploads by preallocating internal tracking containers. #101799 (Gagan Dhakrey).
- Add software prefetch in hash join probe phase to reduce memory access latency for large hash tables, controlled by setting
enable_software_prefetch_in_join. #102444 (Xiaozhe Yu). - Optimize
MemoryTrackerlayout, improving its performance by ~25%. #103464 (Azat Khuzhin). - Rewrite
coalesce(a, b, ...) <op> constandifNull(a, b) <op> constpredicates before index analysis so per-column primary key and skip indexes on each argument can prune granules. Controlled by the new settingallow_key_condition_coalesce_rewrite(on by default). #103468 (Manuel). - Significantly improved query performance when reading Iceberg catalogs with large JSON metadata files by optimizing escaped slash processing. #103998 (Mohaidoss).
- Avoid index uncompressed cache overhead when the cache is disabled (server setting
index_uncompressed_cache_size = 0, which is the default). #104063 (Michael Kolupaev). - Fix
ORDER BY ... LIMITqueries with small limit reading excessive granules when combined with a non-selectiveWHEREfilter. Previously, any filter above an in-order read disabled the per-mark-range task split, so the pipeline could not cancel between granules and read the whole part for each stream. #104112 (Vladimir Cherkasov). - Fixed missing hash table sizes cache reuse after reordering JOIN sides. #104131 (Nikita Taranov).
- When
fsync_after_insertis enabled, fsync of part files is now performed in parallel using the IO thread pool, speeding up insert finalization on wide tables. The full ClickBenchhitsload is about 22% faster. #104137 (Alexey Milovidov). - Vectorise
find_first_symbols,find_first_not_symbols,find_last_symbols_or_null,find_last_not_symbols_or_null, andsplitIntoon AArch64 using NEON. Previously these helpers had a SIMD path only on x86 (SSE2 / SSE4.2) and fell through to a scalar loop on ARM. Speeds up TSV parsing by ~2x, URL functions andsplitByCharby ~1.3x on the ClickBenchhitsdataset; very dense JSON parsing (sub-16-byte field cadence) regresses slightly in line with the existing SSE2 trade-off. #104228 (Alexey Milovidov). - Reading data through a trivial
ALIAScolumn (e.g.some_alias['key']wheresome_alias ALIAS m) now goes through the same per-subcolumn read path as referencing the underlying column directly, restoring large I/O savings forMap,Array,TupleandNullablealiased columns. #104245 (Raúl Marín). - Reduced lock contention on the asynchronous remote-FS read path by making the per-query
AsyncReadCounterslockless. #104374 (Nikita Mikhaylov). - Slightly better query plan for projections in-order scan. #103723 (Mikhail Artemenko).
- Extend
optimizeUseNormalProjectionsto also handle a specific case where nothing was filtered but the projection’s sorting key can remove the sorting step from the query plan. #104680 (Mikhail Artemenko). - Allow
json.path[]syntax sugar and explicit type hints to work correctly on typedJSONpaths. #99179 (Pavel Kruglov). - Optimize
json.path[N].nested.path(which expands totupleElement(tupleElement(json.path[N], 'nested'), 'path')) intojson.path[].nested.path[N], which reads much less data. #99802 (Pavel Kruglov). - Optimize
SHOW TABLESaccess checks insystem.partsby hoisting database-level grant checks out of the per-table loop. #100860 (Shaohua Wang). - Remove a redundant per-table
SHOW TABLESaccess check in theSELECT name/SELECT database, namefast path ofsystem.tables. #100881 (Shaohua Wang). - Enable JIT compilation on macOS. #100947 (Alexey Milovidov).
- Skip deferring the row policy after
FINALwhen it depends only on sorting-key columns and is deterministic, and skip the correspondingPREWHEREdeferral that the row policy was forcing in that case. #102884 (Yarik Briukhovetskyi). - Added support for
hasAnyandhasAllas filter predicates in text indexes. #103266 (Anton Popov). - Route long-lived MergeTree heap state (per-part and per-table metadata) to a dedicated jemalloc arena, exposed via
jemalloc.mergetree_arena.*async metrics. Reduces default-arena fragmentation in steady-state and keeps per-part survivors from pinning otherwise-decayable pages. #104136 (Raúl Marín). - Improve ZooKeeper client timeout handling under heavy load when many requests are pipelined on a single session. The ZooKeeper client now uses a progress-based timeout: as long as any data is received from the server within
session_timeout_ms, the wait is extended. A hard cap of3 * session_timeout_msper request still bounds caller latency. Closes #100466. #104351 (Antonio Andelic). - Move per-event trace flags into a separate array and allocate them lazily, reducing the overhead of
ProfileEventstracing. #105030 (Azat Khuzhin). - Add
compareTrackAtforColumnDecimal, improving comparison performance forDecimalcolumns. #105110 (Artem Zuikov). - Added a SIMD implementation of
MD5(AVX2/AVX512) that hashes multiple inputs in parallel, improving throughput. #105161 (Joanna Hulboj).
Improvement
- Improve the help output for all ClickHouse applications:
--helpnow consistently returns exit code0, prints tostdout, and a top-levelclickhouse --helplists all subcommands. Adds a--no-sudooption forclickhouse start/restart(useful in Docker), and aclickhouse helpsubcommand. Continuation of #58244 from @qoega. #98148 (Alexey Milovidov). - The default of
input_format_column_name_matching_modeis changed frommatch_casetoauto. Input formats that match input column names against the table schema (JSONEachRow,CSVWithNames,JSONColumns,BSONEachRow,RowBinaryWithNames, etc.) now first try a case-sensitive match and fall back to case-insensitive matching when the case-sensitive match misses. The previous strict behavior is preserved undercompatibility. #104320 (Alexey Milovidov). - Added
STDDEVas a case-insensitive alias ofstddevSampfor PostgreSQL/SQL-standard compatibility. #105120 (Alexey Milovidov). - Added
array_to_stringas a case-insensitive alias ofarrayStringConcatfor PostgreSQL compatibility. #105121 (Alexey Milovidov). - Added
unnestas a case-insensitive alias ofarrayJoinfor PostgreSQL compatibility (function-call form). #105124 (Alexey Milovidov). - The progress bar in
clickhouse-clientnow shows temporary data on disk usage (e.g. for external sort, aggregation, or JOIN) next to RAM, including a per-host breakdown for distributed queries. #105190 (Alexey Milovidov). - Added
system.predicate_statistics_log, a new sampled log of predicate filter selectivity and MergeTree index-granule pruning per query. Disabled by default; enable via thepredicate_statistics_sample_rateserver setting. Needed for automatic index and projection recommendations. #98727 (Yarik Briukhovetskyi). - Allow skipping local shard with missing table when
skip_unavailable_shardsis enabled. #100141 (Alexey Milovidov). - Add startup warnings (visible in
system.warnings) when a Linux mdraid array is being resynchronized or is in a degraded state, as both can affect disk I/O performance or indicate disk failures. #100941 (Alexey Milovidov). - WASM UDFs now appear in
system.functionswith correctorigin(WasmUserDefined),syntax,arguments, andreturned_valuecolumns populated from their ClickHouse type metadata. Previously they were either missing or listed with the wrong origin as duplicates. #101053 (Vasily Chekalkin). - The
generate_seriestable function now supports negative step values for generating descending sequences, e.g.SELECT * FROM generate_series(99, 0, -1). #101056 (Alexey Milovidov). - Fix
Context has expiredexceptions raised by some functions (dotProduct,formatRow,structureToCapnProtoSchema/structureToProtobufSchema, user-defined functions) when used in deferred execution paths such asDEFAULT/MATERIALIZEDexpressions and table engine settings, by ensuring those functions hold a strong context where required. #101109 (Alexey Milovidov). - Fix spurious
Cache limits violatedlogical errors on priorities created with zero limits (such as the per-query filesystem cache priority used whenenable_filesystem_query_cache_limitis on). #101428 (Alexey Milovidov). - Auto-detect the region for
s3expressendpoints. #101520 (Pradeep Chhetri). - Support field ids for data files in
Icebergwrites. Closes #102322. #102362 (Konstantin Vedernikov). - The left panel in the web UI (
play.html) now scrolls independently, stays visible when the page is scrolled, and clicking a table scrolls to the query area. #102498 (Alexey Milovidov). - Allow opening the Play UI in a new tab via Ctrl/Cmd/Shift+click or middle-click on the ClickHouse logo in the left panel. #102501 (Alexey Milovidov).
- New metrics to track memory used by projection primary keys and projection index granularity across all tables. #102587 (Narasimha Pakeer).
- Apply
max_network_bandwidth_for_userandmax_network_bandwidth_for_all_usersto remote filesystem reads/writes. #103080 (Azat Khuzhin). - Improve the resilience of backups when Refreshable Materialized Views are constantly refreshed by making decisions based on the snapshotted tables’ state rather than a global one. #103384 (Nikita Mikhaylov).
SELECT * FROM system.databasesnow always lists data lake catalog databases regardless of theshow_data_lake_catalogs_in_system_tablessetting. Previously they were hidden by default, which was inconsistent withSHOW DATABASESthat always showed them. #103444 (Alsu Giliazova).- Align the default of the server setting
concurrent_threads_soft_limit_ratio_to_coresin code with the shippedconfig.xmlvalue (2), so the defaultmax_min_fairconcurrent threads scheduler caps query processing threads at 2x cores out of the box even when the shippedconfig.xmlis not used. #103446 (Alexey Milovidov). - Improved sanitizer robustness in parser and string-function edge cases by handling empty input in
getURLScheme, avoiding null-pointer arithmetic inLexer::nextTokenmax_query_sizechecks, and short-circuiting UTF-8 subsequence evaluation on empty haystacks before decoding. #103489 (Yakov Olkhovskiy). - Improved correctness of monotonicity inference for
divide(0, x)andintDiv(0, x): previously the functions were unconditionally reported as monotonic, but0 / xis non-monotonic on any range that includes 0 because0 / 0is undefined (NaN/Inffordivide, division-by-zero exception forintDiv). The false claim causedKeyCondition::applyMonotonicFunctionsChainToRangeto produce ranges withleft > right, which tripped aLOGICAL_ERRORInvalid binary search result in MergeTreeSetIndexin debug builds when anIN/NOT INexpression on the primary key wrapped the key individe(0, key)orintDiv(0, key). Release builds were unaffected — the assertion is gated by#ifndef NDEBUG. #103621 (Groene AI). - Replace the
HTTPConnectionPool*TCP{Rcv,Snd}BufBytes_{p50,p75,p90,p95}async metrics with a bucket-based histogramhttp_pool_tcp_buf_bytes(labelsgroup,direction) insystem.histogram_metrics. Per-group total async metrics are preserved. #103704 (Sema Checherinda). - The server settings
{disk,storage,http}_connections_{rcvbuf,sndbuf}are now reported as changeable without restart insystem.server_settings. Their values can be updated viaSYSTEM RELOAD CONFIG; the runtime application path was already in place since #100478. #103772 (Sema Checherinda). - Add support for resolved symbols (
Array(String)) inflameGraph. #103816 (Azat Khuzhin). - CLI client can now specify
<rainbow_parentheses>false</rainbow_parentheses>in its config in environments where terminal colors clash with the parentheses (similarly,clickhouse formatnow has--no_rainbow_parentheses). #103851 (Larry Snizek). - Fix
MultiVolnitskyUTF-8 case-insensitive search by rolling back partialputNGraminserts on failure and switching failed needles to fallback searchers, avoiding inconsistent state. #103864 (Yakov Olkhovskiy). - Implement
sched_getcpuviarseqTLS in glibc-compatibility musl. #104016 (Azat Khuzhin). - Replicated refreshable materialized view in APPEND mode will no longer refresh twice if connection to zookeeper was briefly lost during refresh. #104051 (Michael Kolupaev).
- Allow Distributed tables without an explicit column list to validate sharding keys against the inferred remote table structure. #104111 (Yue).
- Fix REST catalog with
Azureabfsspath. #104120 (Konstantin Vedernikov). - Honor
role_arnandrole_session_nameauth settings in the Keeper S3 snapshot client, allowing snapshot uploads to use STSAssumeRole-based authentication. #104140 (Alexey Milovidov). - Fix a memory leak when running queries with
MATERIALIZEDCTEs. #104153 (Alexey Milovidov). - Fix
lowerUTF8/upperUTF8exception when processing large non-ASCII data sets (e.g. during text-index builds) where the accumulated output buffer would exceed 2 GiB; reject excessively long single rows with a clear error. #104229 (Shaohua Wang). - Harden MergeTree column-statistics loading against transient I/O failures to prevent permanently disabling statistics-based optimizations for affected parts. #104372 (zoomxi).
INSERT INTO ... SELECT FROM input(...)no longer requires theCREATE TEMPORARY TABLEgrant. #104470 (Alexey Milovidov).- Added a new MergeTree setting
concurrent_part_removal_threshold_for_remote_disk(default16) that is used instead ofconcurrent_part_removal_thresholdwhen at least one part being removed is stored on a remote disk. The previous threshold of100could makeDROP TABLEand other part-removal operations on object storage backends stall for tens of seconds because removals were performed serially even though each one is a separate network round-trip. The new setting causes the parallel removal path to be entered much sooner on remote storage, while leaving local-disk behavior unchanged. #104676 (Groene AI). - New setting
defer_partition_pruning_after_final(default1) makes the 26.3-introduced behavior of skipping partition pruning underFINALopt-out. Set it to0to restore pre-26.3 partition pruning — substantially faster on event-log workloads where same-PK rows cannot span partitions.compatibility = '26.2'flips it to0automatically. #104705 (Nikita Fomichev). - Fix
intExp2returning wrong results for out-of-range inputs (shifts>= 64under JIT, and integers with magnitude exceedingINT_MAXon both code paths). #105054 (Raúl Marín). - Quote shell arguments built from CLI options and parsed input in
clickhouse installandclickhouse git-importso paths, user/group names, and commit hashes containing whitespace or shell metacharacters are handled correctly. #105232 (Raúl Marín). - The
Aliastable engine is now non-experimental and available without theallow_experimental_alias_table_enginesetting. #103488 (Alexey Milovidov). - Added
--queries-formatoption toclickhouse-benchmarkto choose between the default tab-escaped one-query-per-line input (tsv) and parsing standard input as a script of multiple queries separated by;(script). #99972 (Aleksandr Musorin). - The element-wise tuple operators
tuplePlus,tupleMinus,tupleMultiply,tupleDivide,tupleModulo,tupleIntDiv, andtupleIntDivOrZeroare now variadic and accept two or more tuples of the same size, applied element-wise as a left-fold. They previously accepted exactly two arguments only. #104659 (Aruj Bansal). - Added a new built-in web UI at
/processors-profilethat visualizes the pipeline of any pastSELECTquery as a heatmap, sourced fromsystem.query_logandsystem.processors_profile_log. Each processor is colored by itselapsed_usand shows per-processor stats (rows, bytes, wait times) on hover. #104614 (Nikita Mikhaylov). - Setting
query_plan_use_logical_join_step(and its aliasquery_plan_use_new_logical_join_step) is now obsolete and has no effect; the logical join step is always used. #104017 (Vladimir Cherkasov). - The
userinput onplay.htmland the other built-in web pages (dashboard.html,jemalloc.html,merges.html,binary.html,webterminal.html) is no longer pre-filled with the literal textdefault. It now shows auserplaceholder hint and is empty by default. When left empty, the page does not send auser=URL parameter (and the WebTerminal auth JSON omits theuserfield), so the server applies its usual fallback to thedefaultuser — and HTTP credentials supplied via other channels (X-ClickHouse-User, HTTP Basic, per-handler<handler><user>configuration) are no longer overridden. #105254 (Alexey Milovidov). ORCreader: decouple offset-based read (readBigAt) fromuse_prefetch, so EC-encoded data onHDFScan be read correctly even whenuse_prefetch = false(e.g. by Gluten). #103348 (zhanglistar).- Files downloaded from
play.htmlwith theCSVWithNamesformat now use the.csvfile extension. #103737 (JackFielding). - More input validation for the BigLake catalog. #105117 (Konstantin Vedernikov).
Bug Fix (user-visible misbehavior in an official stable release)
- Fix inconsistent formatting by remembering if an expression was parenthesized. #92340 (Alexey Milovidov).
- Fix accurate comparison between Decimal and Float types. #94293 (zoomxi).
- Allow positional arguments in distributed queries. #94359 (simonmichal).
- Fix assertion failure in
DatabaseCatalog::updateDependencieswhen dropping and recreating a materialized view with the same name; also fix view dependencies being silently lost duringRENAME TABLEorEXCHANGE TABLESwhen referential dependencies were empty. #98779 (Alexey Milovidov). - Fixed a server abort (assertion failure in
DatabaseCatalog::getTableImpl) that occurred when creating a table viaON CLUSTERwith a UUID identical to an existing database’s UUID. #98861 (xiaohuanlin). - Fixed usage of skip indexes on data read (with enabled setting
use_skip_indexes_on_data_read) and existing patch parts created by lightweight updates. #99543 (Alexey Milovidov). - Fix “Not-ready Set” exception when a filter with
IN (subquery)is moved to PREWHERE by the query optimizer. #100375 (Alexey Milovidov). - Fix “Cannot find column” error when combining
ADD COLUMNwithRENAME COLUMNin a singleALTER TABLEstatement. #100387 (Alexey Milovidov). - Fix views with mixed
UNIONandINTERSECT/EXCEPToperators returning wrong results afterDETACH/ATTACHor server restart. #100390 (Alexey Milovidov). - Fix “Trying to execute PLACEHOLDER action” exception that could occur during stress testing with the AST fuzzer when a correlated subquery appeared in an IN clause. #100398 (Alexey Milovidov).
- Fix logical error exception when inserting into an Iceberg table with a
Datecolumn partitioned byyear,month, ordaytransforms. #100404 (Alexey Milovidov). - Fix skip index being used with incompatible data after
ALTER TABLE MODIFY COLUMNchanges the column type, which could cause server crashes in sanitizer builds or incorrect query results. #100526 (Alexey Milovidov). - Fix credential leak in
query_logforpaimonCluster,paimonS3Cluster,paimonAzureCluster, anddeltaLakeS3table functions. #100529 (JIaQi Tang). - Fix
DROP TABLEon Kafka engine tables potentially hanging indefinitely due to a deadlock inrd_kafka_consumer_close. #100604 (Alexey Milovidov). - Replace the hardcoded
source_table_engineslist with runtime lookup viaStorageFactoryandDatabaseFactory. Addsource_access_typetoDatabaseFactory::EngineFeaturesso thatCREATE DATABASEwith source engines (PostgreSQL, MySQL, S3, etc.) requires the same source grants asCREATE TABLE. FixesGRANT TABLE ENGINE ON *failing withtable_engines_require_grant=false. Closes #71544. #100746 (pufit). - Fix server crash when reading from a table whose
ALIAScolumn contained a correlated subquery nested inside a function call (e.g.ALIAS toString(intDivOrZero(x, (SELECT ...)))).CREATE TABLEandALTER TABLEnow reject any subquery at any depth inDEFAULT/ALIAS/MATERIALIZEDcolumn expressions withTHERE_IS_NO_DEFAULT_VALUE. Previously, the shallow validation accepted nested subqueries, so the correlated case crashed at read time and the nested non-correlated case appeared to work but could lead to unexpected behavior; both are now rejected at DDL time. #100753 (Groene AI). - Fixed a server crash (
Logical error: Bad cast from type DB::FunctionNode to DB::ColumnNode) that could occur when using queries with correlated subqueries on tables that haveCONSTRAINT ... ASSUMEdefinitions, whenoptimize_substitute_columnsandconvert_query_to_cnfsettings are enabled. #100756 (Groene AI). - Fix an exception that could occur when inserting a row into a JSON column where the row introduced a new dynamic field alongside a typed field with an incompatible value, and the column was subsequently used as a GROUP BY key. #100758 (Jimmy Aguilar Mena).
- Fix workload IO scheduling being silently bypassed for S3/object-storage writes that go through the
DiskObjectStorageTransactionpath (used bys3_with_keeperdisks and explicitly whenuse_fake_transaction=false). Previously, INSERT writes into MergeTree tables on such disks ignoredCREATE RESOURCE/CREATE WORKLOADthrottling because the resource link was never injected intoWriteSettingsfor the transactional write path. #100777 (JIaQi Tang). - Fix shared schema-cache collision between
ProtobufandProtobufList: reading a message first asFORMAT Protobufand then asFORMAT ProtobufListcould fail becauseProtobufListforced the cached schema into its envelope form.ProtobufListnow falls back to the cached message type when no envelope schema is available. #100849 (Callum Cooper). - Fix heap-buffer-overflow in Rust CXX bridge due to
std::exceptionABI mismatch. #100931 (Azat Khuzhin). FunctionVariantAdaptornow throwsILLEGAL_TYPE_OF_ARGUMENTwhen allVariantalternatives are incompatible with a function, instead of silently returningNullable(Nothing). Previously, aWHERE function(variant_col)predicate where no alternative type was compatible would return 0 rows with no error, while the equivalentSELECTcontext already threw correctly. #100939 (Vasily Chekalkin).TRUNCATE ALL TABLESno longer fails when the database contains views. #100943 (Alexey Milovidov).- Fix the
optimize_rewrite_array_exists_to_hasoptimization to correctly handle type-incompatible cases (e.g. Date vs String) and re-enable it by default. #100944 (Alexey Milovidov). - Fix S3 settings priority so that
storage_configurationdisk settings override global<s3>section, and user/profile/query-level settings override both. #100975 (Alexey Milovidov). - Fix sparse serialization losing the sign of negative zero (-0.0) for BFloat16, Float32, and Float64 columns. #100983 (Takumi Hara).
- Fixed two bugs in the WKT geometry parser used when reading WKT-encoded GeoParquet and Arrow files:
MULTILINESTRINGgeometries were incorrectly parsed asPolygon(causing an exception for typed columns and silent data corruption for mixedGeometrycolumns), and a malformed WKT string with no type keyword triggered undefined behaviour instead of a clean error. #100997 (Vasily Chekalkin). - Fix
grouping/GROUPING SETSqueries on Distributed tables with a single shard that failed with “Method executeImpl is not supported for ‘grouping’ function”. #101030 (Alexey Milovidov). - Fix
LOGICAL_ERROR“Column identifier is already registered” in the planner that could occur when the same table expression was processed multiple times. #101048 (Alexey Milovidov). - Fix LOGICAL_ERROR exception “Column identifier is already registered” when
additional_result_filtersetting is used with UNION or EXCEPT queries. #101051 (Alexey Milovidov). - Fixed server crash (Logical error: Bad cast from ColumnVector to ColumnNullable) when using
* APPLYwith aggregate functions andgroup_by_use_nulls=1with GROUPING SETS, ROLLUP, or CUBE. #101062 (Groene AI). - Fix infinite loop when
input_format_csv_skip_first_linesorinput_format_tsv_skip_first_linesexceeds the number of lines in the file. #101111 (Alexey Milovidov). - Fix out-of-bounds access in lazy materialization optimization that could cause an exception in debug builds. #101144 (Alexey Milovidov).
- Fix type inference in recursive CTEs: column types are now iteratively widened via
getLeastSupertypeacross the non-recursive and recursive sides of theUNION ALLuntil convergence, preventing integer overflow in expressions likex + 1. #101155 (Alexey Milovidov). - Clamp MergeTree compress block size settings (max_compress_block_size, min_compress_block_size, marks_compress_block_size, primary_key_compress_block_size) to 256 MiB to prevent server crash when extreme values are set via CREATE TABLE SETTINGS. #101159 (Groene AI).
- Fix a LOGICAL_ERROR crash in
QueryAnalyzer::resolve()when a ROW POLICY uses a scalar subquery in itsUSINGclause (e.g.USING (SELECT 1)). Closes #100695. #101263 (Groene AI). - Fix undefined behavior in
MergeTreeDataPartWriterCompact::cancelwhen a stream allocation fails. #101292 (Alexey Milovidov). - Fixes a case where timezone was not included during the assignment in the ALTER statement. Closes #101328. Related https://github.com/ClickHouse/ClickHouse/pull/100647. #101403 (Yarik Briukhovetskyi).
- Fix server crash (LOGICAL_ERROR) for INSERT SELECT queries with ORDER BY ALL when the SELECT pipeline produces multiple streams. #101443 (Groene AI).
- Fix incorrect query results caused by join reordering pushing an INNER JOIN filter (referencing only the preserved side of an outer join) into the outer join’s ON clause. #101504 (Vladimir Cherkasov).
- Skip applying lazy materialization for plans with arrayJoin, which could lead to limit not being respected. Close #101608. #101644 (Vladimir Cherkasov).
- Fix incorrect JOIN query results when
mergeFilterIntoJoinConditionoptimization silently dropped a WHERE equality condition with mismatched types. #101652 (Xiaozhe Yu). - Fix the
errortest hint not working for syntax/parsing errors — previously-- { error SYNTAX_ERROR }on a malformed query would fail with “Expected server error” instead of matching the client-side parse error. #101675 (Groene AI). - Fix
INTO OUTFILE ... TRUNCATEnot actually using atomic rename — the write went directly to the original file instead of a temp file, so on query failure the original content was destroyed. Now the data is written to a temp file and renamed only on success. #101884 (Pablo Marcos). - Fixed an exception
Unsupported DeltaLake type: varchar(n)when reading Delta Lake tables whose schema contains varchar(n) or char(n) column types. These types are now mapped to String, consistent with how the Delta Lake protocol stores them as plain byte arrays in Parquet. #101973 (Flavio Malavazi). - Fix silent data loss when reading tar archives from S3 with
schema_inference_mode=unionand heterogeneous Parquet schemas — the Parquet metadata cache incorrectly reused the first file’s metadata for all subsequent files in the archive. #101990 (Ahaan Limaye). - Fix server crash (LOGICAL_ERROR) when executing ALTER TABLE UPDATE/DELETE on Iceberg tables when no prior SELECT or INSERT was done on the table in the same server lifetime. #102113 (Alexey Milovidov).
- Fix possible crash when an ALTER query executed on tables from in-memory database (e.g. temporary tables). #102360 (Den Kalantaevskii).
- Fixed
formatQueryproducing duplicate grants likeGRANT FILE ON *.*, FILE ON *.* TO xinstead ofGRANT FILE ON *.* TO xwhen formatting backward-compatible READ/WRITE grants on the same source. #102411 (Groene AI). - Fix lost parallelism for aggregation after read-in-order queries when
max_streams_to_max_threads_ratiois greater than 1. #102467 (Alexey Milovidov). - Fixed a crash (
LOGICAL_ERROR: Unknown virtual column) when selecting subcolumns (like.nullfor Nullable,.size0for Array, tuple elements, or map keys/values) from a Buffer table engine. #102470 (Groene AI). - Fix exception “Cannot fold actions for projection” in join reorder optimization when a LEFT/RIGHT JOIN with
join_use_nullsis combined with other joins involving more than two tables. #102516 (Alexey Milovidov). - Fixed silent overflow in scalar pointwise operations on numericIndexedVector (e.g.
numericIndexedVectorPointwiseAdd) when the scalar is out of range. Such inputs now raiseINCORRECT_DATAinstead of returning corrupted values. #102546 (FriendLey). - Fix inconsistent AST formatting for INSERT with SAMPLE and query-level OFFSET. Closes #102523. #102547 (zoomxi).
- Fix
LOGICAL_ERRORexception ingroupConcatwhen deserializing a malformed aggregate function state. #102558 (Christoph Wurm). - Now we do not accept garbage at the end of Time64 CSV values with
input_format_csv_use_default_on_bad_values=0. Closes #102490. #102596 (Yarik Briukhovetskyi). - Fix UNKNOWN_ELEMENT_OF_ENUM exception when inserting default value to JSON column with Enum typed paths. Closes #102359. #102687 (Pavel Kruglov).
- Fix columns_substreams.txt corruption during column rename in some cases. Closes #102259. #102689 (Pavel Kruglov).
- Fix inserting into Time data type during JSON parsing. Closes #102016. #102690 (Pavel Kruglov).
- Fix hex encoding of content sample in cached schema filenames. Closes #101904. #102703 (Pavel Kruglov).
- Fixed sort order violation (crash in debug, silent data corruption in release) during
SummingMergeTreemerge when theORDER BYkey is a hash expression over aFloat32column containing signaling NaN values. #102791 (Groene AI). - Make
DETACH DATABASE ... SYNCand other operations that callwaitDetachedTableNotInUsecancellable viaKILL QUERYand responsive to server shutdown, preventing indefinite hangs when a concurrent query holds a table reference. #102804 (Antonio Andelic). - Fixed possible incorrect result of
ANY RIGHT JOIN. #102893 (Nikita Taranov). - Fix S3 requests failing with
ios_base::clear: unspecified iostream_category errorinstead of being retried, caused by PocoBufferedStreamBuf::flushBuffernot handling short writes from the socket layer. #102894 (Sema Checherinda). - Fix
input('auto')table function failing via HTTP interface in INSERT SELECT queries. #102902 (Miсhael Stetsyuk). - Disable trivial LIMIT optimization with row policies/additional_table_filters (to allow parallel index analysis). #102921 (Azat Khuzhin).
- Hide secret key in
HMACSQL function. Fix #102927. #102997 (Mikhail f. Shiryaev). - Fix
MULTIPLE_EXPRESSIONS_FOR_ALIASexception raised on distributed queries that reference the samequantilecall multiple times (e.g. inSELECT,HAVING, andORDER BY) withoptimize_syntax_fuse_functionsenabled. #103014 (tanner-bruce). - Fixes a case found by CI where a not-ready set was passed when the filter depends on the left-side column. Closes #102966. #103029 (Yarik Briukhovetskyi).
- Fix castOrNull to JSON in some cases. Closes #101818. #103036 (Pavel Kruglov).
- Fix
SELECT DISTINCTsilently returning incomplete results when an aggregate projection matched the query and some parts of the table had no projection data (e.g. the projection was added on a table that already held data, andMATERIALIZE PROJECTIONwas not run). Closes #102951. #103052 (Nihal Z. Miaji). - Fix
TOO_FEW_ARGUMENTS_FOR_FUNCTIONexception when aWHEREpredicate such asAND(OR(A, A), A)collapses to a single top-level argument during common expression extraction in the analyzer. #103072 (Peng). - Fix a logical error
Function writeSlice expects same column types for GenericArraySlice and GenericArraySinkraised when evaluatingif/ifNullover tuples, maps, or arrays containing aQBitelement.ColumnQBit::structureEqualsincorrectly compared the inner tuple of oneQBitcolumn against the outer wrapper of the other, so structurally identicalQBitcolumns were reported as different. #103084 (Groene AI). - Make
DETACH DATABASEwithdatabase_atomic_wait_for_drop_and_detach_synchronouslyrespectKILL QUERYinstead of hanging indefinitely when a table reference is held. #103095 (Alexey Milovidov). - Fix segfault when deleting WASM module using non-identifier predicate (e.g.
WHERE 1=1). #103101 (Joe Redfern). - Fix backward compatibility break where old clients fail with
UNEXPECTED_PACKET_FROM_SERVERwhen inserting into a newer server viaremote()or distributed tables, caused by unconditionalsendProgressat the end ofprocessInsertQuery. #103148 (Sema Checherinda). - IN with non-constant tuple second argument must not CAST tuple elements down to the LHS type, this can overflow. Closes #103055. #103169 (Yarik Briukhovetskyi).
- Fix use-of-uninitialized-value in protocol function. #103187 (Pavel Kruglov).
- Fix
LOGICAL_ERROR(Bad cast … to ColumnLowCardinality) during MergeTree index analysis when aWHEREclause compares aLowCardinalitykey column with a constant cast to a type that contains nestedLowCardinality(for exampleVariant(LowCardinality(Date), String)). #103211 (Groene AI). - Fix
Logical error: 'index < bucket_count'in thetimeSeries*ToGridaggregate function family (e.g.timeSeriesResampleToGridWithStaleness,timeSeriesChangesToGrid,timeSeriesResetsToGrid,timeSeriesRateToGrid) when called with extreme timestamp parameters that would overflow signed 64-bit arithmetic in the bucket count computation. Also cap the total number of grid buckets at 16 million to prevent accidental large-memory allocation from adversarial inputs. #103223 (Groene AI). - Fix
Logical error: 'Port is already connected'exception during pipeline expansion in the lazyFINALpath forReplacingMergeTree. The bug affected queries withquery_plan_optimize_lazy_final = 1whenReadFromMergeTree::initializePipelineinserted internal transforms (e.g. aResize) that wired the sub-pipeline’s processors together, causingLazyUnorderedReadFromMergeTreeSource::expandPipelineto try to connect output ports that were already connected. #103230 (Groene AI). - Fix wrong results from
LIMIT BYandDISTINCTwhen the input is aUNION ALLof sorted subqueries. The query plan optimizer incorrectly treated such a union as globally sorted, causing extra rows to be returned. #103231 (Nihal Z. Miaji). - Fix possible crash during statistics calculation in Map type with lazy replication. Closes #102390. #103273 (Pavel Kruglov).
- Fix a data race for ClickHouse, MySQL, PostgreSQL and XDBC dictionary sources where
clone() constreads from andisModified() constwrites to the sameinvalidate_query_responsestring. #103277 (Miсhael Stetsyuk). - Fix incorrect monotonicity detection for
Date32. Closes #101265. #103283 (Yarik Briukhovetskyi). - Cap pre-auth TCP Hello packet strings to 64 KB and add
handshake_timeout_millisecondsserver setting to limit total handshake time, preventing unauthenticated clients from consuming excessive memory or holding threads indefinitely. #103284 (Sema Checherinda). - Fix Parquet ColumnIndex stats min_value > max_value for String columns. #103334 (Saurabh Kumar Ojha).
- Fix incorrect handling of NULL rows for
Nullable(Tuple(...))inputs inflattenTupleandtupleToNameValuePairs.flattenTuplenow preserves the outer null map so NULL rows stay NULL.tupleToNameValuePairsnow changes the result’s value type toNullable(T)when possible when the input isNullable(Tuple(...)), so NULL rows produce[('a', NULL), ('b', NULL)]instead of[('a', 0), ('b', 0)]. When the element type cannot be wrapped inNullable(e.g.Array), default values are used instead of NULL. Closes #103312. #103383 (Nihal Z. Miaji). - Check for malformed flattened Dynamic data in Native format. #103392 (Pavel Kruglov).
- Fix stale RPC causing replication stall after snapshot sync. #103406 (Seva Potapov).
- Fix a
LOGICAL_ERROR“Cannot pop N rows from X” that aborted the server (in debug / sanitizer builds) when reading a malformed BSON document containing a value whose BSON type is incompatible with the target column type inside aNullable(T)orArray(Nullable(T))column. The malformed row now produces a cleanILLEGAL_COLUMNexception as intended. #103418 (Groene AI). - Fix a server abort in
arrayFillandarrayReverseFillwhen applied to anArray(String)column whose first row is empty together with a constant-false lambda. The aggregate / sub-array loop underflowed asize_tindex toSIZE_MAX, which then caused an out-of-bounds read insideColumnString::doInsertManyFrom. Same bug family as #12263. #103424 (Groene AI). - Fixes ACCESS_DENIED / UNKNOWN_TABLE in downstream APPEND RMVs with SQL SECURITY DEFINER when an upstream REPLACE RMV’s EXCHANGE flips the target storage identity mid-resolution. #103427 (Alexander Gololobov).
- Populate
_timecolumn fromurltable function. #103437 (Nikita Taranov). - Fix potential out-of-bounds read in the
ALPcodec decompression path when processing malformed input with an invalid bit-width. #103457 (Raufs Dunamalijevs). - Fix a bug where
SYSTEM SYNC FILESYSTEM CACHE '<name>' ON CLUSTER ...could lose the cache name while formatting the query, causing remote nodes to sync all filesystem caches instead of only the requested cache. #103469 (Asish Kumar). - Fix processing of URL-encoded path in
deltaLakeAzure. Closes #103509. #103525 (Smita Kulkarni). - Fix heap-use-after-free in multiplying an
AggregateFunctionstate by an integer (e.g.quantilesExactState(...) * N). The exponentiation-by-squaring loop merged the state with itself, which is undefined when the aggregate function’smergereallocates its internal storage. Closes STID 0988-40af. #103536 (Groene AI). - Fixed a rare
LOGICAL_ERROR“Part X intersects previous part Y” raised duringReplicatedMergeTreetable startup when two empty unexpected parts on disk had overlapping but non-containing block ranges. The exception aborted the table-attach thread and prevented the table from coming up. #103537 (Groene AI). - Fix
Logical error: Incorrect mark rows for part ...(debug-only assertion) that was triggered by mutations onMergeTreetables with non-adaptive index granularity (index_granularity_bytes = 0) whose last data mark was incomplete (most reliably reproduced viaDETACH/ATTACHfollowed by a lightweightDELETE). #103538 (Groene AI). - Fix
clickhouse-localreturning 0 rows silently when reading from/procand/syspseudo-files via thefile()table function (e.g.SELECT * FROM file('/proc/cpuinfo', 'RawBLOB')). #103548 (Ashrith Bandla). - Fixed handling of the
max_string_lengthargument for theGenerateRandomtable engine. #103550 (Alex Kuleshov). - Fix masking nested credentials in logs. #103552 (Vitaly Baranov).
- Fix SVE detection using SVE instructions when unavailable. #103568 (Raúl Marín).
- Fix
GenerateRandomstorage args parsing. #103574 (Konstantin Bogdanov). - Fix infinite loop on
WITH FILLfor data starting with ±inf. #103580 (Konstantin Bogdanov). - Fix
JSONExtractinto aVarianttype silently truncating fractional JSON numbers. Previously,JSONExtract('{"x": 3.14}', 'x', 'Variant(Int64, Float64)')returnedInt64=3andJSONExtract('{"x": 3.14}', 'x', 'Variant(String, Int64)')returnedInt64=3, dropping the fractional part. The fractional value is now preserved losslessly: aFloat64/Decimalmember claims it when present, otherwise aStringmember captures the original JSON.Varianttypes containing only integer members (e.g.Variant(Int64, Int32)) and direct integer extraction (JSONExtract(json, 'Int64'),JSONExtractInt, etc.) are unchanged. #103620 (Groene AI). - Fix
SYSTEM INSTRUMENT REMOVEwithout arguments producingstd::bad_optional_access(error code 1001) instead ofSYNTAX_ERROR(error code 62). #103622 (Pablo Marcos). - Fix logical error / undefined behavior in
windowIDandtumblewindow view when called with a timezone string as the 3rd argument. #103641 (Alexey Milovidov). - S3 client logging now treats HTTP 400 responses that include a non-empty x-amz-bucket-region header (wrong SigV4 signing region) as an informational wrong-region case with a clearer log line instead of the generic error-style path. The STS web identity credentials provider is added to the S3 credentials chain only when web identity is configured, which reduces spurious warnings for deployments that do not use it. Closes #99140. #103673 (MeltonSmith).
- Fix
SYSTEM SYNC REPLICA <db>.<tbl> IF EXISTSto silently succeed when the database does not exist, matching the existing behaviour for a missing table and the precedent set byDROP TABLE IF EXISTS. Previously the query threwUNKNOWN_DATABASEdespiteIF EXISTS. Closes #103629. #103689 (Groene AI). - Fix logical error
Arguments of 'plus' have incorrect data typesthrown byFunctionBinaryArithmetic::executeImpl2when aMergeTreetable hadArray(LowCardinality(...))in its sort key and aWHEREclause usedplus/minusbetween that column and anArrayconstant of a different element type.KeyCondition::getMonotonicityForRangenow stripsLowCardinalityrecursively before invoking the inner numeric dispatch. #103701 (Groene AI). - Fix dynamic cache resize race in 26.1+. #103702 (Kseniia Sumarokova).
- Fixed an issue where text and bloom_filter skip indices on
ALIAScolumns whose expression contained a lambda with captured constants (e.g.arrayMap((k, v) -> concat(k, '=', v), mapKeys(m), mapValues(m)))were silently ignored. #103708 (Anton Popov). - Fix
positionandpositionCaseInsensitivewith astart_posclose toUINT64_MAXgetting stuck or causing a segmentation fault due to overflowing pointer arithmetic. #103766 (Raúl Marín). - Fixes undefined behavior while parsing dateTime with a double fractional part. #103773 (Yarik Briukhovetskyi).
- Fixed a data-correctness regression in 26.x where JIT-compiled
ifandmultiIfwith aDecimalresult type and a non-Decimal(integer or float) literal in one branch silently returned a value10^scaletoo small. The slow (non-JIT) path was unaffected. Workaround on affected versions:SET compile_expressions = 0. #103809 (Groene AI). - Fixes forwarding the tokenizer from the text index to supported functions. #103826 (Elmi Ahmadov).
- Fix wrong results from
numbers,generate_series, and similar range-honoring sources when theWHEREclause usesINorNOT INover a tuple whose elements deduplicate to a single key column (for example,WHERE tuple(number, number) NOT IN (tuple(1, 2))). Closes #103660. #103835 (Groene AI). - Keep the auto-spilling hash join’s actual memory peak under
max_bytes_before_external_join. Previously, statistics-driven preallocation, in-place hash table doubling, and unboundedGraceHashJoinin-memory buckets could each push the query past the configured cap and tripMEMORY_LIMIT_EXCEEDED. #103838 (Alexey Milovidov). - Fix a hang in
clickhouse-localshutdown when system logs (such astext_logorfilesystem_cache_log) are configured.SystemLogs::flushImplwas callingBaseDaemon::instance().flushTextLogs(), which throwsstd::bad_castoutsideclickhouse-serverand left the saving threads running untilpthread_cond_destroyblocked the destruction of the system log queues. #103874 (Alexey Milovidov). - Reject
MATERIALIZEDCTE queries whose body resolves to different inferred column types in different references with a clearTYPE_MISMATCHerror instead of crashing the server with aBad castLOGICAL_ERROR. This previously happened when the CTE body referenced identifiers from outer scope (for example an alias from the calling subquery’s projection) that were inlined as different constants per reference. #103879 (Groene AI). - Fix a use-of-uninitialized-value in the JOIN-conversion query plan optimizers (
tryConvertAnyOuterJoinToInnerJoin,tryConvertAnyJoinToSemiOrAntiJoin) when the filter on top of anANYOUTERJOINcontains a non-deterministic function such asrand,now, orrowNumberInAllBlocks. The optimizer no longer attempts to constant-fold such filters and leaves the JOIN unchanged, which also prevents incorrect conversions toINNER/SEMI/ANTI JOINthat could silently drop rows. #103880 (Groene AI). - Fix a use-after-free in
StorageKafka2that could crash the server when a Keeper session is replaced while the consumer is holding ephemeral topic-partition locks. #103890 (Groene AI). - Fixed a
LOGICAL_ERROR“Primary key type mismatch” thrown when joining anEmbeddedRocksDBtable viaJOIN ... USING (key)against a subquery whose key column has a different type (e.g.Nullable(UInt64),Int64,Decimal) than the storage’s primary key. The planner now declinesDirectKeyValueJoinon type mismatch and falls back toHashJoin, which handles the type conversion. #103928 (Groene AI). SET max_threads = DEFAULT(and the same formax_final_threadsandmax_parsing_threads) no longer loses the auto state. Previously, after resetting one of these settings,system.settingswould report the resolved core count (e.g.32) instead of'auto(32)', and the server would behave as if the value had been explicitly pinned. #103991 (Groene AI).- Fix
SIZES_OF_ARRAYS_DONT_MATCHwhen readingAggregateFunction(topK(N), String)columns whose persistedalpha_sizewas grown by a pre-25.12 deserialize+serialize cycle. #104002 (Raúl Marín). - Fixed SQL injection vulnerability in PostgreSQL, Cassandra and XDBC dictionary sources: string keys containing single quotes were escaped with
\'(backslash), which these backends treat as a literal backslash rather than an escape sequence, allowing arbitrary SQL to be injected into dictionary lookup queries.ExternalQueryBuildernow emits SQL-standard''escaping for those backends; ClickHouse and MySQL dictionary sources continue to use backslash escaping. #104009 (Shaohua Wang). - Fixed possible type mismatch in aggregation when a column type was altered to/from LowCardinality, and min-max projection wasn’t rebuilt. #104013 (Nikita Taranov).
- Fix infinite loop of query optimizations caused by not propagating prevention of unused column removal when merging expressions. #104083 (János Benjamin Antal).
- Fix
LOGICAL_ERRORinStreamingStorageRegistry::renameTablewhen batch-renaming streaming tables (S3Queue, Kafka, RabbitMQ) by using UUID-based identity tracking instead of name-based. #104101 (Nikita Taranov). - Fixed wrong results when a CTE constructed with
UNION ALLcontained aSELECT DISTINCTbranch and the outer query projected only a subset of the CTE’s columns. The new analyzer’sRemoveUnusedProjectionColumnsPasswas incorrectly removing the un-referenced column from the innerDISTINCTprojection, causing rows that should have remained distinct (same value in the projected column but different value in the dropped column) to collapse into one. #104114 (Groene AI). - Fix several edge case correctness issues in setting
optimize_inverse_dictionary_lookupwhere the optimization could silently drop rows or suppress exceptions. Closes #103270. Close #103085. #104133 (Nihal Z. Miaji). - Fix write out of bounds while deserializing
quantileTimingstate. #104141 (Alexey Milovidov). - Fix undefined behavior when an out-of-range
Float64value is converted to a wide integer type (UInt64,Int64,Int128,UInt128,Int256,UInt256). Previously, values equal toFloat64(numeric_limits<T>::max())(which rounds up to a value above the actual maximum) bypassed the bounds check and produced UB in the subsequent cast. This affected aggregate-function parameter parsing (topK,histogram,uniqUpTo,groupArrayInsertAt, etc.) and integer-typed settings viaSET <setting> = <Float64>. Closes #103817. #104154 (Groene AI). - Fix
LOGICAL_ERRORexception “Unexpected return type from comparison. ExpectedUInt8. GotConst(Nullable(UInt8))” when comparing a nestedTuple(Tuple(Nullable(...)))(or deeper nesting) with aStringliteral. The comparison’s return type is now correctly inferred asNullable(UInt8), matching the runtime behaviour. #104171 (Groene AI). - Fixed a server abort (
UndefinedBehaviorSanitizer: reference binding to null pointer, segfault in release builds) onSELECT ... FROM <ReplacingMergeTree(version, is_deleted)> FINAL PREWHERE is_deleted = <expr> AND <other column expr>whenquery_plan_optimize_lazy_final = 1. The lazy-FINAL non-intersecting reading step lost theis_deletedcolumn from its output header because prewhere consumed it as an input without re-exposing it as an output. The downstreamaddIsDeletedFilterstep then dereferenced a nullActionsDAG::Nodepointer. #104177 (Groene AI). - When calling system.failpoints table, it would use a failpoint, thus possibly disabling it. #104237 (Pedro Ferreira).
- Fix
MemorySanitizer: use-of-uninitialized-valueindetectLanguage*functions when the input contains a UTF-8 character ending exactly at the buffer boundary. #104257 (Raúl Marín). - Fix a logical error (
Bad cast from type DB::CachedObjectStorage to DB::S3ObjectStorage) that aborted argument parsing of data-lake table functions and engines (icebergS3,deltaLakeS3, etc.) when called withSETTINGS disk = '...'against a disk whose underlying object storage is wrapped by a decorator such as a filesystem cache. Closes #89300. #104258 (Groene AI). - Fix parsing of parenthesized subscript expressions on columns named
values, for example(values['a']), so they are no longer interpreted as SQL-standardVALUEStable expressions. #104312 (Desel72). - Fix a server abort/
LOGICAL_ERRORin the filesystem cache background eviction thread (SLRUFileCachePriority::collectEvictionInfo) that could fire whenkeep_free_space_size_ratioorkeep_free_space_elements_ratiowas high enough to trigger eviction while all cache entries had already been promoted to the SLRU protected queue (probationary empty). #104313 (Groene AI). - Fix exceptions (
NOT_FOUND_COLUMN_IN_BLOCK,LOGICAL_ERROR,AMBIGUOUS_COLUMN_NAME) when using projections with UNION ALL views, window functions, or alias-column name collisions. Regression from #88798. #104317 (Amos Bird). - Fixes a possible underflow in parsing postgres arrays. #104322 (Grant Holly).
- Functions that return a non-
Nullabletype (such asArray,Tuple, orMap) now acceptNullablearguments. Affected functions includeextractAll,extractAllGroups,extractAllGroupsHorizontal,extractAllGroupsVertical,extractGroups,splitByChar,splitByString,splitByRegexp,splitByWhitespace,splitByNonAlpha, andalphaTokens.NULLinput rows produce the default value of the result type (e.g. an empty array) instead of raising “Nested type is not allowed inside Nullable type”. #104326 (Alexey Milovidov). - Fix iceberg stats with partitioned table. This closes #104321. #104329 (Konstantin Vedernikov).
- Fix a fatal logical error at server startup on macOS (and similar jemalloc builds) where
Jemalloc::verifySetupincorrectly reported ajemalloc_enable_background_threadsmismatch because optionalbackground_thread/max_background_threadsmallctls are absent; verification is skipped when those mallctls are unavailable, andgetValueno longer leaves the output uninitialized on failure. Closes #102183. #104330 (SAYON DEEP). - Fix a correctness regression where
SELECTqueries withmax_rows_to_read_leafandread_overflow_mode_leaf = 'throw'could incorrectly throwTOO_MANY_ROWSeven when a skip index would have reduced the read below the leaf cap. The symmetric non-leaf settings (max_rows_to_read/read_overflow_mode) were already handled. #104331 (Groene AI). toUUID,toUUIDOrNull,toUUIDOrZero,toUUIDOrDefault,CASTtoUUIDandNullable(UUID),accurateCastOrNulltoUUID, and the input formats that parse a UUID from text (Avro,MsgPack,JSONExtract, …) now reject strings that have the right length but contain non-hexadecimal characters. Previously such inputs were silently turned into a fabricated UUID by walking off the end of the hex digit lookup table; nowtoUUIDthrowsCANNOT_PARSE_UUID, and theOr*variants returnNULL/ the zero UUID / the supplied default. #104370 (Groene AI).- Fix
Bad castLOGICAL_ERRORincaseWithExpression(and SQLCASE expr WHEN ... THEN ... ELSE ...) when the THEN-only supertype and the (THENs + ELSE) supertype land in differentColumnDecimalstorages — for example THEN values(UInt16, Int8)with an ELSE ofDecimal(9, 2). Closes #104335. #104378 (Groene AI). - Internal failures reported via
logExceptionBeforeStart(asynchronous insert flushes, materialized-view refreshes, parse errors raised during internal queries) now correctly increment theFailedInternalQuery,FailedInternalSelectQuery, andFailedInternalInsertQueryProfileEvents alongside the user-visibleFailedQuery,FailedSelectQuery, andFailedInsertQuerycounters. Previously these internal counters stayed at zero for failures occurring before query execution started, undercounting a major class of internal failures. #104399 (Groene AI). - Fix
Code: 36. BAD_ARGUMENTS Expected literal, got {name:Type}thrown when a query parameter is used inside thebase_backupsetting of aBACKUPorRESTOREstatement (e.g.BACKUP ... SETTINGS base_backup = S3({backup_name:String}, ...)). The regression was introduced in26.1.5by PR #99205. Closes #103324. #104413 (Groene AI). - Fix a server abort in
IcebergLocal/IcebergS3writes whenALTER TABLE ... DROP COLUMNis followed by anINSERTwithiceberg_metadata_staleness_msgreater than zero.ALTERnow invalidates the local Iceberg metadata files cache so subsequent reads and writes see the new schema. #104419 (Groene AI). - Fix
DROP ROLE,DROP USER,DROP SETTINGS PROFILE,DROP ROW POLICY,DROP QUOTAandDROP MASKING POLICYto remove references to the dropped entity from any other access entity that referenced it (e.g. a user’sDEFAULT ROLElist, a settings profile’sTOlist, a row policy’s grantees) and persist the cleanup to disk. Previously the in-memory state appeared correct becauseSHOW CREATEfilters unknown UUIDs, but the on-disk.sqlfiles retained danglingID('<dropped-uuid>')entries and the references were resurrected on the next server restart, surfacing asACCESS_ENTITY_NOT_FOUNDerrors during distributed query execution. #104427 (Groene AI). - Fixed a server abort triggered by
azureBlobStorage,AzureBlobStorage-engine, and DeltaLake-on-Azure with a connection string whoseBlobEndpointURL has an empty, non-numeric, or out-of-range port (e.g.BlobEndpoint=http://host:abc/). The server now returns a cleanBAD_ARGUMENTSerror instead of aborting in debug/sanitizer builds. #104460 (Groene AI). - Allow an unquoted identifier as the user name in the
remoteandremoteSecuretable functions, mirroring how the database and table arguments accept unquoted identifiers. Previously such a query failed with a misleading authentication error referring to thedefaultuser. #104465 (Alexey Milovidov). - Fixed
Logical error: Incorrect ASTSelectWithUnionQuery (modes: M, selects: N)triggered when a SQL user-defined function body contains a parenthesized innerUNION ALL(e.g.CREATE FUNCTION f AS x -> (SELECT 1 UNION ALL (SELECT 1 UNION ALL SELECT 1))). #104477 (Groene AI). - Fix
uniqThetaIntersectreturning the cardinality of the first argument instead of0when the second argument is an emptyuniqThetastate — for example the result ofuniqThetaMergeStateIf(s, predicate)when the predicate excludes every row. #104529 (Groene AI). - Fix
SHOW TABLESandsystem.tablessilently truncating the listing forDataLakeCatalogdatabases backed by Iceberg REST catalogs (iceberg-rest,onelake,biglake). When the catalog server paginates the list-tables or list-namespaces response (e.g. Microsoft Fabric / OneLake beyond ~50 tables per namespace), tables on later pages were silently invisible toSHOW TABLESandsystem.tables, even though they were queryable via directSELECT.RestCatalognow follows thenext-page-tokencontinuation token defined by the Iceberg REST OpenAPI spec, matching the existing behavior ofPaimonRestCatalogandUnityCatalog. #104531 (Groene AI). - The
inputtable function now infers its structure from the surroundingINSERTquery’sFORMATclause when that format has a fixed schema (LineAsString,RawBLOB,JSONAsString, etc.), so users no longer have to repeat the structure asinput('line String')for these formats. #104532. #104533 (Groene AI). - Updated datatype of fields in Iceberg history from
Int32toInt64. Closes #94176. #104579 (Smita Kulkarni). - Fixed
Inconsistent AST formattingLOGICAL_ERRORwhen parsing a function call where a lambda follows a comma, e.g.SELECT substring(x, `x` -> `x`). The parser used to silently merge the preceding arguments into the lambda’s left-hand side, producing a single-argument call that could not be re-parsed back to the same AST. It now preserves the function’s original arity. #104626 (Groene AI). CHECK TABLE tnow prefers aTEMPORARYtable over a permanent one with the same name when no database qualifier is given, matching the precedence already used bySHOW CREATE TABLE,DESCRIBE TABLE,OPTIMIZE TABLE, andALTER TABLE. PreviouslyCHECK TABLE tskipped temporary tables entirely, so it failed withUNKNOWN_TABLEon a temporaryLogorFiletable even though those engines supportCHECK. Follow-up to #100966. #104637 (Groene AI).- Fix Keeper termination and restart loop when
get /keeper/availability_zoneis sent withquorum_reads=trueto a Keeper without<placement>configured. #104663 (myeongjun). - Fix a TOCTOU data race in
FutureSetFromTuple::buildOrderedSetInplacethat results in a logical error. #104673 (Miсhael Stetsyuk). - Fix several functions returning different results for the same input depending on whether arguments arrived as columns or constants:
bitRotateLeft/bitRotateRight(boundary shift counts),length(FixedString)/concatWithSeparatorwithLowCardinality(Nullable)inputs,roundDownon NaN, andrightUTF8on invalid UTF-8. #104710 (Raúl Marín). - Fixed
anyHeavyreturning a non-heavy value when the most frequent value was the column default and the data lived across multipleMergeTreeparts (sparse-column read path). #104712 (Raúl Marín). - Fix several defects in setting-constraint handling:
MergeTreeSettingsconstraints declared on a setting’s canonical name could be bypassed by writing to an alias of that setting; thedisallowed_valuesconstraint check threw an exception on clamp paths (secondary queries,ON CLUSTERworkers,SQL SECURITY DEFINERviews) instead of silently dropping the change. #104737 (Raúl Marín). - Fix a
LOGICAL_ERRORexception (Metadata is not initialized) raised byOPTIMIZE TABLE,ALTER TABLE ... DELETE,ALTER TABLE ... ADD COLUMNand other ALTER variants on a lazily-attachedIceberg/IcebergLocal/DeltaLake/Huditable whose metadata had not been loaded yet (typical after a server restart, or after a previous metadata write failed and left a corrupted metadata file on disk). The operation now either proceeds normally if the metadata loads successfully, or surfaces the underlying load failure as a regular user-facing exception instead of aborting the server in debug / sanitizer builds. #104738 (Groene AI). - Fix segfault due to a use-after-free bug in
AvroConfluentRowInputFormat. #104751 (Miсhael Stetsyuk). - Scalar variants of
numericIndexedVectorPointwiseMultiply,numericIndexedVectorPointwiseDivide,numericIndexedVectorPointwiseEqual, andnumericIndexedVectorPointwiseNotEqualnow raiseINCORRECT_DATAwhen called with aUInt64scalar aboveInt64::max. #104784 (FriendLey). - Fix a bug where manually overriding a setting via its alias name (e.g.
SET enable_analyzer = 1instead ofSET allow_experimental_analyzer = 1) after applying acompatibilitysetting could cause that override to be reverted by a subsequent change of thecompatibilitysetting. #104829 (Raúl Marín). - Fix AWS logger being disabled after https://github.com/ClickHouse/ClickHouse/commit/0e8ad4355c9d. #104837 (Konstantin Bogdanov).
- Fix three more functions returning different results for the same input depending on whether arguments arrived as columns or constants:
transform(andcaseWithExpressionthrough it) with a constantDate/Date32/Enum/FixedStringdefault, comparison operators between aStringand a constantFixedString, andif/ifNull/nullIfwith aFixedStringbranch under a constant condition. #104858 (Raúl Marín). - Fix
Bad cast from type DB::ColumnConst to DB::ColumnNullableserver abort during partition pruning forMergeTreetables when the partition expression contains a function chain that collapses to a single constant value (such asfloor(NULL, toRelativeYearNum(...))). #104861 (Groene AI). - Fix a
ThreadSanitizerdata race in theContextDatacopy constructor:table_function_resultswas copied from the source object without acquiringtable_function_results_mutex, so a concurrentContext::executeTableFunctionwriter could race against the unsynchronized read in the copy constructor. #104879 (Groene AI). - Fix data part consistency checks for types with dynamic structure and detect corrupted columns_substreams.txt. Resubmit of https://github.com/ClickHouse/ClickHouse/pull/103858 with additional changes. #104888 (Pavel Kruglov).
- Fix race between DROP and UNDROP in DatabaseCatalog. #104915 (Azat Khuzhin).
- Fix filesystem cache dynamic resize with partially downloaded segments, including restore accounting after failed eviction. #104921 (Antonio Andelic).
DETACH TABLEon a temporary table (without theTEMPORARYkeyword) now correctly raisesSYNTAX_ERROR, matching the behavior ofDETACH TEMPORARY TABLE. Previously it silently set an internalis_detachedflag and returned without error. To remove a temporary table, useDROP TEMPORARY TABLEorDROP TABLE(the latter resolves the temporary table viaContext::ResolveExternal). Closes #103475. #104943 (Groene AI).- Make the
filesystemtable function honormax_memory_usage/max_server_memory_usagewhen loading file content. Previously, large or numerous parallel content reads could push past the limit without raisingMEMORY_LIMIT_EXCEEDEDand end up OOM-killed instead. #104956 (Alexey Milovidov). - Fixed a
LOGICAL_ERRORthrown when filteringsystem.detached_tablesbyuuid(e.g.SELECT count() FROM system.detached_tables WHERE uuid = '...'). The query now returns the expected result instead of aborting the server. #104979 (Groene AI). flattenTupleno longer raises aLOGICAL_ERRORwhen called on a tuple whose nested structure contains only emptyTuple()leaves (e.g.Tuple(c0 Array(Tuple()))orTuple(c0 Tuple())). Such inputs now produce a user-facingILLEGAL_TYPE_OF_ARGUMENTexception explaining that the flatten result would be an empty tuple. #104989 (Groene AI).- Fix a server abort and a silent-wrong-result bug when querying
loop(remote(...))(or anyloop()wrapping a storage that can defer aggregation) withGROUP BY. The outer planner used to addMergingAggregatedStepbased on the inner storage’s reported processing stage, butLoopSourcealways materialises its inner select withQueryProcessingStage::Completeand emits plain column chunks, soMergingAggregatedTransformtripped aLOGICAL_ERROR(Chunk info was not set for chunk in MergingAggregatedTransform) underenable_parallel_replicas = 1and silently dropped the outer aggregation otherwise. #105001 (Groene AI). clickhouse-benchmark --reconnect(bare, no value) was inadvertently broken in 25.4 by a change that turned--reconnectinto an integer option, requiring a value. The bare form now works again and is equivalent to--reconnect=1(reconnect on every query). #105006 (Groene AI).- Fixed malformed JSON output for column names ending with incomplete UTF-8 sequences. #105012 (Pablo Marcos).
- Fix silent data loss after
EXCHANGE TABLESorCREATE OR REPLACE TABLEof a materialized view’s source table. TheMV’s source-view dependency edge is now kept on the original name so it continues to fire on inserts. Regression introduced by #98779; restores the pre-regression behavior. #105029 (Sema Checherinda). - Fix
CANNOT_COMPILE_CODE Could not find symbol __fixunsdftiwhen JIT-compiling expressions that convert aFloattoUInt128, such astoUInt128(<Float64 expression>). The unsigned 128-bit float-to-int compiler-rt builtins were missing from the JIT symbol resolver. Closes #105031. #105048 (Raúl Marín). - Fix
clickhouse-localnot printing log messages from a failed query whensend_logs_levelis set. #105067 (Alexey Milovidov). - Fix incorrect results when the same parameterized view is referenced more than once in the same query with different argument values. Previously, the analyzer collapsed the calls into one, silently dropping all but the first filter. #105170 (Alexey Milovidov).
- Fix
TOTALSrow being rendered twice at the bottom of the result table in theplay.htmlweb UI. #103803 (Alexey Milovidov). - Reject non-finite vectors (
NaN,±Inf) during vector search (either as searched vectors or as reference vectors); they previously caused undefined behavior inusearch. #104079 (Groene AI). - PromQL: fix the aggregation operator for empty vectors. #104425 (Vitaly Baranov).
- PromQL: fix error handling in the Prometheus query API. #104741 (Vitaly Baranov).
- Fix a race in
MergeTreeTransaction::afterCommitwhere, after a connection loss between writing the commitCSNto ZooKeeper and finalizing the transaction, theCOMMITresponse could reach the client before the newcreation_csn/removal_csnbecame visible insystem.parts. #104708 (Tuan Pham Anh). - Fix exponential memory growth in the KQL parser when converting nested array indexing (
arr[arr[arr[...]]]). #105142 (Alexey Milovidov). - Fix incorrect results for
RIGHT ANY JOINwhen the right table has multiple rows per key and the output block is split due to size limits. Closes #99431. #102064 (Vladimir Cherkasov). - Check for stack overflow in
Avroreader during nested-type deserialization. #102417 (Pavel Kruglov). - Fix duplicate rows in
system.completionsforMergeTreesettings — each setting name appeared twice because bothgetMergeTreeSettingsandgetReplicatedMergeTreeSettingswere dumped despite having identical setting names. Closes #102013. #102015 (Groene AI). - Fix
StorageObjectStorageQueue(S3Queue,AzureQueue) blocking shutdown until partially-processed files were fully read from object storage. The source now aborts the read immediately on shutdown; deduplication ensures rows already streamed into the destination table before shutdown are not duplicated when the file is retried on next start. #103126 (Tuan Pham Anh). - Fix multi-block inserts to the
Aliastable engine withinsert_deduplication_tokenso that all blocks are kept. #103246 (Enric Calabuig). - Fix
JSONHasandJSONExtractBoolon nativeJSONcolumns returning the extracted value (cast toUInt8) instead of0/1. #103313 (zxuhan7). - Protect the
CustomSeparatedinput format against malformed or adversarial data that omitsformat_custom_row_after_delimiter. Header detection, schema inference, and variable-column rows previously accumulated fields unboundedly and could allocate many gigabytes of memory before failing. Reads now fail withINCORRECT_DATAonce a single row contains more than 1,000,000 fields. #103404 (Groene AI). - Fix
RESTOREof replicatedMergeTreetables so that restored part attachment usesbackup_restore_keeper_max_retriesinstead of the regular insert Keeper retry budget. #104610 (Pablo Marcos). - Fix wrong results from
WHERE p AND <LowCardinality(Nullable(int)) constant>onMergeTreetables. Previously such queries returned zero rows because part pruning derived aNULLdefault from theLowCardinality(Nullable(...))type and synthesized anotEquals(x, NULL)guard, pruning every part. #104767 (Groene AI). - Fix incorrect aggregation result when grouping by a non-injective function of a column that is also the partition key (e.g.
PARTITION BY awithGROUP BY intDiv(a, 2)ora % 2). Values from different partitions that mapped to the same group were not merged, producing duplicate group rows underallow_aggregate_partitions_independently = 1. #104869 (Nihal Z. Miaji). - Fix a race in
Keepersnapshot transfer where a snapshot could be removed or moved while it was being sent to a recovering follower. #104941 (Antonio Andelic). - Fix a silent wrong-result bug in
hilbertEncodeandmortonEncodewhere a non-constantTuplefirst argument (range mask) used row 0’s values to drive the bit-shift for every row. The functions now compute the per-row mask values, so the result no longer depends on the input being constant or on the block size. #104992 (Groene AI). - Fix
clickhouse-localsilently ignoring user-level configuration (profiles,users,quotas, access-control settings) when the configuration file is auto-discovered from./clickhouse-local.xml,~/.clickhouse-local/config.xml, or/etc/clickhouse-local/config.xml. Previously these settings were applied only when--config-filewas passed or./config.xmlexisted in the current directory; now all discovery paths behave consistently. #105008 (Groene AI). - Fix
BFloat16columns silently returning zero matches when compared against a string literal (e.g.WHERE bf16_col = '49.9'). #105042 (Raúl Marín). - Fix
CLEAR COLUMNand TTL handling during merges forSummingMergeTree,AggregatingMergeTree, andCoalescingMergeTreewhen merge-required columns are absent or expired. Closes #101953. #105203 (Antonio Andelic). - Fix a race between
DNSCacheUpdater::runandContext::reloadClusterConfigby adding an explicit null-guard forshared->clusters_configbefore dereferencing it. #105220 (Mikhail f. Shiryaev). - Fix
best_effortdate-time parsing fortoDateTime64withmsandnsprecision. #105233 (Kaviraj Kanagaraj). - Fix
OSIOWaitMicrosecondsreporting thread-lifetime I/O wait instead of per-query I/O wait. #105246 (Mikhail f. Shiryaev). Huditable engine now raisesINCORRECT_DATA(a regular query-level exception) instead ofLOGICAL_ERRORwhen a parquet file in the table directory does not match the Hudi[FileId]_[FileWriteToken]_[Timestamp].[extension]naming convention. Previously such file names caused an exception in debug builds. #105266 (Groene AI).- Fix deadlock in
ParallelFormattingOutputFormaton schedule failure: whenscheduleFormatterThreadForUnitWithNumberthrows (e.g.CANNOT_SCHEDULE_TASK), the unit was left inREADY_TO_FORMATwith no formatter thread to process it, leading to a hang. The schedule call is now wrapped intry/catchand any failure is routed throughonBackgroundExceptionso the collector exits cleanly. #105275 (Azat Khuzhin). - Fix silent data loss in
Distributedasync inserts when recovering from an abnormal shutdown: if the last.binfile in a saved batch was intact but a middle one was corrupted,DistributedAsyncInsertBatch::recoverBatchwould only validate the last file’s header and thensendBatchwould mark the entire batch — including the intact files — as broken, losing their rows. Each file’s header is now validated individually so only the actually broken file is moved tobroken/and the surviving rows reach the remote shard. #105281 (Groene AI). - Fix a regression in
clickhouse extract-from-config --try: when the config usedfrom_envattributes and had noinclude_fromelement (or had one pointing to a missing file), allfrom_envsubstitutions were silently dropped and returned empty strings. This broke the Docker entrypoint port discovery in 26.2.5. Closes #101704. #105283 (Groene AI). - Fix
INSERT INTOaSQLitetable failing with a SQLite syntax error when the inserted value is anEnum,JSON, orAggregateFunctionwhose text representation contains a single quote. Theoutput_format_values_escape_quote_with_quotesetting is now honored by the corresponding serializations (previously onlyStringandFixedStringhonored it). #105285 (Groene AI). - Fix
Code: 44. ILLEGAL_COLUMN: Cannot add column ...: column with this name already existsthrown by distributed queries withallow_push_predicate_ast_for_distributed_subqueries = 1(the default) when aGLOBAL INtuple is matched against a subquery whose projection contains duplicate column names, e.g.(x, y) GLOBAL IN (SELECT number, number FROM numbers(5)). #105290 (Groene AI). - Fix
reinterprettoArray(LowCardinality(...))returning a confusingNOT_IMPLEMENTEDerror at runtime; it now returnsILLEGAL_TYPE_OF_ARGUMENTduring type checking. #105301 (Raúl Marín). minMap/maxMap(array form) andminMappedArrays/maxMappedArraysnow treatNaNconsistently withORDER BY:NaNis treated as last (returned only when all values areNaN). Previously, results depended on the position ofNaNin the data due to IEEE 754 unordered comparison semantics, and disagreed with theMap-argument form ofminMap/maxMapthat was fixed in #100448. #105331 (Raúl Marín).- Fix a memory leak in the per-table
ColumnsDescriptioncache forMergeTree-family tables withNestedcolumns. Entries were never evicted acrossALTER ADD COLUMN/DROP COLUMNcycles whenshare_nested_offsets = 1(the default). #105376 (Groene AI). - Fix
BAD_ARGUMENTSexception “It’s a bug! Only integer types are supported by__bitWrapperFunc” thrown when aSELECTwith aTYPE set(N)skip index has aWHEREatom whose result type isFloat,BFloat16, or any other non-integer type (for exampleWHERE c0 + 0.1orWHERE log(c0)). The skip index now falls back to the regular filter path in that case. #105384 (Groene AI).
Build/Testing/Packaging Improvement
- Stop using the system
compiler-rtlibraries and headers. Closes #91475. #102857 (Konstantin Bogdanov). - Refresh the distroless Docker base image to fix OpenSSL CVEs in
libssl3t64. #103583 (Rahul Nair). - Reliably receive the GPG key during releases by chaining multiple Ubuntu keyservers, instead of timing out on
keyserver.ubuntu.com. #103834 (Mikhail f. Shiryaev). - Remove and forbid build-time
CMakechecks (check_*,try_compile,try_run). The compiler and toolchain are fixed, so feature detection at configure time is unnecessary and is now blocked project-wide; any version-specific behaviour must be gated onCMAKE_CXX_COMPILER_VERSIONexplicitly. #103980 (Alexey Milovidov). - Bump
libarchivefrom 3.8.6 to 3.8.7. #104047 (Robert Schulze). - Update
mongo-c-driverto 2.3.0. #104300 (Raúl Marín). - Update LLVM dependencies for 22.x. #104381 (Joshua Carp).
- Make the embedded-client and PTY descriptor classes build on macOS and FreeBSD by using portable POSIX
posix_openpt/grantpt/unlockptand removing Linux-only#ifguards. #104436 (Alexey Milovidov). - Upgrade
librdkafkato version 2.14.1. #105222 (János Benjamin Antal).
ClickHouse release 26.4, 2026-04-30. Presentation, Video
Backward Incompatible Change
- The
INoperator now uses exact value semantics forBooltype: only0and1values in the set matchBoolvalues. Previously, numeric values greater than255in theINset were incorrectly clamped to true when compared againstBool, soSELECT CAST(1, 'Bool') IN (256)returned 1. Now it correctly returns0. Closes #92980. #93115 (Ashrith Bandla). - The H3 library has been updated to v4, which improves the precision of length, area, and other metric calculations. This change is backward incompatible because the new results differ from previous ones. #100348 (Alexey Milovidov).
- Disallows using
SELECTas a bareword identifier in aWITHexpression list element. #101059 (Aruj Bansal). - This patch changes how the merge table will handle virtuals. If the underlying table contains
_tableor_database, these columns will be read from storage; otherwise, they will be filled after the read step using the expression step. #101742 (Mikhail Artemenko). - The
INoperator now rejects lossyDecimalconversions inside composite types (Tuple,Array,Map) as well, making its behavior consistent with top-level scalar comparisons. Previously, precision checks were enforced only for top-level scalar values: for example,CAST('33.3', 'Decimal64(1)') IN (33.33)correctly returned0, butCAST(['33.3'], 'Array(Decimal64(1))') IN ([33.33])incorrectly returned1because the lossy conversion happened inside anArray. Now both cases correctly return0. #101812 (Nihal Z. Miaji). - Reduced default
http_max_fieldsfrom 1,000,000 to 1,000 andhttp_max_field_name_sizefrom 128 KB to 4 KB to limit pre-authentication memory usage by HTTP connections. Addedhttp_max_request_header_sizeandhttp_headers_read_timeoutsettings. Users who rely on the previous higher limits can restore them via settings. #103285 (Sema Checherinda).
New Feature
- Add automatic spilling to hash and parallel hash joins by converting them to grace hash join when memory limit is reached. This behavior is controlled by
max_bytes_before_external_join. #97813 (János Benjamin Antal). - Add Arrow Flight SQL support. #91170 (Yakov Olkhovskiy).
- Add incremental read support for
Paimontable engines with Keeper-backed snapshot progress tracking, including targeted snapshot delta reads viapaimon_target_snapshot_id, and extend test coverage for type mapping, partition pruning, and incremental read scenarios. #93655 (XiaoBinMu). - The
stemfunction is now non-experimental (previously, settingallow_experimental_nlp_functionshad to be enabled). #102399 (Jimmy Aguilar Mena). You can now stem all the words/tokens in columnsString,FixedString,Array([Fixed]String),Nullable,LowCardinalityandConsteasily with thestemfunction. #99137 (Jimmy Aguilar Mena). - Implement new behavior of
max_insert_block_size_rows,max_insert_block_size_bytes,min_insert_block_size_rows,min_insert_block_size_bytesin squashing under compatibility settinguse_strict_insert_block_limits. #94207 (Kirill Kopnev). - Add function
arrayAutocorrelation(arr [, max_lag])that computes the normalized autocorrelation of a numeric array for each lag. Supports integer, float, and decimal array types. #94776 (Wenyu Chen). - A SQL function
obfuscateQuery. Closes #98010. #98305 (Xuewei Wang). - Add support for Map and JSON/Object types as dictionary attributes. Now dictionaries can store and retrieve complex types including Map(String, String), Map(String, Array(String)), JSON, and Nullable(JSON) types in both FLAT and HASHED layouts. #98627 (yanglongwei).
- Added two new MergeTree settings —
replicated_fetches_min_part_levelandreplicated_fetches_min_part_level_timeout_seconds— that allow replicas to skip fetching freshly-inserted (unmerged) parts from peers, reducing replication overhead during heavy ingestion. #98625 (tanner-bruce). - Add MergeTree skip index support for JSON columns using JSONAllPaths with bloom_filter, tokenbf_v1, ngrambf_v1, and text (inverted) index types, enabling granule skipping based on the set of JSON paths present in each granule. #98886 (Pavel Kruglov).
- The
printffunction now supports non-constant format strings, allowing different format patterns per row based on column values. #98991 (Yash ). - Add a new projection index,
commit_order, that reorganizes data in insertion order. #99004 (Mikhail Artemenko). - Add
highlightfunction that wraps occurrences of search terms in a text string with HTML tags (default<em>/</em>). Supports ASCII case-insensitive matching, automatic merging of overlapping matches, and custom open/close tags. #99131 (Peng). - Implement quotas by normalized query hash to protect public ClickHouse services from abuse. 1. Support
NORMALIZED_QUERY_HASHas a quota key type - separate quota buckets per unique normalized query, soCREATE QUOTA q KEYED BY normalized_query_hashtracks each distinct query independently. 2. SupportQUERIES_PER_NORMALIZED_HASHas a quota resource type — limits max executions of any single normalized query within an interval, soMAX queries_per_normalized_hash = 100prevents any one query pattern from running more than 100 times. #99586 (Alexey Milovidov). - Users can now write join queries using the
NATURAL JOINsyntax, which automatically matches on all columns sharing the same name and deduplicates those columns in the result. #99840 (Peter Nguyen). - Support
SET TIME ZONE 'tz'as alias forSET session_timezone. #99883 (phulv94). - Added support for parameterized queries in the Web UI (
play.html): query parameters like{name:Type}are detected and input fields are shown for filling in their values. #100041 (Alexey Milovidov). - Support SQL standard
VALUESclause as a table expression inFROM, e.g.SELECT * FROM (VALUES (1, 'a'), (2, 'b')) AS t(id, val). #100143 (Desel72). - Add PostgreSQL-compatible units to the
EXTRACToperator:EPOCH,DOW,DOY,ISODOW,ISOYEAR,WEEK,CENTURY,DECADE,MILLENNIUM. Also fixEXTRACT(WEEK FROM date)which previously threw an error. #100274 (Alexey Milovidov). - Added support for SQL-standard compound interval literals with
TOrange qualifiers, e.g.INTERVAL '1:30' HOUR TO MINUTE. Internally decomposed into sums of intervals. #100453 (Desel72). - Add asynchronous metrics for kernel TCP receive and transmit buffer memory (
sk_rmem_alloc,sk_wmem_alloc) of HTTP connection pool sockets, reported as p50/p75/p90/p95 percentiles and totals per connection group. #100575 (Sema Checherinda). - Added a jemalloc profiling web UI for ClickHouse Keeper, available at
/jemallocon the HTTP control port. #100606 (murphy-4o). - Implement command
SYSTEM FLUSH OBJECT STORAGE QUEUE db.table PATH 'x'for ordered and unordered modes. #100709 (Bharat Nallan). - Added function
JSONAllValuesthat returns all values from aJSONcolumn asArray(String), with values serialized in text representation and ordered by their path names. Added support of text index forJSONAllValuesexpression onJSONcolumns. When a text index is created onJSONAllValues(json_column), it is automatically used to filter queries onJSONsubcolumns (e.g.,json_column.key1 = 'value'). #100730 (Anton Popov). - Adds a new setting
input_format_column_name_matching_modewhich allows different case sensitivities for input formats. #99346 (manerone). - Add
watchcommand toclickhouse-keeper-clientwith watch support inget,exists, andlscommands. #100834 (Den Kalantaevskii). - Added
getChildrenRecursive(ListRecursive) request to ClickHouse Keeper andlsrcommand toclickhouse-keeper-client. This closes #99916. #100998 (Konstantin Vedernikov). - Add new function
arrayTransposetaking a two-dimensional array (matrix) and transposing it:SELECT arrayTranspose([[1, 2, 3], [4, 5, 6]]). #101214 (Vitaly Baranov). auto_statistics_types mergetreesetting defaults to'minmax, uniq'— minmax and uniq statistics are created automatically for all suitable columns in new tables -materialize_statistics_on_insertdefaults to false — statistics are now built during merges rather than at insert time, reducing insert overhead. useSET materialize_statistics_on_insert = 1to restore the old behavior. #101275 (Han Fei).- Add
prefer_dependency_replicarefresh setting for materialized view dependency chains to reduce missing data from cross-replica replication lag. #101591 (Seva Potapov). - Adds a
hasPhrase(aliasmatchPhrase) function for phrase search (continuous sequences of tokens). Search is brute-force, i.e. not supported by the text index yet. #101997 (Elmi Ahmadov). - Add
s3_read_request_duration_microsecondsands3_read_request_byteshistogram metrics to observe S3 GET request connection lifetime and bytes consumed, visible insystem.histogram_metricsand the Prometheus endpoint. #102058 (Sema Checherinda). DateandDate32values can now be added toTimeandTime64values using the+operator, producing aDateTimeorDateTime64result. For example,SELECT toDate('2024-01-15') + toTime('14:30:25')returns2024-01-15 14:30:25. The result is computed in the session timezone, and out-of-range results are handled according to thedate_time_overflow_behaviorsetting. Closes #95914. #102421 (Nihal Z. Miaji).- The text index is now GA and stays enabled regardless of the
compatibilitysetting, preventing unexpected disabling during backup restores or when running in compatibility mode. #101518 (Nikita Fomichev).
Experimental Feature
- Add
ALTER TABLE ... EXECUTE remove_orphan_filesfor Iceberg tables to identify and remove unreferenced files from object storage. #99127 (murphy-4o). - Add
query_plan_optimize_join_order_randomizesetting that randomizes statistics used for join reordering, useful for testing. #100643 (Vladimir Cherkasov). - Add AI function support to ClickHouse, allowing users to call OpenAI and Anthropic endpoints using SQL.
aiGenerateis included as the first such function. #100831 (George Larionov). - Add AI functions:
aiClassify,aiExtract, andaiTranslatefor utilizing LLM APIs in ClickHouse. #100832 (George Larionov). - Added
system.histogram_metric_log, a new system table that periodically snapshots all histogram metrics (e.g. S3/Azure latencies, keeper request processing stages durations). Also, thevaluecolumn ofsystem.histogram_metricschanges toFloat64as it’s more flexible and compatible with the Prometheus data model. #103046 (Miсhael Stetsyuk). The table structure is likely to be changed in future releases.
Performance Improvement
- ClickHouse is now able to prune entire data parts in SELECT queries based on min/max statistics. #94140 (zoomxi).
- Reduce lock contention during readonly operations on ReplicatedMergeTree tables with finished mutations. #95771 (Eduard Karacharov).
- Respect
optimize_read_in_orderwhen reading projections. Closes #89453. #95885 (Andrey Zvonov). - Small set of improvements in Hash Join and Concurrent Hash Join. #96663 (Yarik Briukhovetskyi).
- Optimize
DISTINCTtransform by disablingLowCardinalitycolumns optimization when input data is almost distinct. #97113 (Nihal Z. Miaji). - Performance optimization for
LIKEqueries from #97723. Now these queries can use text indices. #98149 (Elmi Ahmadov). - Vectorized math functions (
exp,log,sigmoid,tanh) are now accelerated on AArch64 (using NEON/SVE) and on FreeBSD/Darwin, where they previously used a slower scalar fallback. #98230 (Raúl Marín). - Queries filtering on
MergeTreeprimary key columns with regexp alternations over literal strings, such as^(abc-1|abc-2), can now use primary key pruning when the alternatives share a common prefix. #98988 (Yash ). - Generalize
ORDER BY ... LIMITtop-k dynamic filtering to supportNullable,String, andCOLLATEtypes. #99033 (murphy-4o). - Speedup hash join on
Int32andInt64keys with small range by using a direct-index hash table. #99275 (Hechem Selmi). - Faster discontinuous queries for
LowCardinalitycolumns with a single dictionary. #99285 (Ivan Babrou). - Speed up
var*Stableandstddev*Stablefunctions forFloat64columns by devirtualizing the inner loop. Note: this enables compiler optimizations (FMA/registers) that alter floating-point results at the ULP level. #99460 (Riyane El Qoqui). - Use optimised Firedancer base58 encode for inputs of 32/64 bytes (automatic for
base58Encode). Allow using optimised base58 decode if decoded result is 32/64 bytes (explicit withbase58Decode('...', 32)or alike). #99461 (Joanna Hulboj). - Enable linker section-based optimizations (
-ffunction-sections,-fdata-sections,--icf=all) to reduce binary size and improve instruction cache utilization. #99474 (Alexey Milovidov). - Fix negative scaling for short queries with aggregation on machines with many cores. When a query reads few marks, the pipeline no longer expands to
max_threadsafter aggregation, avoiding overhead from mostly-empty streams. #99493 (Alexey Milovidov). - Improve the performance of queries with parallel replicas by correctly selecting the reading task size. #99801 (Nikita Taranov).
- Allow prefetching when reading a remote file through the userspace page cache. #99919 (Alexey Milovidov).
- Avoid unnecessary computation of String
.sizesubcolumn during subcolumns enumeration. #99941 (Pavel Kruglov). - Make clickhouse-client’s progress bar less jittery when working from a hotel with clusters with a very large number of replicas. #100145 (Alexey Milovidov).
- Start
MemoryWorkerinclickhouse-localwhen page cache is enabled, so that the userspace page cache can be actually used. #100306 (Alexey Milovidov). - Optimize queries by pushing the
LIMITclause down into theUNION ALL. #100364 (Alexey Milovidov). - Add JIT compilation support for
StringandFixedStringcolumn comparisons inORDER BY, improving merge-phase sort performance by 6–17% for string-heavy sort keys. Co-authored with @lgbo-ustc. #100577 (Raúl Marín). - When
read_in_order_use_virtual_rowis enabled together with the newread_in_order_use_virtual_row_per_blocksetting, virtual row boundary information is now emitted after each block read fromMergeTree, allowing the merge to reprioritize sources mid-stream for parts whose data is fully filtered out byWHERE/PREWHERE/JOIN. Close #99945. #100603 (Vladimir Cherkasov). - Faster Float-to-String conversion for large integer values by extending the
itoafast path with dragonbox-compatible rounding. #100649 (Raúl Marín). - Replace
dragonboxwithzmijfor 1.5x-3x faster Float-to-String conversion. #100650 (Raúl Marín). - Faster
Int128/UInt128to string conversion by replacing software division with Barrett reduction and unrolling the conversion loop. #100671 (Raúl Marín). - Avoid spawning redundant threads in
uniqExactparallel merge. #100686 (Jiebin Sun). - Add batch parallel merge for
uniqExact. #100687 (Jiebin Sun). - Better parallelization of queries with simple views (with underlying
MergeTreetable) executed with parallel replicas. #100815 (Igor Nikonov). - Implements support of parallel replicas over simple views (including eligible
UNION ALLviews overMergeTreetables) whenparallel_replicas_allow_view_over_mergetree=1. This allows to parallelize view’s outer query instead of inner one which increases query parallelization across nodes. #100958 (Igor Nikonov). - Optimise reading in order of the primary key for
full_sorting_mergewhen filters withINare present in the query plan. #101261 (Nikita Taranov). - Optimization allocations/deallocations by caching sampling settings instead of traverse all memory tracker hierarchy. #101267 (Azat Khuzhin).
- Fix significant INSERT performance regression when
deduplicate_insert = 'enable'(default since 26.2) by deferring data hash computation from squashing to the sink and using batch column hashing viaupdateHashWithValueRange, reducing overhead from ~2.5s to ~0.5s for 5M rows with 22 columns. #101494 (Sema Checherinda). - Reduce profiled lock overhead by using
try_lockto avoid timing uncontended acquisitions and removing hold-time measurement. #101502 (Antonio Andelic). - Replace hand-written AVX-512 intrinsics in
arrayDotProductwith platform-independent auto-vectorizable loops, adding AVX2 and ARM NEON support. #101571 (Peng). - Improve performance in
INSERT VALUESforMap,Array, andTuplecolumns when values are passed as escaped strings (e.g.'{\'key\':1}'), avoiding unnecessary fallback to the SQL expression parser. #102119 (Joanna Hulboj). - Fixed excessive
RabbitMQtable engine CPU usage. #102711 (Jaap Elst). - The JOIN order optimizer now infers transitive equi-join predicates from existing join conditions. For example, given
A.x = B.x AND B.x = C.x, the equivalenceA.x = C.xis recognized, allowing the optimizer to consider direct joins between transitively-connected tables. This can improve plan quality for star and snowflake schemas where dimension tables connect through a shared fact table. The feature is controlled by the newenable_join_transitive_predicatessetting (off by default). #98479 (Alexander Gololobov). - Optimize
TRUNCATE DATABASE TABLES LIKEby pre-cancelling merges in parallel. #98597 (Shaohua Wang). - Add monotonicity support for multiply, enabling primary key pruning for
key * constantexpressions. #98983 (Amos Bird). - Cache dictionaries no longer take an exclusive lock in
hasKeys; this reduces lock contention by using a shared lock for cache reads. #100796 (liuguangliang). - Inline VIEW subquery in the query tree to allow more optimisations to be applied to the VIEW. #100830 (Dmitry Novik).
- Optimize cache loading on server startup. #101500 (Kseniia Sumarokova).
- Implement lazy column materialization for ReplacingMergeTree with FINAL in case the predicate is selective enough. #101647 (Nikolai Kochetov).
- Re-enable the
optimize_rewrite_array_exists_to_hasoptimization (off by default since 23.10). It rewritesarrayExists(x -> x = elem, arr)into the much fasterhas(arr, elem)and now correctly skips the rewrite when the array element type andelemare not compatible forhas(e.g.DatevsString), so previously breaking queries continue to work. Closes #71431. #100944 (Alexey Milovidov).
Improvement
- Improved EXPLAIN PLAN pretty=1 output: print top-level query output columns, show join relation labels/symbols with estimated result rows and locality, and include per-step output columns for join/source steps. The changes cover Information Deficit part from #98117. #99462 (Kirill Kopnev).
- Add MergeTree table setting
share_nested_offsets(defaulttrue). When set tofalse, Array columns with dotted names (e.g.n.a,n.b) are treated as independent columns instead of sharing offset files and validating equal array sizes as part of legacyNestedsemantics. #98416 (Amos Bird). - Users can now specify multiple authentication methods in users.xml/yaml configuration (in SQL it was always possible). #91998 (Flip-Liquid).
- Auto reload Raft inter-node connections which are using TLS. #93455 (Evgeny).
- Extend
cast_keep_nullableto work with Dynamic/JSON types. When set, casting NULL from types that can be Nullable will return NULL, otherwise NULL will throwCANNOT_INSERT_NULL_IN_ORDINARY_COLUMNerror. #96504 (Seva Potapov). - Reduced the memory footprint from the internal data structures (
ISerializationobjects) by introducing an object pool. #96563 (Nikita Mikhaylov). - Add support of
passwordandidentityfields to keeper-client XML config. #96800 (Grigorii Sokolik). - Improve
Icebergwrites for the unity catalog. #98162 (Konstantin Vedernikov). - Add setting
finalize_projection_parts_synchronouslyto allow synchronous finalization of projection parts during INSERT, reducing peak memory usage for tables with many projections while preserving existing async behavior by default. #98228 (Amos Bird). - Add
projections_duration_mscolumn tosystem.part_logthat records per-projection merge/rebuild duration in milliseconds. #98292 (Amos Bird). - Improve canceling queries using ExpressionTransform and NumbersRangedSource by KILL QUERY and cancel query (Ctrl+C) in clickhouse-client. #98908 (Roman Vasin).
- Replace the hardcoded
source_table_engineslist with a runtime lookup viaStorageFactory::getAllStorages(). This adds access checks for some missing table engines and closes #71544. #98984 (pufit). - Add a setting to control type mismatch behavior for Variant and Dynamic (throw or return null). #99085 (Bharat Nallan).
- Improve
Icebergand Spark compatibility: fix inconsistent path handling caused by mixed usage of storage paths and metadata paths; enforce thatIcebergtables write down a table location that is either a URL or an absolute path; add a fallback for counting file sizes inAzurebecause some ClickHouse readers don’t support byte counting after traversal; handleversion-hint.txtin a manner compatible with Spark; introduce type-level abstractions that make it harder to mix up path types in the future; add tests forAzureandLocalthat verify cross-engine interoperability without intermediate uploading/downloading; fix usage of position deletes, which previously relied on path inference heuristics where that approach is inappropriate. #99163 (Daniil Ivanik). #100420 (Daniil Ivanik). - Fix possible race condition in
IPartitionStrategy::cached_resultintroduced in https://github.com/ClickHouse/ClickHouse/pull/92844. #99400 (Arthur Passos). - Users can now write ClickHouse Interval datatypes in the Arrow Format. #99519 (Peter Nguyen).
- Adds native support for importing and exporting
UUIDdata types inArrowandParquetformats. Users can now directly query and transfer UUID data between ClickHouse and other data tools without requiring manual string conversions or workarounds. Automated logical inference for top-level UUIDs, and support for explicit schema hint for nested UUIDs. #99521 (Ivan). - Support
7zarchives on object storage. Closes #70968. #99600 (Alexey Milovidov). - Add
ObjectStorageListedObjects,ObjectStorageGlobFilteredObjects,ObjectStoragePredicateFilteredObjects, andObjectStorageReadObjectsProfileEvents for introspection of object storage (S3,Azure, etc.) file listing and reading pipeline. #99778 (Sema Checherinda). - Fix
mergetable function failing withUNKNOWN_IDENTIFIERerror when querying columns not present in all underlying distributed/remote tables. #99833 (Alexey Milovidov). - Now we include commit time in total mutation execution time metric for ReplicatedMergeTree. It was lost after #96376. #99936 (alesapin).
- Add a write-ahead log for blob objects pending removal in
MetadataStorageFromDisk, improving durability and consistency between metadata and remote object storage when objects are deleted. #100019 (Maksim Kita). - Disable AI SQL generation (
??command) in the embedded client (SSH and WebSocket protocols) to prevent access to the server’s environment variables. #100290 (Alexey Milovidov). - Change the interface for Iceberg inserts with the catalog. Deprecate settings:
storage_catalog_type,storage_aws_access_key_id, etc. #100334 (Konstantin Vedernikov). - Render tabs as 4 spaces when pasting into clickhouse-client. Closes #100405. #100416 (Raúl Marín).
- Avoid scanning the whole remote data lake catalog for “Maybe you meant …” table hints when
show_data_lake_catalogs_in_system_tablesis disabled. #100452 (Alsu Giliazova). - Apply
distributed_index_analysis_min_indexes_bytes_to_activateafter partition pruning. #100477 (Azat Khuzhin). - Fix assertion failure in Parquet bloom filter push down when using empty IN/NOT IN clauses. #100543 (zoomxi).
- MinMax column statistics now store the minimum and maximum values as Field (typed) instead of Float64. The serialized format includes the column type name alongside the values. The statistics file version is bumped to V2; files written by older versions require re-materialization (ALTER TABLE … MATERIALIZE STATISTICS ALL). fix #53140. #100605 (Han Fei).
- Update
cppkafkato include fix for Consumer close deadlock. #100612 (Azat Khuzhin). - Object information used for parsing data files in Iceberg now contains the number of file rows and file size in bytes parsed from manifest file. #100645 (Daniil Ivanik).
- Add
use_separate_cache_arenaconfiguration parameter to be able to control separation of the cache memory arena. #100664 (Seva Potapov). - Adds native support for importing Apache Arrow’s
StringViewandBinaryViewdata types into ClickHouseStringcolumns, improving compatibility for Arrow-based ingestion. #100762 (Ivan). - A few Keeper server settings are now hot-reloaded if config file is changed at runtime: max_requests_batch_size, max_requests_batch_bytes_size, max_request_size, quorum_reads. #100773 (Michael Kolupaev).
- Increment profile events
MemoryAllocatedWithoutCheck/MemoryAllocatedWithoutCheckBytesin release build. #100899 (Pavel Kruglov). - Cgroupv2 memory tracking now excludes
slab_reclaimablefrom kernel memory, giving a more accurate measure of non-reclaimable memory usage. #100901 (Antonio Andelic). use_partition_pruning = 0now also disablesMinMaxindex pruning and count optimization on partition key columns, in addition to disabling pruning based on partition keys. #100904 (Nihal Z. Miaji).pretty=1inEXPLAIN [PLAN]now prints expressions in a human readable format. #100927 (Kirill Kopnev).accurateCastOrNullandaccurateCastOrDefaultnow supportTupletarget types, including nestedTupleswithNullableelements. Previously these functions rejectedTupletargets becauseTuplecould not be insideNullable. Closes #100820. #100942 (Nihal Z. Miaji).- Fix chart duplication in Play UI when switching between light and dark themes. #101058 (Alexey Milovidov).
- Update chdig to v26.3.1 (perfetto UI, sparklines to summary for CPU/Memory/Merges/Queries), system.warnings, regexp search in logs). #101092 (Azat Khuzhin). Update chdig to v26.4.3 (perfetto improvements, fixes for sharing via pastila.nl, flamegraph diffs, change settings in realtime). #103145 (Azat Khuzhin).
- You can now have a trailing comma in the
WITHclause before aSELECTquery. #101093 (Aruj Bansal). - Add
compress_per_column_in_compact_partsMergeTree setting to control how compressed blocks are organized within Compact parts. Whentrue(default, preserving current behavior), each column starts a new compressed block, allowing selective decompression. Whenfalse, all columns within a granule are packed into the same compressed block, improving compression ratio and read performance for workloads that always read all columns. #101114 (Amos Bird). - Show table info balloon in Play UI only when hovering over the table name, not the entire row. #101118 (Alexey Milovidov).
- Add engine-specific icons and improve table list UX in the Play UI sidebar. #101134 (Alexey Milovidov).
- Support
Nullable(Tuple)forArrow,ArrowStream,ORC, legacyParquetformats. #101272 (Nihal Z. Miaji). - Display TOTALS row as a table footer in the web UI (play.html). #101286 (Alexey Milovidov).
- Support multi-query mode in the web UI (
play.html): run multiple queries at once with parallel execution ofSELECT-like queries and per-query result display. #101290 (Alexey Milovidov). - Fix column resize in play.html web UI after the result table was refactored into a web component. #101295 (Alexey Milovidov).
- Add ability limit amount of jemalloc profile flushes on MEMORY_LIMIT_EXCEEDED per time interval. #101396 (Azat Khuzhin).
- Added keeper settings
nuraft_streaming_mode(by defaultfalse),nuraft_max_log_gap_in_stream,nuraft_max_bytes_in_flight_in_stream. Closes #90743. #101427 (Kseniia Sumarokova). - Added
CGroupMemoryUsedWithoutPageCacheasync metric that reports cgroup memory usage excluding both the kernel OS page cache and the ClickHouse userspace page cache, mirroringMemoryResidentWithoutPageCache. Also clarified theCGroupMemoryUsedmetric description. #101513 (Francesco Ciocchetti). - Add parser-level syntactic sugar for the SQL standard
OVERLAYfunction syntax. Theoverlayfunction already exists; this adds support for the keyword-based form usingPLACING,FROM, andFORas separators. #101681 (Desel72). - Added column alias
INDEX_LENGTHto system tableinformation_schema.tables, analogous to existing uppercase aliases in this table. #101705 (Robert Schulze). - System table
information_schema.tablesnow ignores inactive table parts. This makes the shown table size values more realistic. #101706 (Robert Schulze). - The
ngramsfunction now rejects invalid ngram lengths. Example:SELECT ngrams('abc', 0)now returns an error. #101922 (Robert Schulze). - A follow-up for #91820 and #90837: filter unsupported algorithms from the error message; run FIPS-specific tests in FIPS builds. #102067 (Mikhail f. Shiryaev).
- Limit cell height to three lines in the Web UI (
play.html), with expandable cells on click. #102154 (Alexey Milovidov). - Added new option that allows to force (virtual/path) style for S3 endpoints. Resolves #82019; #76007 Continue of https://github.com/ClickHouse/ClickHouse/pull/83168. #102378 (Konstantin Vedernikov).
- The
restore_replace_external_engines_to_nullsetting now also skips restoring databases with external engines (e.g.DataLakeCatalog,MySQL,PostgreSQL,S3) instead of failing or initiating external connections. #102400 (Nikita Fomichev). - Add text index analysis support for the
hasPhrasefunction via theHINTmode. #102438 (Elmi Ahmadov). - Treat STATISTICS as read-only in ColumnDependency to fix LOGICAL_ERROR during MATERIALIZE STATISTICS ALL. #102627 (Konstantin Bogdanov).
- Create and populate
system.asynchronous_metric_login keeper-as-server mode. #102664 (Miсhael Stetsyuk). - Add
default_system_log_flush_policy.skip_alias_columnsconfig option to allow omitting ALIAS columns from system log tables, fixing S3-backed system logs that reject ALIAS columns. #102669 (Miсhael Stetsyuk). - Don’t enable auto statistics for system tables. They rarely have chance to use them. #102862 (Han Fei).
- Support
arraytokenizer for the LIKE optimization. #102880 (Elmi Ahmadov). - Send MemoryAllocatedWithoutCheck even in release builds. #103064 (Azat Khuzhin).
- Expose per-thread untracked_memory in system.stack_trace. #103065 (Azat Khuzhin).
Bug Fix (user-visible misbehavior in an official stable release)
- Fix
Block structure mismatch in streamerror caused by unnecessary columns returned from Lazy materialization. Fixes #95191. #96682 (Nikolai Kochetov). - Fix a logical error with data masking policy query with
ON CLUSTER. #97594 (Bharat Nallan). - Fix a bug when using Unity catalog on top of GCS. #98456 (Melvyn Peignon).
DataLakeCatalognow respects the server’shttp_forbid_headersconfiguration when validating theauth_headersetting. #98827 (Michael Anastasakis).- Fix N+1
HeadObjectcalls for S3 brace-expansion globs. #99219 (Konstantin Bogdanov). - Validate setting changes in create queries when the engine itself also supports settings. #99279 (János Benjamin Antal).
- Fixed
ALTER TABLE UPDATE/DELETEfailing withMissing columnserror when a table has a MATERIALIZED column whose expression depends on an EPHEMERAL column. #99281 (Yash ). - Credentials in JDBC, ODBC, and NATS connection strings are now masked in query logs and
SHOW CREATEoutput, preventing accidental exposure of sensitive information. For URI-style connection strings (e.g.{scheme}://{user}:{password}@{host}), only the password portion is masked while the rest remains visible for easier debugging. Thenats_tokensetting is now also masked. #99344 (János Benjamin Antal). - Fix parseDateTimeBestEffort incorrectly parsing words starting with month prefixes in DD-month-YYYY format. Closes #99345. #99350 (Pavel Kruglov).
- Fix ignoring of TABLE_UUID_MISMATCH for non analyzer. #99380 (Azat Khuzhin).
- Fix a bug where explicit settings sent alongside
compatibilityin the same request could be silently ignored when their value matched the server default. #99402 (Raufs Dunamalijevs). - Fixes cases where numbers with leading zeros in hive partitioning path were causing errors. Fixes #98801. #99458 (Yarik Briukhovetskyi).
- Fix heap-use-after-free when a table is dropped concurrently with a running read query (19 occurrences in CI over the last 90 days). #99483 (Alexey Milovidov).
- Fixed a bug in Keeper where a read request could get stuck (causing session to time out) if a different unrelated session on the same server was closed at just the wrong moment. #99484 (Michael Kolupaev).
- Validate column structure before applying patches. #99531 (Seva Potapov).
- Fix vertical merge
rows_sourcesassertion failure whenSYSTEM STOP/START MERGEStoggles rapidly during merge of table withDynamiccolumns. #99532 (Alexey Milovidov). - Fix incorrect partition pruning for
toWeek()that caused queries withWHERE toWeek(date, mode) = Nto return empty results for weeks 49-52 on tables partitioned bytoYYYYMM(date). #99542 (Takumi Hara). - Fix exception in functions operating on ColumnReplicated with unreferenced rows produced by JOIN. #99564 (Hechem Selmi).
- Fix
CLEAR COLUMNnot rebuilding projections and not reevaluation materialized columns that depend on the cleared column, which could cause exceptions or data corruption during subsequent merges. #99565 (Desel72). - Fixed an exception (
Bad get: has Tuple, actual type String) inConditionSelectivityEstimatorwhen a query uses IN with a single scalar query parameter (e.g.WHERE col IN ({p:String})) on a table that has column statistics anduse_statisticsis enabled. #99614 (Ilya Yatsishin). - Part with unknown projections should not be marked as lost forever. #99623 (Sema Checherinda).
- Fix a rare logical error exception during vertical merge when
SYSTEM STOP MERGESandSYSTEM START MERGESare executed concurrently. #99628 (Desel72). - Fix dangling reference in injectRequiredColumns causing crash during merge. #99679 (Tuan Pham Anh).
- Fix undefined behavior in Avro format reader when reading numeric values that overflow the target column type. Now queries fail on overflows instead of silently producing incorrect values. #99697 (asyablue22).
- Fix parsing of shell-style quotes in arguments for the
executabletable function. #99794 (Nikita Semenov). - Fix false-positive abort in
NativeReaderwhen deserializing a Native format stream with a row-count mismatch: changed fromLOGICAL_ERRORtoINCORRECT_DATAso the error is handled as a data error rather than triggeringabort()in sanitizer/debug builds. #99822 (Rahul Nair). - Fix process abort in
Tuplecolumn deserialization when the serialization kind in the binary stream isDETACHED. #99823 (Rahul Nair). - Fix false
LOGICAL_ERRORexception during filesystem cache dynamic resize due to a race condition in SLRU sub-queue promotion. #99850 (Alexey Milovidov). - Fix async insert queries reporting zero
written_rows,read_rows, andresult_rowsinquery_logand client output. #99879 (Sema Checherinda). - Fix exception “Bad cast from type X to Y” in
KILL QUERYwhen the internal query against system tables returns columns wrapped inColumnConst. #99881 (Alexey Milovidov). - Fix logical error with correlated subquery within untuple argument. #99917 (Vladimir Cherkasov).
- Fixes an exception when calling
right,rightUTF8, or other substring functions with a length of INT64_MIN (-9223372036854775808), which previously caused undefined behavior due to integer overflow. The functions now correctly report an ARGUMENT_OUT_OF_BOUND error. #99934 (Jimmy Aguilar Mena). - Now ClickHouse should properly handle spark-style tables (where we have full absolute path for each file or relative path to common table path). Fixes #92348. #99935 (alesapin).
- Fix “Inconsistent AST formatting” exception for
ALTER TABLE ... MODIFY QUERYwith nested subqueries containingSETTINGSwhen theALTERitself also hasSETTINGS. #99938 (Nikita Mikhaylov). - Revert #97114 “Move join step row estimation before check for 1 child” due to suspected performance regression. #99957 (Alexander Gololobov).
- Fixes a bug where ClickHouse could skip files if the
Content-Lengthheader was missing in their HEAD request response (for example, because of decompressive transcoding in GCS). #99971 (Yarik Briukhovetskyi). - Fix assertion failure (exception in debug builds, incorrect results in release builds) when multiplying
NumericIndexedVectoraggregate states by an even integer constant, caused by self-XOR on aliased Roaring bitmaps inpointwiseAddInplace. #99976 (Desel72). - Prevent
Unexpected return typeexception in legacy filter pushdown through chainedJOIN USINGwhen key types change after join conversions. #99999 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception “Unexpected node type for table expression … Actual IDENTIFIER” when a scalar subquery is used inside an unresolved table function argument, e.g.SELECT * FROM remote('localhost', view(SELECT 2 AS x), concat(x, (SELECT 1))). #100014 (Alexey Milovidov). - Fixed
INSERTwithVALUESfailing when the data was followed by a trailing SQL comment (--or/* */) on the next line. The comment is now skipped instead of being parsed as another row. #100016 (Pratima Patel). - Fix exception in
arrayRemovewhen comparing tuples with NULL components. #100017 (Alexey Milovidov). - Fix cross-user data leak in
system.asynchronous_inserts: any user withSELECTon the table could see pending async insert entries belonging to other users. Entries are now filtered by the current user, unless the user has theSHOW_USERSprivilege. #100024 (Shaohua Wang). - Fixes case where Time64 to UInt64 cast could clamp values to 24 hours. #100025 (Yarik Briukhovetskyi).
- Fix local server crash when CREATE DICTIONARY has a definition with list value containing non-existing function. #100036 (Yakov Olkhovskiy).
- Fix
CSV,MsgPackformat not being able to parseNullable(Tuple)properly. Closes #99753. #100038 (Nihal Z. Miaji). - Fix
CREATE VIEWfailing withUNKNOWN_IDENTIFIERwhen using a WITH function-expression alias (e.g.tuple(...)) as the right-hand side ofIN. #100042 (Peng). - Fix timeseries aggregate functions (e.g.
timeSeriesResampleToGridWithStaleness) failing withILLEGAL_TYPE_OF_ARGUMENTwhen used withinitializeAggregationorAggregatingMergeTreeunder parallel replicas. #100053 (Alexey Milovidov). - Make correctly processing negative values inside NumericIndexedVectorDataBSI. #100086 (Daniil Ivanik).
- Fix
accurateCastOrDefaultandto*OrDefaultfunctions not preserving Const column type for constant inputs. #100132 (Alexey Milovidov). - Omitted query parameters with
LowCardinality(Nullable(T))type now correctly default to NULL, same asNullable(T). #100144 (Denys Melnyk). - Fix use-of-uninitialized-value in StringSearcher.h. #100225 (Konstantin Bogdanov).
- Allow cancellation of scalar subqueries and other analysis-time pipelines via Ctrl+C. Previously, pressing Ctrl+C during a long-running scalar subquery had no effect until the subquery completed. Also fix the progress bar and JSON statistics to correctly report rows read during scalar subquery execution, both in
clickhouse-clientandclickhouse-local. Co-authored with @YjyJeff. #100230 (Raúl Marín). - Fixed a
LOGICAL_ERRORexception in queries involvingDynamiccolumns with cross joins and runtime filters, caused byColumnVariant::filtersharing variant column pointers instead of cloning them in thehasOnlyNullsoptimization path. Closes https://github.com/ClickHouse/ClickHouse/pull/100147. #100234 (Pavel Kruglov). - Fixed array of variant bug which may reinterpret data type upon calling
arrayFirst/arrayLastfunction. For example, previouslyArray(Variant(Date, Bool))is converted toBoolwhen the actual underlying variant type isDate. #100255 (timothygk). - A few minor changes to functions: h3 functions now validate boundaries better; readWKB checks the size limits (a new setting,
max_wkb_geometry_elements); random generator functions limit the maximum iterations in their computations. A follow-up for #93543. #100270 (Alexey Milovidov). - Fixed an issue where cutURLParameter could incorrectly skip parameters when they appeared as substrings of other parameters. #100280 (Nikita Semenov).
- Fix exception when Iceberg metadata file path setting contains a null byte. #100283 (Alexey Milovidov).
- Fixed the quadratic number of run queries when
distributed_index_analysisis used with predicates containingINsubqueries. #100287 (Anton Popov). - Fix “Block structure mismatch” exception when using
GROUP BY ... WITH TOTALS HAVINGcombined withUNION DISTINCTand nullable expressions. #100293 (Alexey Milovidov). - Fix LOGICAL_ERROR exception in
estimateCompressionRatiowhenblock_size_bytesparameter is extremely large. #100298 (Alexey Milovidov). - Fix “Inconsistent AST formatting” exception in debug builds when using
GROUP BY CUBE(...) WITH ROLLUPor similar combinations. #100376 (Alexey Milovidov). - Fix exception when creating a view with column aliases and
SELECT *orEXCEPT/INTERSECTqueries. #100386 (Alexey Milovidov). - Fix
DROP TABLEhanging indefinitely on Kafka engine tables when consumers are stuck in a rebalance after a heartbeat error. #100388 (Alexey Milovidov). - Fix
ReadBuffer is canceled. Can't read from it.exception in backup/restore operations using zip archives. #100400 (Alexey Milovidov). - Fix
TOO_MANY_ROWSexception forSELECT count()queries withmax_rows_to_read/force_primary_keywhen data is split across multiple parts with non-aligned granule boundaries. #100408 (Alexey Milovidov). - Fix
system.completionsto correctly filter databases, tables, and columns by access rights in all grant combinations: per-table, per-db, and per-column revoke. #100432 (Shaohua Wang). - Fix SEGFAULT in NuRaft due to race condition. #100444 (Pablo Marcos).
min/max/argMin/argMaxnow treat NaN consistently withORDER BY: NaN is always skipped (returned only when all values are NaN). Previously, results depended on NaN position in the data due to IEEE 754 unordered comparison semantics. #100448 (Raúl Marín).- Fixed a copy-paste bug where
delta_lake_snapshot_end_versionset withoutdelta_lake_snapshot_start_versionwas silently ignored instead of producing aBAD_ARGUMENTSerror. #100454 (Mohammad Lareb Zafar). StorageRabbitMQ::shutdownis not idempotent (it unconditionally accesses weak pointers and then destroys the corresponding shared pointers), but is now called twice: once inStreamingStorageRegistryand then inDatabaseCatalog. This fix makes the method idempotent and adds defensive null checks. #100455 (Miсhael Stetsyuk).- Fix
LOGICAL_ERRORexception when usingaccurateCastOrNullwithQBittarget type. #100470 (Raufs Dunamalijevs). - Fix LOGICAL_ERROR exception “Stream … not found” when inserting into a table with nested
Array(JSON)columns in wide parts withoptimize_on_insert=0. #100475 (Pavel Kruglov). - Validate file entry paths in backup metadata to reject path traversal, absolute paths, and empty names during
RESTORE. #100483 (Pablo Marcos). - Fix
LIMIT m OFFSET n WITH TIESsyntax not working. This syntax is equivalent toLIMIT n, m WITH TIESwhich already worked. #100491 (Nihal Z. Miaji). - Fix exception “No set is registered for key” when using
INwithNullable(Tuple)columns that have named fields andLowCardinalityelements. #100523 (Alexey Milovidov). - Fix heap-buffer-overflow in usearch
sorted_buffer_gt::insert()that could crash or silently corrupt memory during vector similarity search. #100537 (Dustin Healy). - Fix
EXECUTE ASignoringFORMATandINTO OUTFILEclauses specified in the query. #100538 (pufit). - Fix inconsistent AST formatting for SAMPLE with query-level OFFSET. Closes #100576. #100579 (Pavel Kruglov).
- Fix polaris catalog with azure. Since 25.12 this catalog with azure started to add bucket at the beginning of the path. For example
abfss://polaris-polaris@<some_url>.windows.net/polaris-polaris/<other-path>instead ofabfss://polaris-polaris@<some_url>.windows.net/<other-path>. This PR cuts bucket in the path. #100583 (Konstantin Vedernikov). - Fix type mismatch exception in transform when default column is const on some blocks. Closes #100574. #100616 (Pavel Kruglov).
- Fixes NOT_FOUND_COLUMN_IN_BLOCK cases where the projection SELECT part has columns that do not exist in the original SELECT part of the query. Closes #100194. #100623 (Yarik Briukhovetskyi).
- Validate Npy format shape dimensions against file size and overflow limits to prevent denial of service from crafted
.npyfiles with unreasonably large dimensions. Also reject empty shapes and cap per-row memory to 2 GiB. #100625 (Raúl Marín). - Fix
session_timezonebeing ignored when parsingDateTimevalues during async inserts (TCP) and all inserts over HTTP. #100647 (Sema Checherinda). - Allow passing sharding key to
cluster()andclusterAllReplicas()table functions when using a table function as the source (e.g.cluster('name', view(...), sharding_key)). #100665 (Sergey Veletskiy). - Fix server crash (assertion failure) when using parametric aggregate functions with Array combinator and NULL arguments, such as
quantileIfArrayArray(0.5)([[NULL]], [[1]]). #100679 (nerve-bot). - Fix exception when computing common supertype for empty and non-empty tuples with
use_variant_as_common_typeenabled. #100699 (Antonio Andelic). - Server no longer fails to start when an Azure blob storage disk is configured but the endpoint is temporarily unreachable (e.g. DNS failure). #100701 (Raúl Marín).
- Fix undefined behavior in
positiveModulowhen the unsigned divisor does not fit in the signed result type. #100705 (Raúl Marín). - Fix server crash (logical error “Unexpected return type from __topKFilter”) when
use_top_k_dynamic_filteringis enabled and theORDER BYcolumn hasDynamicorVarianttype. #100742 (Groene AI). - Fix server crash when using
has()function with PREWHERE/WHERE on a Tuple key containing LowCardinality elements. #100760 (Groene AI). - Fix
file_offset_of_buffer_end <= getFileSize()assertion failure (exception in debug builds) when reading fromLogorStripeLogtables on S3 object storage with concurrent writes. #100763 (Alexey Milovidov). - Fix an exception in the statistics selectivity estimator when a WHERE clause contains a function expression (e.g. toDecimal64(col, 3)) on a table with statistics enabled. The estimator now skips such predicates instead of attempting an invalid type cast. #100764 (Han Fei).
- Fixes a rare case where join with reordering can produce a wrong result. #100790 (Yarik Briukhovetskyi).
- Fix incorrect
AggregateFunctionargument types in optimized trivial count, which causedNUMBER_OF_ARGUMENTS_DOESNT_MATCHexception when querying expressions likecount(v0 + v1)on distributed tables. #100794 (YjyJeff). - Some catalogs can show some secrets in the
SETTINGSsection ofselect * from system.databasesquery result. This PR prevents such behavior. #100800 (Konstantin Vedernikov). - Fix undefined behavior (signed integer overflow) in
toStartOfIntervalwhen using Week, Quarter, or Year intervals with an origin argument and extreme interval values. #100817 (Raúl Marín). - Fix
If,Distinct,DistinctIf,IfStateaggregate function combinators withTuplereturn type and one or moreNullableargument not being able to read older serialized states after introduction ofNullable(Tuple). Closes #98917. #100826 (Nihal Z. Miaji). - Fix segfault in s3Cluster and distributed queries due to connection pool use-after-free. #100837 (Konstantin Bogdanov).
- Fix null pointer dereference segfault when loading dictionaries during server shutdown.
Context::getUserDefinedSQLObjectsStorage(dereferencesuser_defined_sql_objects_storage) is called by dictionary threads concurrently with the main thread callingContext::shutdown(setsuser_defined_sql_objects_storageto null). We need to make sure we disable future updates in the dictionaries loader, kill the currently running dictionary queries and join the dictionary loading threads - all before runningContext::shutdown. Similar to what we do with normal queries. #100839 (Miсhael Stetsyuk). - Fix buffer overflow in
ULIDStringToDateTimewhen input contains non-ASCII bytes. #100843 (Konstantin Bogdanov). - Fix crash (
LOGICAL_ERROR) when querying aMergetable (ormerge()table function) that wraps multiple tables including aDistributedtable, withdistributed_group_by_no_merge=1enabled. #100859 (Groene AI). - Cast_keep_nullable when enabled will not throw when casting dynamic null to variant. #100864 (Seva Potapov).
- Fix
clickhouse-keeper-clientget,exists, andlscommands printing duplicatewatch_iderror messages to stdout instead of stderr. #100893 (Mohammad Lareb Zafar). - Fix exception in
intDiv/intDivOrZeroon arrays of nullable tuples, e.g.SELECT intDiv([divide((1, 2), ... AND NULL)], 2). #100895 (Raúl Marín). - Evaluate engine arguments for
StorageAliasbefore storing the definition, so that expressions likecurrentDatabase()are resolved to literals before being saved to the database. #100902 (Nikolay Degterinsky). - Fix
processAndOptimizeTextIndexFunctionswhenquery_plan_merge_expressions = 0, whereExpressionStepis directly aboveReadFromMergeTree. Fixes #100879. #100909 (Jimmy Aguilar Mena). - Update replxx to include fix for out-of-bounds access in do_complete_line. #100925 (Azat Khuzhin).
- Fix wrong results when JOIN with shard-by-PK optimization uses query condition cache and some parts are filtered out by cached conditions. #100926 (Groene AI).
- Fix
divideandintDivreturningILLEGAL_DIVISIONwhen used in filter expressions during index analysis in some cases. #100928 (Nihal Z. Miaji). - Fixed “Target table doesn’t exist” errors for materialized views with inner tables during async startup, caused by incorrect startup dependency ordering. #100946 (Nikolay Degterinsky).
- Fix undefined behavior (signed integer overflow) in parseDateTimeBestEffort when parsing datetime strings with more than 18 fractional-second digits. #100948 (Vasily Chekalkin).
- Fixed a crash when using a text search index with an
INclause containing a tuple subquery, e.g.WHERE (id, str) IN (SELECT (id, str) FROM ...), or when the number of columns in the subquery does not match the tuple on the left side ofIN. #100959 (Anton Popov). - Fixed crash when building a polygon dictionary from a
MergeTreetable that uses sparse columns serialization. #100964 (Anton Popov). - Fix logical error “Invalid action query tree node” when using
INTERSECT ALL/UNION ALLwith constant-folded expressions. #100977 (Alexey Milovidov). - Fix
sumCountOrDefaultaggregate function with one or moreNullableargument not being able to read older serialized states after introduction ofNullable(Tuple). Closes #100882. #101021 (Nihal Z. Miaji). - Fix crash (
Logical error: isConst/isSparse/isReplicated assertTypeEquality) in merge algorithms when lazy column replication (enable_lazy_columns_replication) producesColumnReplicatedcolumns that flow into merge-sort pipelines with late-arriving inputs. #101036 (Groene AI). - Fix incorrect
UNKNOWN_IDENTIFIERerror when the same alias is used for multiple expressions inSELECT; the correctMULTIPLE_EXPRESSIONS_FOR_ALIASerror is now reported. #101040 (Alexey Milovidov). - Fix ALIAS columns with
DateTime/DateTime64types not applying timezone conversion when the declared timezone differs from the expression timezone. #101043 (Alexey Milovidov). - Fix row policies not being recorded in
query_logfor views, subqueries, andINSERT ... SELECT. Even though row policies were applied during query planning, they were not propagated from sub-planners to the parent planner for logging. Row policies (for logging only) are now kept inQueryAccessInfoso that both planners and sub-planners can populate them. #101044 (Narasimha Pakeer). - Fix exception in
DirectJoinMergeTreeEntitywhen pipeline blocks containColumnConstcolumns that are merged with regular columns. #101046 (Alexey Milovidov). - Fix spurious space in CTE column alias formatting (
WITH t (a, b)→WITH t(a, b)). #101049 (Alexey Milovidov). - Fix
remote/clustertable functions failing with nested table functions likemergewhen the analyzer is enabled. #101055 (Alexey Milovidov). - Fix
OFFSETbeing applied twice in distributed queries whenprefer_localhost_replica=1, producing fewer rows than expected. #101071 (Nihal Z. Miaji). - Fix crash when using the
Regexpformat with an invalid regular expression informat_regexpsetting. #101074 (Nihal Z. Miaji). - Fix “Illegal type Decimal64 of start parameter” error for timeseries aggregate functions when using
serialize_query_plan=1with parallel replicas. #101083 (Groene AI). - Fix exception in
optimizeLazyMaterializationwhen a projection with PREWHERE is used withORDER BY ... LIMIT. #101115 (Anton Popov). - Fix server crash (SIGABRT) when using aggregate functions with the internal-only
Nullcombinator (e.g.sumNull,avgNull) andaggregate_functions_null_for_empty = 1setting enabled. #101147 (Groene AI). - Fix a use-after-free in the filesystem cache write path that could cause reads from freed memory when logging completed file segments (detected by MemorySanitizer in BuzzHouse). #101161 (Groene AI).
- Fix server crash with “Trying to attach external table to a ready set without explicit elements” when distributed index analysis encounters a GLOBAL IN predicate whose set was built without explicit elements. #101178 (Groene AI).
- Fix
MAX/MINaggregate functions onDecimalcolumns returning incorrect results when JIT compilation is enabled (after the compilation threshold is reached). #101203 (Raúl Marín). - Fix
minmax_count_projectionand trivialCOUNT(*)optimizations being permanently disabled after a lightweight delete, even after all parts with a mask of lightweight delete were merged away. #101212 (Anton Popov). - Fix a case which can lead to
Having zero bytes, ...logical error from cache arising from a remote object being overwritten in betweenlistandreadwhich previously resulted in a stale object metadata. #101219 (Kseniia Sumarokova). - Fix server crash (LOGICAL_ERROR: Bad cast from ColumnVector to ColumnLowCardinality) when querying a MergeTree table with
ORDER BY CAST(lc_column, 'Type')wherelc_columnhas a LowCardinality type. #101220 (Groene AI). - Fix cleanup of stale processing nodes in
S3Queue. #101230 (Kseniia Sumarokova). - Fix UB in mergeTreeAnalyzeIndexes() in case of invalid optimizations argument. #101253 (Azat Khuzhin).
- Fix
Logical error: 'partitions_count > 0'exception when performing consecutiveALTER TABLE UPDATEon a partitioned Iceberg table. #101278 (Desel72). - Fix wrong query results when a large integer constant (e.g. 256, 2147483648) is used as a boolean predicate in a WHERE clause with AND on MergeTree tables. For example,
SELECT count() FROM t WHERE (2147483648 > b) AND 2147483648would incorrectly return 0 instead of matching all rows. #101287 (Groene AI). - Fix insert-select from delta lake cluster with replicated merge tree. #101299 (Konstantin Vedernikov).
- Fixed crash with “Logical error: Reading from materialized CTE before materialization” when a scalar subquery references a chain of dependent materialized CTEs. #101305 (Groene AI).
- Fix data race on
storage_idinIStorage::getDependentViewsByColumn. #101385 (Nikolay Degterinsky). - Fix BACKUP FROM SNAPSHOT AST formatting and cloning. #101405 (Pablo Marcos).
- Fix LOGICAL_ERROR crash “Current component is empty” when querying
system.part_moves_between_shardswithenforce_keeper_component_trackingenabled. #101462 (Groene AI). - Fix segmentation fault in DataTypeDynamic::create() when the fuzzer generates a malformed Dynamic type AST. #101464 (Groene AI).
- Throw an error when
delta_lake_snapshot_versionor CDF version settings are used without DeltaKernel enabled, instead of silently returning wrong data. #101489 (Desel72). - Fix
NOT_FOUND_COLUMN_IN_BLOCKexception when using ARRAY JOIN with JOIN USING andanalyzer_compatibility_join_using_top_level_identifiersetting enabled. Close #101240. #101507 (Vladimir Cherkasov). - Fix Iceberg INSERT retry loop failing when the table was created with
iceberg_metadata_file_pathand the target metadata version already exists. #101548 (Groene AI). - Strip Nullable from result column in arrayIntersect and related functions to avoid serialization/deserialization mismatch. #101569 (George Larionov).
- Fix server crash (LOGICAL_ERROR) when SELECT-ing from a materialized view backed by an IcebergLocal table engine. #101577 (Groene AI).
- Fix incorrect error message when calling
intExp10with NaN argument — it saidintExp2instead ofintExp10. #101582 (Krishna Chaitanya). - Fix
allow_statistics=0not blockingALTER TABLE ADD STATISTICSandALTER TABLE DROP STATISTICSafter refactoring in #100288. #101585 (Krishna Chaitanya). - Fix
KeeperMapCREATE TABLEfailing with “Cannot create metadata for table” when leftover ZooKeeper nodes from a pre-25.1 partial drop are missing thedrop_lock_versionnode. #101623 (Antonio Andelic). - Fix possible logical error during reading Map subcolumns. Closes #100769. Closes #101336. #101641 (Pavel Kruglov).
- Fix exact subcolumn match priority over prefix match in
getSubcolumnDatato avoid possible crash. Closes #101271. #101645 (Pavel Kruglov). - Fix crash (LOGICAL_ERROR: “ColumnUnique can’t contain null values”) when comparing a
LowCardinalitycolumn with aVariantNULL constant whileuse_variant_default_implementation_for_comparisonsis disabled. #101690 (Groene AI). - What: Added empty-stream guard to Bzip2ReadBuffer so it returns EOF instead of throwing UNEXPECTED_END_OF_FILE when the inner stream is empty. #101691 (ClickGap AI Bot).
- What: Fixed the inverted description text for the
alterablecolumn insystem.s3_queue_settingsandsystem.azure_queue_settings— swapped0and1meanings to match the actual code behavior. #101703 (ClickGap AI Bot). - Fix positiveModulo(tuple, number) incorrectly dispatching to division instead of modulo. #101709 (ClickGap AI Bot).
- Fixes a crash when
thread_pool_sizeis configured on a cache-wrapped disk. Previously,FileCacheSettings::loadFromConfig()rejectedthread_pool_sizeas an unknown setting, preventing the server from starting. The setting is a validIDiskparameter that controls the number of threads used for disk-to-disk copy operations during background part moves. #101712 (Francisco). - Fix
RANGE_HASHEDdictionary creation silently accepting a non-existentMAXrange attribute and using the wrong type configuration when min and max range attributes had different types. The bug was a copy-paste error inbuildRangeConfigurationthat looked upmin_attr_nameinstead ofmax_attr_namefor the max attribute. #101732 (Yakov Olkhovskiy). - Fix use-after-free crash in CPU lease scheduler when the wait timer outlives the worker thread whose
ProfileEvents::Countersit references. #101761 (Antonio Andelic). - Fixes bug in arrayLevenshteinDistanceWeighted and arraySimilarity functions. Closes #101725. #101767 (Mikhail f. Shiryaev).
- Fix Prometheus Query API ignoring POST form bodies. #101794 (James Cunningham).
- Fix exception escaping from S3
Client::~Clientdestructor causing server termination. #101798 (Gagan Dhakrey). - Fix use-after-scope in parallel deserialization of
Objecttype dynamic paths, which could cause crashes when reading tables with many dynamic paths. #101823 (Antonio Andelic). - Fixed incorrect output in function
formatDateTimewith formatter%Wwith certain (non-default) formatting settings. #101847 (Robert Schulze). - Fix
shouldPatchFunctionfalse negative inSYSTEM INSTRUMENT ADDwhen the search string first appears inside a template argument of the demangled symbol name. #101885 (Pablo Marcos). - Fix UDF registry loss when ZooKeeper session expires during periodic refresh — all user-defined functions could become unavailable until a full refresh succeeds. #101891 (Nikita Fomichev).
- Fixed
system.codecsdescription forAES_256_GCM_SIVto reportAES-256instead ofAES-128. #101917 (Jimmy Aguilar Mena). - Fix using wrong extremes in min-max index created on JSON column leading to wrong query result. Closes #101700. #101918 (Pavel Kruglov).
- The
splitByStringtokenizer now rejects empty separator strings. #101928 (Robert Schulze). - Fix
materialize_skip_indexes_on_merge=falsenot suppressing text (full-text) indexes during merge. Previously, only non-text skip indexes (minmax, set, bloom_filter) were suppressed; text indexes continued to be built, wasting CPU and I/O. #101932 (Groene AI). - The
sparseGramstokenizer generated longer tokens than the provided max length (this was due to a hard-coded+2in the implementation). #101934 (Elmi Ahmadov). - Fix SIGSEGV in
MergeTreeDataPartWriterWide::cancelwhen a stream constructor throws duringaddStreams, leaving a null entry incolumn_streams. #101936 (Antonio Andelic). - Fixes an exception when querying Merge or Distributed tables with a full-text index and combined filter conditions that mix
has*Tokenswith LIKE, whilequery_plan_direct_read_from_text_indexis enabled. #101939 (Jimmy Aguilar Mena). - Fix undefined behaviour when parsing native protocol query packets with invalid
QueryProcessingStagevalues. #101972 (Raúl Marín). - Close TCP connection when an exception occurs during initial query parsing to prevent reading garbage from a desynchronized stream. #101989 (Raúl Marín).
- Fix SLRU race bug in filesystem cache 26.1+, which can lead to space reservation logical error. In debug build it can also lead to failed assert:
'Previous state is Evicting, but expected state to be Active while setting Evicting flag for 2c1e3484ecdc6b78a8978fa5b17c5097:0:339 (state: Evicting)'.. #101991 (Kseniia Sumarokova). - Fix exception when casting a string with trailing data to empty
Tuple()type. #102011 (Alexey Milovidov). - Fixes incorrect row ordering in queries that use ORDER BY with the grace_hash join algorithm. Affected queries could return results in the wrong order, producing silently incorrect output. #102036 (János Benjamin Antal).
- Fixes a LOGICAL ERROR (Unexpected size of index type) that could occur in RIGHT JOIN and FULL JOIN queries when the
max_bytes_in_joinsetting was configured. #102042 (Jimmy Aguilar Mena). - Fixes cases where Time with negative values was returning wrong result on comparison with DateTime. Closes #101670. #102056 (Yarik Briukhovetskyi).
- Fix crash in UDF refresh caused by
ZooKeeperRetriesControlretrying on a stale (expired) ZooKeeper session without renewing it. #102059 (Nikita Fomichev). - Fix missing spaces when formatting unlock snapshot. close https://github.com/clickhouse/clickhouse/issues/101723. #102063 (Han Fei).
- Fix crash (SIGSEGV) when querying a view with a WHERE clause and the inner query produces columns with different types than the view metadata (e.g. Nullable from LEFT JOIN with
join_use_nulls). #102085 (Miсhael Stetsyuk). - Fix
VectorSimilarityIndexCacheentries never being evicted after part removal due to mismatched cache keys. #102152 (Seva Potapov). - NACK broken messages when using rabbitmq storage. #102157 (Seva Potapov).
- Fix logical error when parsing incorrect empty tuple string. #102289 (Nihal Z. Miaji).
- Fix incorrect aggregation results (duplicate rows) when using
optimize_aggregation_in_order=1with GROUP BY columns ordered differently from the table’s sorting key. #102299 (Groene AI). - Fix crash in
IcebergLocalALTER TABLE ... UPDATEwhen using Avro format, caused byLowCardinality/Nullablewrapper types not being unwrapped before serialization. #102337 (Desel72). - Fixed a segmentation fault in mutations on materialized columns without an expression. Closes #102185. #102342 (zoomxi).
- Coalescing merge tree fix for array type. This closes #89509. #102384 (Konstantin Vedernikov).
- Fix segfault (or LOGICAL_ERROR in debug builds) when reading Parquet files with bloom filter push down enabled and WHERE clause equality/inequality conditions. The crash occurred due to an out-of-bounds memory access in the Parquet prefetcher’s bloom filter data retrieval, and could also cause non-deterministic wrong query results. #102385 (Groene AI).
- Fix
LOGICAL_ERRORabort during SLRU filesystem cache dynamic resize caused by shared eviction statistics across sub-queues and incorrect recovery path for failed candidates. #102396 (Antonio Andelic). - Fix failure to initialize on a fresh replica Alias tables without a target table in the Database Replicated. Closes #101320. #102397 (Nikolay Degterinsky).
- Fix out-of-bounds read in string search functions (
countSubstrings,position, etc.) when searching for a needle consisting entirely of null bytes. #102401 (Raúl Marín). - Full text index settings (
enable_full_text_index,allow_experimental_full_text_index,use_skip_indexes_on_data_read) are no longer disabled when thecompatibilitysetting points to a version older than 26.1. Previously this could preventSharedDatabaseCatalogfrom creating tables with text indexes. #102422 (Nikita Fomichev). - Fix out of bounds read in
printfwith trailing%. #102472 (Raúl Marín). - Fixes a chassert exception
ReadBuffer is canceledin debug builds in AsynchronousMetrics, caused by rewind not resetting the buffer cancellation flag. #102524 (Yuri Fedoseev). - Fixed
hasToken/hasTokenOrNullwith separator-only needles (e.g.'()','!!!') on columns with a text index: previously the index silently skipped all granules instead of throwingBAD_ARGUMENTS(forhasToken) or returningNULL(forhasTokenOrNull). #102544 (Jimmy Aguilar Mena). - Fix OOMs on huge multi requests in the keeper. For OpenTelemetry tracing, we unconditionally allocate >1 KiB for OpenTelemetry spans in
ZooKeeperRequestobjects - meaning, for really huge multi requests, we try to allocate >10 GiB extra memory. To fix this, we now keep shared data in static memory and usestd::unique_ptroverstd::optionalinZooKeeperOpentelemetrySpans. #102586 (Miсhael Stetsyuk). - Fix
NamedCollectionCurrentMetric being inflated byCREATE NAMED COLLECTION IF NOT EXISTSon existing collections, and not being initialized for collections loaded from config or SQL storage at startup. Closes #102507. #102598 (Pablo Marcos). - Fix exception in
getStructureOfRemoteTablewhen local shard returns empty columns due to concurrent DDL. #102604 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception when multiple concurrentCREATE TABLE IF NOT EXISTSqueries target the sameS3Queuetable on a Shared database. #102610 (Nikita Taranov). - Fix LOGICAL_ERROR crash “Unexpected number of rows in column subchunk” in native Parquet V3 reader when reading nullable columns with a WHERE filter. #102628 (Groene AI).
- Fix
AzureWriteMicrosecondsprofile event description saying “read” instead of “write”. #102639 (Miсhael Stetsyuk). - Bug with row policy that gives ‘Not found column in block’ exception in some special cases. #102648 (Yarik Briukhovetskyi).
- Fixed a server exception in ClusterDiscovery when a static cluster (defined in config) temporarily had no live nodes. #102661 (Kseniia Sumarokova).
- Fix wrong date data type inference in case of overflow after timezone adjustment. Closes #102601. #102674 (Pavel Kruglov).
- Fix
SYSTEM WAIT VIEWhanging forever when the refreshable materialized view is dropped while the wait is in progress. #102681 (Nikolay Degterinsky). - Fix CASE with Dynamic expression returning ELSE for all rows. Closes #102511. #102684 (Pavel Kruglov).
- Fix flattened Dynamic type serialization with binary encoded data types. Closes #101911. #102692 (Pavel Kruglov).
- Fix format_schema_source=‘query’ silently ignoring multi-row results. Closes #101905. #102698 (Pavel Kruglov).
- Report actual exit code via SSH client instead of mapping all errors to
1. Closes #101741. #102700 (Konstantin Bogdanov). - Fix losing HTTP headers for dynamic/predefined query handlers. Closes #101846. #102706 (Konstantin Bogdanov).
- Apply Poisson sampling correction to collapsed jemalloc heap profiles to match jeprof output. Previously the collapsed format underestimated actual allocation sizes by not accounting for the sampling probability. #102759 (Antonio Andelic).
- Fix the crash in the function
hasPhrasewith aNULLargument. #102802 (Nikita Taranov). - Fix server crash (SIGSEGV) when reading Avro files with recursive schemas containing cyclic symbolic type references. Now such schemas are detected and rejected with a clear error message instead of crashing. #102853 (Groene AI).
- Fix server crash (LOGICAL_ERROR assertion) when a function on a
Variantcolumn hits a memory limit or other non-type-conversion exception during result casting inFunctionVariantAdaptor. The exception is now propagated correctly instead of being misclassified as an internal error. #102855 (Groene AI). - Fix server crash in debug/sanitizer builds when
std::length_erroris thrown during schema inference (e.g., from extremeinput_format_msgpack_number_of_columnsvalues or malformed input data). #102859 (Groene AI). - Make null representation in serialization of replicated and sparse columns respect settings (e.g. format_tsv_null_representation). #102888 (Hechem Selmi).
- Backported in #103499: Fix S3 requests failing with
ios_base::clear: unspecified iostream_category errorinstead of being retried, caused by PocoBufferedStreamBuf::flushBuffernot handling short writes from the socket layer. #102894 (Sema Checherinda). - Fix
minmax_count_projectionand trivialCOUNT(*)optimizations being permanently disabled after a lightweight delete, even after all parts with a mask of lightweight delete were merged away. #102900 (Anton Popov). - Fix random crashes in jemalloc due to LTO. #102913 (Azat Khuzhin).
- Optimize row policy OR-chains to IN in the new analyzer. #102915 (Azat Khuzhin).
- Fix jemalloc metadata corruption caused by page cache freeing with wrong alignment that may lead to crashes. #102918 (Azat Khuzhin).
- Plain INSERTs without materialized views no longer request excessive ConcurrencyControl slots and threads (
max_threadsinstead ofmax_insert_threads), preventing CC slot starvation and thread count blowup on clusters with high INSERT throughput. #102961 (Sema Checherinda). - Reintroduce ArrowMemoryPool to allow throwing MEMORY_LIMIT_EXCEEDED to avoid kernel OOM. #102999 (Azat Khuzhin).
- Fix
cast_string_to_date_time_modebeing ignored forCASTtoNullable(DateTime). Closes #101840. #103035 (Pavel Kruglov). - Added support for
ALIAScolumns in text index direct read optimization. #103037 (Anton Popov). - Backported in #103454: Fix
SELECT DISTINCTsilently returning incomplete results when an aggregate projection matched the query and some parts of the table had no projection data (e.g. the projection was added on a table that already held data, andMATERIALIZE PROJECTIONwas not run). Closes #102951. #103052 (Nihal Z. Miaji). - Fix wrong results returned by
WHERE x AND toNullable(N)onMergeTreetables whenNis an integer wider thanUInt8(e.g.256,65535,2147483648, or any negative integer). The filter incorrectly discarded all rows becausesplitFilterNodeForAllowedInputsused aNULLzero when converting theNullableremainder of a reducedANDto boolean, turning the comparison intoNULLunder three-valued logic. #103077 (Groene AI). - Fixed incorrect argument type reported in error messages of string search functions (e.g.
locate,position) when arguments are passed in swapped order (locate(needle, haystack)withfunction_locate_has_mysql_compatible_argument_order = 1). #103102 (Alex Kuleshov). - Fix waitForPause hanging indefinitely when disableFailPoint is called with no thread paused at the failpoint. #103119 (Shaohua Wang).
- Cap pre-auth TCP Hello packet strings to 64 KB and add
handshake_timeout_millisecondsserver setting to limit total handshake time, preventing unauthenticated clients from consuming excessive memory or holding threads indefinitely. #103284 (Sema Checherinda). - Fix Parquet ColumnIndex stats min_value > max_value for String columns. #103334 (Saurabh Kumar Ojha).
- Check for malformed flattened Dynamic data in Native format. #103392 (Pavel Kruglov).
- Populate
_timecolumn fromurltable function. #103437 (Nikita Taranov). - Fix SVE detection using SVE instructions when unavailable. #103568 (Raúl Marín).
Build/Testing/Packaging Improvement
- Libstemmer (Snowball) dependency now uses newer version v3.0.1. #99256 (Jimmy Aguilar Mena).
- Randomize settings in clickhouse-test:
use_skip_indexes_for_top_k,use_top_k_dynamic_filtering,query_plan_max_limit_for_top_k_optimization. #91782 (Nikita Fomichev). - Implement a stress test for functions, checking the soundness of their various properties. #93543 (Michael Kolupaev).
- Provide own CMake configuration for
llvm-projectinstead of importing upstream one. #97453 (Konstantin Bogdanov). - Randomize more
optimize_*settings in the test infrastructure to improve coverage of query optimization passes. #97547 (Alexey Milovidov). - Use Rust toolchain nightly-2026-03-22. #98602 (Konstantin Bogdanov).
- Use
wasmtimev42.0.1. #98603 (Konstantin Bogdanov). - Use
llvm-project22.1.1. #98882 (Konstantin Bogdanov). - Replace
SANITIZE_COVERAGE(custom sanitizer callbacks, symbol-level granularity) with LLVM source-based coverage (WITH_COVERAGE,-fprofile-instr-generate -fcoverage-mapping) for the nightly per-test coverage pipeline. The server now reads its own coverage mapping from ELF sections at startup and collects(file, line_start, line_end)tuples per test via a newSYSTEM SET COVERAGE TEST 'name'command. Test selection in targeted CI checks uses line-range queries against a newchecks_coverage_linesCIDB table and ranks candidate tests by how many changed diff lines they cover. #99513 (Nikita Fomichev). - Fix llvm-libc link error with -O0 build. #100023 (Zheguang Zhao).
- Fixed two error messages on container startup in case the configuration did not contain the
logger.logandlogger.errorlogsettings (e.g. when all log messages are supposed to go to STDOUT/STDERR). #100239 (Simon). - Prefer
ld64.lldover Apple’sld(cctools-port ld64) for macOS builds. This should significantly reduce Darwin link times, as cctools-port’s ld64 is very slow with-ffunction-sectionsand-dead_strip. Falls back toldifld64.lldis not available. #100275 (Alexey Milovidov). - Tests to ensure that directories do not register any secrets (REST + Glue). #100307 (Konstantin Vedernikov).
- Repeat recently modified tests with different randomized settings. #100385 (Alexey Milovidov).
- Track
#embedfile dependencies in CMake and enable ccache depend mode for correct rebuilds. #100411 (Alexey Milovidov). - Add correctness tests for TPC-H queries. #100580 (Raufs Dunamalijevs).
- Use
aws-sdk-cpp1.11.771. #100582 (Konstantin Bogdanov). - Allow performance test XMLs to reference external SQL query files and settings via file attribute. #100747 (Raufs Dunamalijevs).
- Fix compilation with
-march=x86-64-v4by adding missingTargetSpecific.hinclude inLowerUpperImpl.h. #100932 (Alexey Milovidov). - Fix build on gentoo by adding
--no-default-configto cxxflags. #100973 (Isak Ellmer). - Added
utils/auto-bisect/— a shell-based bisection framework that downloads pre-built CI binaries and runs a user-supplied test script to find the first commit that introduced a regression, without requiring a local build. #100989 (Nikita Fomichev). - Disable ThinLTO by default in CMake so that local developer builds no longer implicitly enable it. CI release builds are unaffected since they explicitly pass
-DENABLE_THINLTO=1. #101041 (Alexey Milovidov). - Add TPC-DS SF1 benchmark to performance tests. #101209 (Raufs Dunamalijevs).
- Added stateless tests for MergeTree lightweight deletes covering:
has_lightweight_deleteflag lifecycle,COUNT(*)correctness withoptimize_trivial_count_query,MATERIALIZED/DEFAULTcolumn integrity,ReplicatedMergeTreeflag recovery,read_in_orderwith deleted rows, multiple delete/merge cycles,_row_existscolumn hiding, predicate variety, andALTER DELETERBAC enforcement. #101792 (Nikita Fomichev). - Distroless Docker images are now published with ubuntu and alpine variants for tagged releases. #101941 (Rahul Nair).
- Stack traces now show clean bare relative paths (e.g.
src/Common/Exception.cpp) instead of paths polluted with the build directory (e.g../ci/tmp/fast_build/./src/Common/Exception.cpp). #102000 (Raúl Marín). - Add a CI style check that rejects files larger than 5 MB committed to the repository, with a whitelist for existing legitimate test data. Remove unused 14 MB
zookeeper_log.parquet. #102080 (Raúl Marín). - Remove ~400 unused
#includedirectives from headers to reduce compilation times. #102585 (Raúl Marín). - Use
wasmtimev43.0.1. #102603 (Konstantin Bogdanov). - Use
openssl3.5.6. #102606 (Konstantin Bogdanov). - Use
xz5.8.3. #102607 (Konstantin Bogdanov). - Upgrade distroless Docker image base from Debian 12 (glibc 2.36, OpenSSL 3.0) to Debian 13 (glibc 2.41, OpenSSL 3.5), reducing CVE surface to zero reachable vulnerabilities. #101678 (Rahul Nair).
ClickHouse release 26.3 LTS, 2026-03-26. Presentation, Video
Backward Incompatible Change
- Downgrading after upgrading may cause data loss. Propagate data types serialization versions to nested data types. For example, String serialization version
with_size_streampreviously was applied only on top-level String columns and Tuple elements. Now it’s applied to any String type inside any nested type likeArray/Map/Variant/JSON/etc. This behaviour is controlled by MergeTree settingpropagate_types_serialization_versions_to_nested_typesthat is now enabled by default. After this change, newly created data parts cannot be read by older versions, but old parts can be read on new version with no problems. Upgrade is safe, but downgrade is not — if you need to roll back after upgrading to 26.3, data written by 26.3 in columns with nested types will be unreadable! See #101429 for details. #94859 (Pavel Kruglov). - Remove the
hypothesisskip index type. It was an obscure, experimental feature with limited practical use. Creating tables withINDEX ... TYPE hypothesiswill now produce an error. #96874 (Alexey Milovidov). - Remove the experimental
detectProgrammingLanguagefunction. #99567 (Alexey Milovidov). - Fix
NOToperator precedence to match the SQL standard:NOTnow binds looser thanIS NULL,BETWEEN,LIKE, and arithmetic operators. For example,NOT (x) IS NULLis now parsed asNOT (x IS NULL)instead of(NOT x) IS NULL. This may change the result of queries that relied on the previous (non-standard) behavior. #97680 (Alexey Milovidov). - Corrects the metadata of normal projections so that projections with multi-column sorting keys are properly recognized. Builds on top of #90429. #91352 (Amos Bird).
- Fixed skip index files not respecting replace_long_file_name_to_hash setting, causing “File name too long” errors and broken index reads for indices with long names. Skip index filenames are now hashed when they exceed max_file_name_length, similar to column files. This is backward compatible (new servers read old parts), but downgrading (or old servers during a rolling upgrade) may cause long-named indices to be ignored. #97128 (Raúl Marín).
- Turn on async insert by default. ClickHouse will be batching all small inserts by default now. This setting is set under compatibility. If you set
compatibility=<version less than 26.2>then default value would be the previous one,false. You can turn off/on async inserts at several levels: in the config in users profiles, for the session, for the query, or for the MergeTree table. #97590 (Sema Checherinda). - Change the default value of
mysql_datatypes_support_levelfrom empty todecimal,datetime64,date2Date32, enabling proper mapping of MySQLDATEtoDate32,DECIMAL/NUMERICtoDecimal, andDATETIME/TIMESTAMPwith precision toDateTime64by default. Previously, MySQLDATEcolumns were mapped toDatewhich cannot represent dates before 1970-01-01, causing data corruption. #97716 (Alexey Milovidov). - Accept array of part names instead of regexp for
mergeTreeAnalyzeIndexes{,UUID}since regexp is slow (Experimental feature). #98474 (Azat Khuzhin). - Change default
stderr_reactionfromthrowtolog_lastfor executable UDFs. UDFs that write warnings to stderr no longer fail when exit code is 0. Exit code exceptions now include stderr content. #99232 (Xu Jia).
New Feature
- Added bucketed serialization for Map columns in MergeTree (
map_serialization_version = 'with_buckets'). Keys are split into hash-based buckets so that reading a single key (m['key']) only reads one bucket instead of the entire column, providing 2-49x speedup for single-key lookups depending on map size. The number of buckets and the bucketing strategy can be controlled by new MergeTree settings:map_serialization_version,max_buckets_in_map,map_buckets_strategy,map_buckets_coefficient, andmap_buckets_min_avg_size. #99200 (Pavel Kruglov). - Support materialized CTE. Allow evaluating CTEs only once during query execution and store their results in temporary tables. Closes #53449. #94849 (Dmitry Novik).
- Allow certain SQL-standard functions without parentheses for compatibility, such as
NOW. Closes #52102. #95949 (Aly Kafoury). - You can now use the natural sort key function as
naturalSortKey(s). #90322 (Nazarii Piontko). - You can now use native JSON/Object input for JSONExtract functions. Closes #88370. #96711 (Fisnik Kastrati).
- If a query parameter has
Nullabletype and is not specified, we will assume that its value isNULL. #93869 (Vikash Kumar). - Support auxiliary ZooKeeper for
Replicateddatabase. #95590 (RinChanNOW). - Support
hasfunction for JSON type to check path existence, similar to Map. #96927 (DQ). - Added the
mergeTreeTextIndex(database, table, index)table function, which allows reading data directly from a text index. This function can be used for introspection or for performing aggregations on top of text index data. #97003 (Anton Popov). - Add
table_readonlyMergeTree setting to mark tables as read-only, preventing inserts and modifications. #97652 (Alexey Milovidov). - Add new setting
use_partition_pruningand aliasuse_partition_key. Set it tofalseto disable partition pruning based on the partition key. #97888 (Nihal Z. Miaji). - Implements
ALTER TABLE ... EXECUTE expire_snapshots('<timestamp>')for Iceberg tables. #97904 (murphy-4o). #99130 - Allow each
type=httpentry in<protocols>to specify a custom<handlers>key pointing to a separate<http_handlers_*>config section, enabling different HTTP routing rules per port. #98414 (Amos Bird). - Add
pretty=1option toEXPLAINfor tree-style indented output andcompact=1to collapseExpressionsteps, making query plans more readable. #98500 (Kirill Kopnev). - Add
restore_access_entities_with_current_grantsserver setting. When enabled, restored users/roles from backups have their grants limited to what the restoring user is allowed to grant (same semantics asGRANT CURRENT GRANTS), instead of failing withACCESS_DENIED. #98795 (pufit). - Add
caseFoldUTF8andremoveDiacriticsUTF8functions for Unicode case folding and diacritical mark removal. #98973 (George Larionov). - Add
normalizeUTF8NFKCCasefoldstring function for NFKC_Casefold Unicode normalization, which combines NFKC normalization with case folding. #99276 (George Larionov). - Add
unicode_wordtokenizer for full-text indexes and thetokensfunction. It splits text using Unicode word boundary rules: ASCII words are formed with connector characters (underscore, colon, dot, single quote), while non-ASCII Unicode characters become single-character tokens. Note: 26.3 accepts this tokenizer only under the nameunicode_word; it was renamed toasciiCJKin 26.4. #99357 (Amos Bird). - Added
max_skip_unavailable_shards_numandmax_skip_unavailable_shards_ratiosettings to limit how many shards can be silently skipped whenskip_unavailable_shardsis enabled. If the number or ratio of unavailable shards exceeds the configured threshold, an exception is thrown instead of returning silently incomplete results. #99369 (Alexey Milovidov). - Users can now use
SOMEkeyword for subquery expressions. It behaves identically toANY. #99842 (Artem Kytkin). - Add
output_format_trim_fixed_stringsetting to strip trailing null bytes fromFixedStringvalues in text output formats. #97558 (NeedmeFordev). - Support parenthesized table join expressions in FROM clause, e.g.
SELECT * FROM (t1 CROSS JOIN t2). #97650 (Alexey Milovidov). - Implement function
toDaysInMonth: it returns the number of days in the month of the specified date. #99227 (Vitaly Baranov).
Experimental Feature
- Add experimental support for WebAssembly-based user-defined functions (UDFs), allowing custom function logic to be implemented in WebAssembly and executed within ClickHouse. Special thanks to Alexey Smirnov for contributing the Wasmtime backend support. #88747 (Vladimir Cherkasov). Incremental improvements for WASM UDF support. #99373 (Vasily Chekalkin).
- Add support for external SQL dialects using
polyglotlibrary. #99496 (Alexey Milovidov). - Add
ALPfloating-point compression codec (without ALP_rd fallback for non-compressible doubles). #91362 (Nazarii Piontko). - Add experimental lazy type hints for
JSONcolumns. When enabled viaallow_experimental_json_lazy_type_hints,ALTER TABLE ... MODIFY COLUMN json JSON(path TypeName)that only adds or modifies type hints completes instantly as a metadata-only operation, without rewriting historical data. Type hints are applied at query time for old parts and materialized during INSERTs and background merges. #97412 (tanner-bruce). - Enable parallel reads from YTsaurus table engine. #97343 (MikhailBurdukov).
Performance Improvement
- Improve the performance of data lakes. In previous versions, reading from object storage didn’t resize the pipeline to the number of processing threads. This gives orders of magnitude improvements (~40x) on multi-core machines. #99548 (Alexey Milovidov).
- Now, the relationship between
enable_parallel_replicasandautomatic_parallel_replicas_modeis as follows. A query can use parallel replicas only ifenable_parallel_replicas > 0. Additionally, ifautomatic_parallel_replicas_mode=1, the decision whether to use parallel replicas is made during planning based on the previously collected statistics. Ifautomatic_parallel_replicas_mode=0, parallel replicas will be used for all supported queries regardless of any statistics. One notable exemption is distributed insert-select with parallel replicas: in this case, queries will always be executed as ifautomatic_parallel_replicas_mode=0. #97517 (Nikita Taranov). - Allow partition pruning when the predicate contains any comparison operator (
=,<,>,!=) and the partition key is wrapped in a deterministic function chain (e.g.PARTITION BY xand predicates likecityHash64(x) % 5 > 2,toYYYYMM(x) < 2026,toYYYYMM(x) = 2026, ortoYYYYMM(x) != 2026will all use the partition key for pruning). Closes #28800. #98432 (Nihal Z. Miaji). - Allow read-in-order optimization and primary-key pruning when the
CASTtarget type isNullableand the conversion is monotonic; for example, withPRIMARY KEY x, ClickHouse can use read-in-order optimization forORDER BY x::Nullable(UInt64)and can apply primary-key pruning for predicates such asWHERE x::Nullable(UInt64) > 500000. #98482 (Nihal Z. Miaji). - Allow index pruning and filter pushdown when an integral column is compared with a float literal; for example, predicates like
WHERE x < 10.5can now use the primary key for pruning, and filters such asprime < 1e9ornumber < 1e5are now pushed down for theprimes()andnumbers()table functions instead of causing unbounded execution. Closes #85167. #98516 (Nihal Z. Miaji). - Added a new SLRU cache for Parquet metadata to improve read performance by removing the need to re-download files just to read metadata. #98140 (Grant Holly).
- Support swapping sides of ANTI, SEMI and FULL joins based on optimizer statistics. #97498 (Hechem Selmi).
- Optimize granules skipping for
pointInPolygonfor large polygons and fixpointInPolygonindex analysis throwing during primary key pruning. #91633 (Nihal Z. Miaji). - Improve performance of
levenshteinDistancefunction. #94543 (Joanna Hulboj). - Optimize batch decimal type conversions by avoiding per-element function calls. #95923 (Konstantin Bogdanov).
- Iceberg tables now support asynchronous metadata prefetching via
iceberg_metadata_async_prefetch_period_mstable setting, which periodically pre-populates the metadata cache. Additionally, theiceberg_metadata_staleness_msquery setting allows SELECT queries to use cached metadata if it is fresher than the specified staleness, eliminating calls to the Iceberg catalog during request processing. #96191 (Arsen Muk). S3Queueordered mode uses S3 ListObjectsV2 StartAfter to avoid re-listing full prefix history, reducing ListObjects calls. #96370 (Venkata Vineel ).- Lower memory usage for inserts deduplication. In general the original block is needed for deduplication, but for sync insert we could omit it and save the memory for good. #96661 (Sema Checherinda).
- Use an arch-specific value for cache line size instead of a hardcoded value of 64. #97357 (Nikita Taranov).
- Slightly optimized reading from the text index dictionary, improving the overall performance of text index analysis. #97519 (Anton Popov).
- Speed up
LZ4decompression of 16 byte blocks in ARM. #97774 (Raúl Marín). - Refactor tokenization to a new high-performance interface, replacing the old iterator-style API to support SIMD and stateful tokenizers. Part of #90268. #97871 (Amos Bird).
- Improved performance of text index analysis for queries with combined conditions involving both indexed and non-indexed columns. Previously, early exit optimization during index analysis was incorrectly disabled in such cases. #98096 (Anton Popov).
- Improve the performance of queries with constant expressions that generate very long arrays or maps. #98287 (Alexey Milovidov).
- Fix key condition analysis for
DateTime64primary keys compared with integer constants, which previously resulted in no granule pruning. #98410 (Amos Bird). - The setting
optimize_syntax_fuse_functionsis enabled by default. #98424 (Alexey Milovidov). - Optimize
avgWeightedaggregate function by using local accumulators instead of per-row store-forwarding through aggregate state, improving performance by up to 27% for Nullable inputs. #98793 (Antonio Andelic). - Improves performance and reduces memory usage for parallel window functions in certain scenarios, and for
arrayFoldworkloads with large arrays. This can also reduce page-fault pressure and improve stability under tight memory limits for affected queries. #98892 (filimonov). - Improve performance of sorted merges. #99013 (Artem Zuikov).
- Optimize
INTERSECT ALLandEXCEPT ALL. #99097 (Raufs Dunamalijevs). - Support the
read_in_order_use_virtual_rowoptimization for reverse-order reads. #99198 (Vladimir Cherkasov). - Reduce cache contention in
RIGHTandFULLJOINs by checking if JoinUsedFlags is set before writing. #99274 (Hechem Selmi). - Optimize
PrefetchingHelper::calcPrefetchLookAheadby replacing floating-point math with pure integer arithmetic, improving instruction cache layout and reducing cycle overhead during aggregation loops. #99327 (Riyane El Qoqui). - Reduce memory consumption of Keeper by replacing
absl::flat_hash_setwithCompactChildrenSetfor storing node children. The new container stores 0–1 children inline without heap allocation, which covers the majority of Keeper nodes. This reducesKeeperMemNodesize from 144 to 128 bytes. #99860 (Antonio Andelic). - Aggregate projections are now correctly supported in views. Fixes #32753. #88798 (Amos Bird).
- Support OUTER to INNER join conversion optimization with
join_use_nulls. Closes #90978. #95968 (Vladimir Cherkasov). - Improve subcolumns reading by correct sizes calculation before reading. It reduces memory usage and speeds up the subcolumns reading. #96251 (Pavel Kruglov).
- Make mark, uncompressed and page caches to use separate jemalloc arena to avoid memory fragmentation when short lived allocations, i.e., for queries and requests are mixed with longer lived allocations for caches. #96812 (Seva Potapov). #98812. #99021
- Tables with
DELETE TTLrules can now use the vertical merge algorithm. #97332 (murphy-4o). - Apply data skipping indexes during distributed index analysis. #97767 (Azat Khuzhin).
- Marks of secondary indexes are now prewarmed when the
prewarm_mark_cachesetting is enabled (loaded into the index mark cache during data part fetches and table startup). #97772 (Anton Popov). - Reduced locking during access control. #97894 (Nikita Taranov).
- When apply_row_policy_after_final or apply_prewhere_after_final is enabled, compound AND conditions in row policies and PREWHERE are now decomposed to extract sorting-key atoms for primary key index analysis. Previously, if a deferred filter contained a mix of sorting-key and non-sorting-key predicates (e.g. x > 1 AND y != ‘foo’), the entire expression was excluded from index analysis. Now sorting-key atoms (like x > 1) are extracted and used for granule pruning, even from nested AND expressions. #98513 (Yarik Briukhovetskyi).
- Reduce lock contention in MergeTreeBackgroundExecutor by making task resources release without acquiring the lock. Closes #93620. #98604 (Dmitry Novik).
- Fix excessive memory usage (~514 MiB) during format auto-detection when reading non-Arrow data (e.g. JSON from
urlorfilewithout explicit format), caused by the ArrowStream reader misinterpreting the first bytes as a huge metadata length. #98893 (Konstantin Bogdanov).
Improvement
- Makes it possible to parse GeoParquet files that contain different Geo type in the same column. #97851 (Mark Needham).
- Introduce
tokensForLikePatternSQL function that tokenizes LIKE patterns while respecting wildcard semantics:%and_are treated as wildcards, escaped wildcards (\%,\_) are treated as literals, and tokens adjacent to unescaped wildcards are discarded. #97872 (Amos Bird). - Add a
{_schema_hash}placeholder for the S3 table engine that inserts a hash of the table’s column definitions into the S3 path. #98265 (Miсhael Stetsyuk). SymbolIndex,addressToSymbol,system.symbols, andbuildIdnow work on macOS by parsing Mach-O symbol tables. #99014 (Alexey Milovidov).- The
system.stack_tracetable now works on macOS, allowing introspection of all server thread stack traces. #98982 (Alexey Milovidov). - Add per-server LDAP config option
<follow_referrals>(defaultfalse) to control whether the LDAP client follows referrals. Disabling referral chasing avoids timeouts and hangs when searching from an Active Directory domain-root base DN. Referral-related log messages are moved fromwarntotrace. #96765 (paf91). - We now track any data skipping indices that were used during query execution in the query_log table in a new column named
skip_indices. Fixes #78676. Original author @pheepa. #87862 (Grant Holly). - ACCESS_DENIED hints no longer reveal column names unless the user can show all required columns; database/table names remain visible in the hint. #91067 (filimonov).
- Add a dedicated cleanup thread for MergeTree to prevent cleanup delays under heavy merge load. This resolves #86181. #91574 (Amos Bird).
- Reload cluster config if IPs of local server’s hostname changed, instead of IPs of any host. Fixes #81215, #70156 and #65268. #93726 (Zhigao Hong).
- Allow optimize_aggregators_of_group_by_keys to correctly optimize aggregate functions in GROUPING SETS queries. #93935 (Xiaozhe Yu).
- Keeper-bench: report errors in metrics and generate json metrics file for
--input-request-logmode. #95748 (Mohammad Lareb Zafar). - Add new clause ROLE to CREATE USER. #97074 (Vitaly Baranov).
- You can now set internal_replication settings for a cluster created by the Replicated database. #97228 (Pervakov Grigorii).
- New setting
allow_nullable_tuple_in_extracted_subcolumnscontrols whether extractedTuple(...)subcolumns fromTuple,Variant,DynamicandJSONare returned asNullable(Tuple(...))(NULLfor missing rows) or asTuple(...)(default tuple values for missing rows). Disabled by default, this setting can only be changed by restarting the server. #97299 (Nihal Z. Miaji). - Add information about deferred filters as a separate item to EXPLAIN query output (when using Row Policies/PREWHERE with FINAL). Related: #91065. #97374 (Yarik Briukhovetskyi).
- Enable
type_json_allow_duplicated_key_with_literal_and_nested_objectby default. It allows to avoid errors about duplicated keys during parsing of JSONs like{"a" : 42, "a" : {"b" : 42}}that can be formatted by ClickHouse from original JSON data{"a" : 42, "a.b" : 42}. #97423 (Pavel Kruglov). - Keeper improvement:
find_super_nodesis a very useful command for debugging unexpected growth in the node count in Keeper. Unfortunately, if there are multiple super nodes, it’s almost impossible to find more than one, because the command gets stuck forever traversing the children of the first encountered super node. This PR forbids traversing the children of super nodes. #97819 (pufit). - Initial completion support for
clickhouse-keeper-client. #97828 (Konstantin Bogdanov). - Flush async logging buffers in case of crash. #97836 (Azat Khuzhin).
- Enable the impersonate feature by default (see EXECUTE AS target_user). #97870 (Vitaly Baranov).
- Improve canceling queries with SQLite table engine by KILL QUERY and cancel query (Ctrl+C) in clickhouse-client. #97944 (Roman Vasin).
- Add server setting
jemalloc_profiler_sampling_rateto control jemalloc’slg_prof_sampleand expose it asjemalloc.prof.lg_sampleasynchronous metric. #97945 (Antonio Andelic). - Support weights in concurrent bounded queue implementation. #97962 (Daniil Ivanik).
- Add sslmode to the allowed keys for PostgreSQL dictionary sources. Previously, sslmode was not in the dictionary_allowed_keys allowlist in PostgreSQLDictionarySource.cpp, making it impossible to configure SSL mode for PostgreSQL dictionary connections. This prevented dictionaries from connecting to PostgreSQL servers that require SSL (e.g., AWS RDS, which enforces SSL by default), as the connection would fail TLS negotiation and the server would reject the unencrypted fallback. #98014 (mcalfin).
- Show a clear “no such file” error when passing a non-existent file path to
clickhouseorclickhouse-local, instead of a confusing generic message. #98048 (Raúl Marín). - Text indexes can now be built on top of
Nullable([Fixed]String)andArray(Nullable([Fixed]String))columns. #98118 (Jimmy Aguilar Mena). - Avoid dropping named collections that are dependencies of dictionary sources. #98127 (Pablo Marcos).
- Enable
grace_hashjoin algorithm for queries with totals. #98144 (János Benjamin Antal). - Cancel background merges early in DROP DATABASE for ordinary shared merge tree. #98161 (Shaohua Wang).
- Improve canceling queries with MongoDB and MySQL by KILL QUERY and cancel query (Ctrl+C) in clickhouse-client. #98187 (Roman Vasin).
- Remove NetlinkMetricsProvider and use procfs exclusively for per-thread taskstats metric collection. Netlink-based collection is problematic in containerized environments and has worse tail latency under contention. #98229 (Amos Bird).
- Refactor Iceberg manifest file handling to fix issues with manifest file caching. #98231 (Daniil Ivanik).
- Now we take into account cases where the sorting key of the table can be an expression like
toDate(time), and can make the decisions about not-deferring expressions like this if they are part of filters. #98237 (Yarik Briukhovetskyi). - Add a new
MaxAllocatedEphemeralLockSequentialNumbermetric for the maximum sequential number allocated for ephemeral lock znodes in ZooKeeper. #98243 (Miсhael Stetsyuk). - Update clickstack to version 2.20.0. #98252 (Aaron Knudtson).
- Added a new profile event
KeeperRequestTotalWithSubrequeststhat counts each subrequest within a multi-request individually, providing better visibility into the actual Keeper workload. The existingKeeperRequestTotalevent continues to count each multi-request as a single request. #98348 (Antonio Andelic). SYSTEM RELOAD DICTIONARIESnow reloads dictionaries in topological order so that dictionaries sourcing from other dictionaries see fresh data after reload. #98356 (Alexey Milovidov).- Restart the statistics cache after changing the MergeTree setting. #98520 (Han Fei).
- Only “alive” replicas (that are connectable) participate in distributed index analysis. #98521 (Azat Khuzhin).
- Add a setting
access_control_improvements.disallow_config_defined_profiles_for_sql_defined_users(disabled/allowed by default) that disallows using config-defined settings profiles (except for thedefaultprofile) for SQL-defined users. #98662 (Alexander Tokmakov). - Cap the number of nodes used in the automatic parallel replicas heuristic to the actual number of nodes in the cluster (instead of only the
max_parallel_replicassetting). #98668 (Nikita Taranov). - Implement hedged requests and asynchronous reading for distributed index analysis. #98724 (Azat Khuzhin).
- Deserialization of binary
AggregateFunctionstates now requires consuming the full input. If extra redundant trailing bytes are present, ClickHouse throws an exception instead of accepting malformed state data. #98786 (Nihal Z. Miaji). - Make TRUNCATE DATABASE respond to query cancellation. #98828 (Shaohua Wang).
- Improve
keeper-benchwith request pipelining, warmup period, per-operation stats, reproducible seeds, and better error handling. #98906 (Antonio Andelic). - Support SAMPLE clause in distributed index analysis. #98931 (Azat Khuzhin).
- Show chart title in dashboard even when query returns empty result or encounters an error. #98975 (Yash ).
- Analyzer error messages no longer dump all columns of a table (which could produce 150KB+ exceptions). Column lists are now capped at 10 entries. #99002 (Yash ).
- Properly return column stats from sub-queries with joins so that parent query can use them for join reordering. #99096 (Alexander Gololobov).
- Mark ZooKeeper session as expired immediately when finalization starts, instead of waiting for the send thread to exit. This allows other threads to establish a new session without delay. #99102 (Raúl Marín).
- Use more math functions from LLVM-libc:
exp,exp2,expm1,fabs,fabsl,floor,fmodl,log,log2,logf,pow,scalbn,scalbnl,copysignl,nan,nanf,nanl, and theexplogxfshared constants. #99118 (Konstantin Bogdanov). - Reduce memory usage and fix potential duplicate output in
system.jemalloc_profile_textcollapsed format. #99121 (Antonio Andelic). - Add
is_subrequestcolumn tosystem.aggregated_zookeeper_logto separate standalone requests from sub-requests inside Multi/MultiRead requests. Previously, sub-requests were aggregated into the same buckets as standalone requests, and since each sub-operation was logged with the total multi-request duration, the average latency became misleading. Sub-requests now have zero latency. #99169 (Miсhael Stetsyuk). - Allow
ALTER TABLE MODIFY COLUMN x TTL ...command without specifying column type. #99208 (Nikolay Degterinsky). - Skip stale Keeper requests for sessions that have already disconnected, avoiding unnecessary Raft round-trips. The number of tracked finished sessions is capped by the
max_finished_sessions_cache_sizecoordination setting. #99246 (Antonio Andelic). - Support text index built on
mapValues(map)withINoperator. #99286 (Anton Popov). - Shell-like completion support in clickhouse keeper-client (handle completions of arguments in quotes, i.e.
'foo ba', handle escaped arguments, i.e.foo\ ba, makelsprint quoted nodes, if they have whitespaces). #99312 (Azat Khuzhin). - Prevent Keeper
mntrcommand from getting stuck because of lock contention. #99472 (Antonio Andelic). - Reduce lock contention in Keeper dispatcher by invoking callbacks and dispatching read requests outside mutex scope, and add profiled lock guards for observability. #99751 (Antonio Andelic).
- Tolerate missing padding at the end of the last block of parquet files. #99857 (Seva Potapov).
Bug Fix (user-visible misbehavior in an official stable release)
- Fixes how an Alias table target is saved as a DDL dependency when not fully qualified: it’s now saved with the Alias table database instead of the session database. #95175 (Enric Calabuig).
- Fix wrong result or exception during reading subcolumns of ALIAS columns. #95408 (Pavel Kruglov).
- Fix missing column when non-standard identifier alias in JOIN with old analyzer. Fixes #25594, #47288 and #53263. #95679 (Zhigao Hong).
- Fixes a crash in Kusto dialect functions
bin(),bin_at(),extract(), andindexof()when empty arguments are provided. #95736 (NeedmeFordev). - Forbids mounting local_object_storage (which is used by datalakes above local filesystem and maybe by LocalDisk) anywhere apart from user_files_path in clickhouse-client. #96201 (Daniil Ivanik).
- In
DeltaLaketable engine fix logical race on snapshot version change, remove redundant heavy snapshot reloads. #96226 (Kseniia Sumarokova). - Fix logical error on attaching a part in MergeTree if there were several chained renames between detaching and attaching. #96351 (Alexey Milovidov).
- Fix a bug where explicit settings sent alongside
compatibilityin the same request could be silently ignored when their value matched the server default. #97078 (Raufs Dunamalijevs). - Fix the client reporting
NETWORK_ERRORinstead of the actual parsing error (with the correct row number) when an INSERT with parallel parsing encounters invalid data. #97339 (Alexey Milovidov). - Fix
sumCountaggregate function not being able to read older serialized states after introduction ofNullable(Tuple). Closes #97370. #97502 (Nihal Z. Miaji). - Fix exception in tuple comparison involving
Nothingtype elements (e.g., comparing withNULLtuple elements) when used withGROUPING SETSandORDER BY. #97509 (Alexey Milovidov). - Fix non-deterministic
uncompressed_hashcomputation for Compact MergeTree parts when multiple compression codecs are used, which could cause incorrect deduplication behavior. #97522 (Alexey Milovidov). - Fix logical error about missing stream during INSERT SELECT with JSON and buckets in shared data. Closes #97331. #97523 (Pavel Kruglov).
- Fix
MEMORY_LIMIT_EXCEEDEDexceptions being incorrectly reported asCORRUPTED_DATAduring SummingMergeTree and CoalescingMergeTree merges. #97537 (János Benjamin Antal). - Fix “Context has expired” exception for correlated subqueries containing table functions like
url(). #97544 (Alexey Milovidov). - Fix exceptions and incorrect behavior in
optimize_syntax_fuse_functionswith aggregate projections, Date types, and column name preservation. #97545 (Alexey Milovidov). - Remove incorrect
replaceRegexpOnetoextractquery rewrite that produced wrong results when the regexp didn’t match; also fix exception whenreplaceRegexpOneis used withGROUP BY ... WITH CUBEandgroup_by_use_nulls=1. #97546 (Alexey Milovidov). - Fix
DROP DATABASEwithdatabase_atomic_wait_for_drop_and_detach_synchronouslyhanging indefinitely when the query is killed. #97586 (Alexey Milovidov). - Fix
KILL QUERYnot being able to terminate queries stuck inWITH FILLgeneration, dictionary loading viadictGet, orALTER DELETEwithmutations_sync=1onReplicatedMergeTree. #97589 (Alexey Milovidov). - The
looptable function was callinginner_storage->read()directly, bypassing the interpreter layer where row policies, column-level grants, and other security checks are applied. This allowed a user restricted by row policies to read all rows vialoop(table)even when a direct SELECT returned zero rows. #97682 (pufit). - Fixes incorrect partition pruning in cases of using pre-epoch DateTime64 with
toDate()function. #97746 (Yarik Briukhovetskyi). - After this patch,
hasPartitionIdwill return false if another partition with a higher partition ID exists in the data part set. #97748 (Mikhail Artemenko). - Fix possible crashes during reading of empty granules in advanced shared data in JSON. Closes #97563. #97778 (Pavel Kruglov).
- Fix
Cannot schedule a fileLOGICAL_ERRORonINSERTintoDistributeddue to race betweenDROPandINSERT. #97822 (Azat Khuzhin). - Fixed ClickHouse server crash/assert in call to
mapContainsKey/mapContainsKeyLikewithtokenbf_v1skip index. #97826 (Shankar Iyer). - Fix LOGICAL_ERROR exceptions caused by
LowCardinalityinside compound types (Variant,Dynamic,Tuple) inconcatWithSeparator,format,INsubqueries,GLOBAL IN, and joins with runtime filters. #97831 (Raúl Marín). - Fix
LOGICAL_ERRORexceptionChunk info was not set for chunk in MergingAggregatedTransformwhen usingARRAY JOINwithmerge()table function over multiple Distributed tables combined withGROUP BY. #97838 (Raúl Marín). - Fix server crash (
std::terminate) caused by an uncaught exception in the HTTP connection pool destructor when the connection group hard limit is reached under high concurrency. The exceptionHTTP_CONNECTION_LIMIT_REACHEDcould escape~PooledConnectionwhen recycling a connection back to the pool, leading toSIGABRT. #97850 (Antonio Andelic). - Fix incorrect result when
grace_hashalgorithm is used with non-equi joins and left block cannot be processed completely because of the size constraints on the join result. #97866 (János Benjamin Antal). - Fix performance inefficiency in DeltaLake metadata scanning introduced in #96686. #97880 (Kseniia Sumarokova).
- Fix data race in ZooKeeper client between sendThread and receiveThread. #97887 (Pablo Marcos).
- Fixes a bug where it was not possible to use CTE with distributed insert selects. Continuation of https://github.com/ClickHouse/ClickHouse/pull/87789. Closes #95837. #97889 (Yarik Briukhovetskyi).
- Fix exception from
CachedOnDiskReadBufferFromFile::readBigAt. Closes #97325. #97890 (Kseniia Sumarokova). - Fix
LOGICAL_ERRORexception inAliasengine with materialized columns due to column mismatch. Closes #97907. #97921 (Kai Zhu). - Fix Keeper data loss after restart when using Azure Blob Storage with
s3_plainmetadata for log storage. #97987 (Antonio Andelic). - Fix JIT miscompilation of
signfunction for integer types wider thanInt8— values outside the -128..127 range could produce incorrect sign. #98012 (Alexey Milovidov). - Fixed
DUPLICATE_COLUMNexception and silent NULLs when reading Delta Lake tables that use column mapping “name” mode with struct fields whose names contain dots (e.g.STRUCT<`a.foo`: STRING, `b.foo`: STRING>). #98013 (Caio Ishizaka Costa). - Fix mutation after lightweight update and secondary indices. #98044 (Raúl Marín).
- Fix incorrect result of FINAL queries when mixing primary key and non primary key skip indexes. #98097 (Raúl Marín).
- Enforce READ ON FILE checks for scalar file() and DESCRIBE TABLE file(). #98115 (Nikolay Degterinsky).
- Fixes a crash where querying files with a glob pattern (e.g.,
file('dir/**', 'LineAsString')) would throw an unhandled filesystem exception (STD_EXCEPTION) if the directory contained a dangling symlink. Dangling symlinks are now silently skipped, and the query returns results from all valid files. #98143 (Mark Andreev). - Fix segfault in query plan optimization when converting outer join to inner join with
arrayJoinin filter expression. #98147 (Alexey Milovidov). - Fix
ProtobufListformat not working with Kafka engine due to read state not being reset between messages. #98151 (Alexey Milovidov). - Fix logical error with analyzer_compatibility_join_using_top_level_identifier and ARRAY JOIN, closes #98164. #98179 (Vladimir Cherkasov).
- Set
Watchcomponent for watch responses inaggregated_zookeeper_loginstead of leaving it empty. #98202 (Antonio Andelic). - If the partition key columns are not covered by the sorting key, then partition pruning could incorrectly skip partitions containing rows that should “win” during FINAL deduplication. #98242 (Yarik Briukhovetskyi).
- Fix logical error “Bad cast from type DB::ColumnConst to DB::ColumnArray” in
kql_array_sort_asc/kql_array_sort_descwhen called with constant array arguments. #98251 (Alexey Milovidov). - Fix out-of-bounds access in
ColumnConst::getExtremesthat could cause a crash whenextremes = 1is enabled. #98263 (Alexey Milovidov). - Fix potential deadlock when two concurrent
MOVE PARTITIONoperations work with the same pair of tables in opposite directions. #98264 (Alexey Milovidov). - HTTP server now returns an error message in the response body for 400 Bad Request responses caused by malformed headers, instead of an empty body. #98268 (Alexey Milovidov).
- Fix wrong results with distributed index analysis (experimental feature) and query condition cache. #98269 (Azat Khuzhin).
- Fixed LOGICAL_ERROR exception “Invalid binary search result in
MergeTreeSetIndex” triggered bytoDateconversion on key columns with data crossing the 65535 boundary. #98276 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception when a RIGHT JOIN wrapped in a CROSS JOIN is swapped by thequery_plan_join_swap_tableoptimization in the legacy join step code path. #98279 (Alexey Milovidov). - Validate corrupted data during
DDSketchdeserialization to prevent segfaults, exceptions, infinite loops, and OOM when reading corruptedquantilesDDaggregate function states. #98284 (Alexey Milovidov). - Fix LOGICAL_ERROR “Trying to execute PLACEHOLDER action” when correlated columns from outer queries are referenced inside lambda functions such as
arrayMap. #98285 (Alexey Milovidov). - Fix logical error exception in
caseWithExpressionwhenCASEexpression involvesmaterialize(NULL)or otherNullable(Nothing)arguments. #98290 (Alexey Milovidov). - Fix bad cast exception when filtering
_tablevirtual column inmergetable function. #98291 (Alexey Milovidov). - Fix sporadic deduplication failure where re-inserts were incorrectly deduplicated due to inconsistent cleanup ordering between
blocks/anddeduplication_hashes/ZooKeeper directories. #98293 (Alexey Milovidov). - Fix exception when
ORDER BY ... WITH FILLis used together withLIMIT BY. #98361 (Alexey Milovidov). - Fix silent data corruption when inserting a Parquet/Arrow
Datecolumn into anEnumcolumn — now properly rejects the incompatible type conversion instead of storing invalid enum values. #98364 (Alexey Milovidov). - Fix exception when reading an Arrow file with
Arraycolumn into a table withNestedcolumn. #98365 (Alexey Milovidov). - Fix
MATERIALIZE INDEXandMATERIALIZE PROJECTIONmutations getting stuck when the index or projection is dropped before the mutation finishes. #98369 (Alexey Milovidov). - Fix exception when reading from
Nullable(Tuple(...))where a Tuple element name collides with the Nullablenullsubcolumn. #98372 (Alexey Milovidov). - Fix exception “Column … query tree node does not have valid source node” when joining a
Mergetable (wrapping aDistributedtable) with another table. #98376 (Alexey Milovidov). - Fix incorrect Parquet
BooltoFixedStringconversion in native V3 reader that produced raw bytes instead of string representation. #98378 (Alexey Milovidov). - Fix
tryGetColumnDescriptionto filter subcolumns by parent column kind, consistent with other column lookup methods. #98391 (Alexey Milovidov). - Accept base64 credentials without padding in HTTP Basic Auth. Some HTTP clients omit trailing
=padding in theAuthorization: Basicheader, which previously caused authentication failures. #98392 (Amos Bird). - Fix incorrect partition pruning results after merging parts with
Nullablepartition key columns, caused by wrong min-max index bounds. #98405 (Amos Bird). - Fix rare exception in the pipeline executor, that could manifest as a
Received signal 6(only in debug builds), when pipeline expansion races with query cancellation. #98428 (Alexey Milovidov). - Fix exception “Column identifier is already registered” when
count_distinct_optimizationis used with aQUALIFYclause. #98433 (Alexey Milovidov). - Fix exception “cannot be inside Nullable type” when using
IN/NOT INwithLowCardinalitycolumn arguments (e.g.a NOT IN (b)whereaisLowCardinality(String)). #98443 (Alexey Milovidov). - Fix “Pipeline stuck” exception in
full_sorting_mergejoins caused by a deadlock inPingPongProcessorwhen theFilterBySetOnTheFlyoptimization created a circular dependency withMergeJoinTransform. #98454 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception “Projection cannot increase the number of rows in a block” when merging parts with TTL that deletes all rows and an aggregate projection with a constantGROUP BYkey. #98458 (Alexey Milovidov). - Fix logical error exception when
CROSS JOINis used together withINNER JOIN USING. #98459 (Alexey Milovidov). - Fix null pointer dereference in
dictGetOrDefaultwhen the key argument isNullable. #98460 (Alexey Milovidov). - Fix exception in
DISTINCTqueries when using aggregate projections andmaterializecausesLowCardinalitytype differences between the query and the projection. #98462 (Alexey Milovidov). - Fix LOGICAL_ERROR exception when
arrayJoinis used in a filter expression with OUTER JOIN andjoin_use_nullsenabled. #98464 (Alexey Milovidov). - Fix logical error exception “Replica decided to read in WithOrder mode, not in ReverseOrder” when using parallel replicas with
optimize_aggregation_in_order. #98467 (Alexey Milovidov). - Fixed ClickHouse Keeper disconnecting Java ZooKeeper clients after
addWatchrequest. The Java client expects a 4-byteErrorResponsebody in theaddWatchresponse, but Keeper was sending an empty body, causingEOFExceptionand session disconnect. This broke Apache Curator’sCuratorCacheand any Java application using persistent watches. Fixes #98079. #98499 (Antonio Andelic). - Fix
zk_followersandzk_synced_followersKeeper metrics not decreasing when a follower goes down. Add newzk_learnersandzk_synced_non_voting_followersmetrics to themntrfour-letter-word command. Fixes #54173. #98504 (Antonio Andelic). - Fix a LOGICAL_ERROR exception in
renameAndCommitEmptyPartsthat could occur whenTRUNCATE TABLEruns concurrently withOPTIMIZE TABLEusing MergeTree transactions. #98508 (Alexey Milovidov). - Fixed Keeper’s secure raft port ignoring
cipherListanddhParamsFilefromopenSSLconfiguration, always using defaults instead of user-specified values. Close #51188. #98509 (Antonio Andelic). - Fixed misleading Keeper log messages like “Receiving request for session X took 9963 ms” where the reported time was actually spent waiting idle in
poll()between heartbeats, not performing the operation itself. Fixes #79026. #98510 (Antonio Andelic). - Fix unexpected result with read_in_order_use_virtual_row and monotonic functions, close #97837. #98514 (Vladimir Cherkasov).
- Fix
LOGICAL_ERROR: Not-ready Set is passed as the second argument for function 'in'when usingPREWHEREwithINsubquery on MergeTree tables. #98522 (Alexey Milovidov). - Fix Keeper TCP connections preventing graceful server shutdown by not responding to shutdown signal. #98525 (Alexey Milovidov).
- Fix exception “Sorting column wasn’t found in the ActionsDAG’s outputs” when
query_plan_convert_join_to_inis enabled withquery_plan_merge_expressions = 0. #98526 (Alexey Milovidov). - Fix MongoDB dictionary source failing with named collections. Closes #97840. #98528 (Pablo Marcos).
- Fixed LOGICAL_ERROR when Identifier is empty after parameter substitution. #98530 (Pervakov Grigorii).
- Fix pipeline deadlock when using
sort_overflow_mode = 'break'together with window functions. #98543 (Alexey Milovidov). - Fix column rollback in Buffer engine during handling an exception during appending a new block. Old logic could lead to corrupted in-memory state of columns. #98551 (Pavel Kruglov).
- Fixed exception
Bad cast from type ColumnConst to ColumnDynamicin null-safe comparison (<=>/IS NOT DISTINCT FROM) with constDynamicorVariantcolumns andNULL. Also fixedIS DISTINCT FROMwithDynamic/VariantvsNULLalways incorrectly returning 0. #98553 (Alexey Milovidov). - Fixed usage of the text index with other skip indexes. Previously, logical errors such as “Trying to get non-existing mark” could be thrown when a query filter utilized a text index and other regular skip indexes simultaneously. #98555 (Anton Popov).
- Fix logical error “TABLE_FUNCTION is not allowed in expression context” when a table function with an alias appears multiple times in the same query scope (e.g. in both
PREWHEREandQUALIFYclauses). #98557 (Alexey Milovidov). - Fix distributed index analysis with expressions (not just columns) in PK (leads to zero filtering of redundant granules on remote replicas). #98561 (Azat Khuzhin).
- Disallow dropping column when its subcolumns are used in other columns default/alias expressions and use analyzer for default expressions on alter drop column. #98569 (Nikita Mikhaylov).
- Fix S3 requests being incorrectly retried on non-retryable errors (including
HTTP_CONNECTION_LIMIT_REACHED) in the HTTP client. #98598 (Sema Checherinda). - Fixes a decimal overflow when partition pruning with DateTime64. #98628 (Yarik Briukhovetskyi).
- Fix two bugs in JIT expression compilation: a copy-paste error in
nativeCasttype checking that made integer-to-integer and float-to-float cast branches unreachable, and incorrectnullptrTargetMachine passed to LLVMPassBuilderpreventing target-specific optimization passes from being registered. #98660 (Alexey Milovidov). - Fix RBAC bypass that allowed users to DESCRIBE any table via
remote(),remoteSecure(),cluster(), orclusterAllReplicas()pointed at localhost, without requiringSHOW_COLUMNSprivilege. #98669 (pufit). - Fix
BAD_GETexception and incorrect query results when a non-boolean expression (e.g.sin(col)) is used in both WHERE and SELECT with a JOIN, due to filter push-down optimization corrupting shared DAG nodes. #98681 (Alexey Milovidov). - Fix LOGICAL_ERROR “Replica decided to read in Default mode, not in WithOrder” when using
read_in_order_through_joinwith parallel replicas. #98685 (Alexey Milovidov). - Fix exception “Bad cast from type
DB::TableFunctionNodetoDB::QueryNode” when usinginputtable function as an argument ofremote. #98694 (Alexey Milovidov). - Fix outdated data parts resurrection caused by incorrectly cleaning up empty covering parts. #98698 (Shaohua Wang).
- Fix exception in
LogicalExpressionOptimizerPasswhen a boolean function in anequalscomparison returns aVarianttype. #98712 (Alexey Milovidov). - Fix
parseDateTimeBestEffortincorrectly parsing words starting with month/weekday prefixes. Closes #97965. #98742 (Pavel Kruglov). - Fix
UNKNOWN_IDENTIFIERexception when queryingmerge()table function orMergeengine over tables with JSON columns that have different parameters (e.g. differentSKIPfields) and ALIAS columns referencing JSON sub-paths, with the new analyzer enabled. Closes #97812. #98753 (Pavel Kruglov). - Fix
optimize_skip_unused_shardsoptimization with the analyzer in caseDistributedstorage is used in aView. #98754 (Nikolai Kochetov). - Fix tuple subcolumn access by name (e.g.
SELECT x.aforTuple(a UUID, b Int32)) for external tables passed via--externalinclickhouse-client. Closes #96925. #98755 (Pavel Kruglov). - Fix
reverseUTF8exception on invalid (truncated) UTF-8 input. #98770 (Alexey Milovidov). - Fix detecting set skip index usefulness with OR with false (i.e. or(x, 0)) predicate. #98776 (Azat Khuzhin).
- Fix a
LOGICAL_ERRORexception (Block structure mismatch inremoveUnusedColumns) that could occur withFINAL+PREWHERE+ constantWHEREexpression + column-independent aggregates likecount(). #98778 (Alexey Milovidov). - Make
system.trace_logentries for ClickHouse dictionaries’ auto-reloads have non-empty query IDs. #98784 (Miсhael Stetsyuk). - Fixes a crash where we could de-reference a null pointer in system tables created between the time when we snapshot the tables in the
IDatabaseTablesIterator::table()call and the tables changing in another thread during later iteration. #98792 (Grant Holly). - Fix
SYSTEM START REPLICATED VIEWnot waking up the refresh task. #98797 (Pablo Marcos). - Fix exception “Inconsistent table names” when using
view()table function containing JOINs inside another JOIN (only with old analyzer). #98809 (Alexey Milovidov). - Fix adjusting RLIMIT_SIGPENDING (via pending_signals). #98829 (Azat Khuzhin).
- Fix exception when composing
loopwith cluster table functions. #98860 (Konstantin Bogdanov). - LEFT ANTI JOIN with multiple join key columns returned wrong results when
enable_join_runtime_filters=1(which is default). #98871 (Alexander Gololobov). - Fix
WITH FILL STALENESSproducing extra filled rows when data is read in multiple chunks (e.g., with smallindex_granularity). #98895 (Alexey Milovidov). - Fix “RPNBuilderFunctionTreeNode has A arguments, attempted to get argument at index B” LOGICAL_ERROR. #98900 (Azat Khuzhin).
- Fix memory tracking drift caused by failed allocations not being rolled back,
nallocx(0)undefined behavior, and off-by-one in global peak tracking. Extend tracking to coverio_uringring buffers. #98915 (Antonio Andelic). - Forbid attaching to local data lake tables outside user paths, not only creating them. #98936 (Daniil Ivanik).
- Fix a race condition that could cause a “ReadBuffer is canceled” exception in queries using
urlClusteror similar cluster table functions. #98955 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception in financial functions (financialNetPresentValue,financialInternalRateOfReturn, etc.) whenBFloat16type arguments are passed. #98958 (Alexey Milovidov). - Fix skip indexes (and primary key conditions) not being applied for ALIAS columns when query plan expression merging is disabled (query_plan_merge_expressions = 0 or query_plan_enable_optimizations = 0). #98960 (Peng).
- Increment
InsertQueryProfileEvent for async inserts. Closes #98626. #98962 (Narasimha Pakeer). - Fix exception “Inconsistent KeyCondition behavior” in debug builds when primary key contains NaN float values, by making
accurateLessandaccurateEqualshandle NaN consistently with ClickHouse sort order. Closes #98075. #98964 (Alexey Milovidov). - SummingMergeTree no longer sums Bool (and other domain type) columns. Bool values are kept as-is instead of being arithmetically summed. #98976 (Yash ).
- Fixes an exception Scalar doesn’t exist that occurred when querying a remote shard with
optimize_const_name_sizeset andenable_scalar_subquery_optimization= 0. Large constants replaced with__getScalarreferences in the remote query were not being sent to the shard, causing the query to fail. #98979 (andriibeee). - Fix
NOT_FOUND_COLUMN_IN_BLOCKfor some queries withGROUP BYand expressions that include inverse dictionary lookup,Date/DateTimeconversion comparisons, and tuple comparisons. Closes #98888. #98980 (Nihal Z. Miaji). - Fixed undefined behavior (null pointer dereference) when altering a version/sign/is_deleted column to
EPHEMERALorALIASin MergeTree engines. Such alterations are now properly rejected. #98985 (Alexey Milovidov). - Fixed an issue where
system.grantsomitted the regular expression parameters forURLandS3grants in theaccess_objectcolumn. #98987 (DQ). - Fixed Iceberg BigLake reads: ADC credentials are now forwarded to the GCS S3 client (fixing 403 errors), OAuth2 credentials are URL-encoded before sending (fixing auth failures for tokens with special characters), and namespace traversal no longer aborts on BigLake HTTP 400 responses. #98998 (Nikita Fomichev).
- Fixed
clickhouse-clientfailing to switch timezone whenTZenvironment variable uses POSIX file path syntax (e.g.TZ=:/etc/localtime). #99000 (Yash ). - Fix incorrect or less pruning when
startsWith,LIKE,NOT LIKEused withFixedStringcolumn. Additionally,FixedStringtoStringcast function can now prune granules when wrapped around key column. Closes #98940. #99001 (Nihal Z. Miaji). - Fixed
windowFunnelwithstrict_deduplicationreturning incorrect level when a duplicate event was encountered. #99003 (Yash ). - Fixes a bug where EXISTS would ignore LIMIT and OFFSET clauses in subqueries, causing incorrect results when the subquery returned no rows due to an offset or a zero limit. Closes #88722. #99005 (andriibeee).
- Fix “Block structure mismatch” exception when filter push-down optimization encounters an AND expression that short-circuits to a constant with
GROUPING SETS. #99010 (Alexey Milovidov). - Fix exception when reading patch parts (lightweight updates) without
_part_offsetcolumn in the query plan. #99023 (Alexey Milovidov). - A query like
SELECT * FROM table WHERE pk_id = ''wherepk_idis the primary key and ofStringtype will now correctly use the primary key index for filtering granules. #99027 (Shankar Iyer). - Fix
DEPENDENCIES_NOT_FOUNDexception in Kafka engine when materialized view is detached while the background thread is streaming data. #99028 (Alexey Milovidov). - Fix exception when creating a table with an
EPHEMERALcolumn that has the same name as a virtual column (e.g.,_part_offset). #99031 (Alexey Milovidov). - Fix misleading “inflate failed: buffer error” when reading non-existent compressed files via
url()table function with glob patterns. Now returns empty result as expected whenhttp_skip_not_found_url_for_globsis enabled. #99034 (Alexey Milovidov). - Fix server crash (std::terminate) when executing
ALTER TABLE ... DROP PARTon a patch part after a schema change (e.g. ADD COLUMN). The crash was caused by missing system columns (_part) in the empty coverage part metadata, leading to an uncaught exception inside a NOEXCEPT_SCOPE. #99036 (Peng). - ClickHouse server process could crash if there was a memory limit exceeded exception thrown during a cached disk read. That is now fixed. #99042 (Shankar Iyer).
- Fix
LOGICAL_ERRORwhen querying a table that has both a ROW POLICY and an ALIAS column usingdictGet. The issue was caused by premature access to the table expression during ALIAS column resolution in the new analyzer. #99065 (Peng). - Fix out of bounds error when user tries to query only virtual columns from Iceberg table with Avro format for data. It’s super rare scenario so not marking it as critical. Fixes #88238. #99080 (alesapin).
- Fix segfault in recursive CTE with
remote()+view(). #99081 (Konstantin Bogdanov). - Skip unnecessary extra index analysis when read-in-order optimization is applied. #99084 (Vladimir Cherkasov).
- Fixed a crash triggered by a memory limit exception thrown during patch part application. #99086 (Anton Popov).
- Fix debug assertion in
DDLWorkercaused by stalefirst_failed_task_nameafter a ZooKeeper entry is deleted during reinitialization recovery. #99099 (Antonio Andelic). - Fixed rebuild of text indexes on merges with TTL. #99107 (Anton Popov).
- Fix crash in
ALTER TABLE ... REMOVE SETTINGSquery for Iceberg table engine. Fixes #86330. #99108 (alesapin). - Fixes a bug in
query_plan_convert_any_join_to_semi_or_anti_joinoptimization, returning an incorrect result for unmatched rows. Related: https://github.com/ClickHouse/ClickHouse/pull/95995. #99112 (Yarik Briukhovetskyi). - Fix LOGICAL_ERROR exception in
ASTColumnsExceptTransformer::transform. #99119 (Pablo Marcos). - Fix RBAC bypass that allowed users to obtain table structure via
DESCRIBE TABLEorCREATE TABLE ASon table functions (mysql(),postgresql(),sqlite(),arrowFlight(),jdbc(),odbc(), etc.) without the required source access privileges. For functions that infer schema from remote servers, this also allowed triggering outbound connections (SSRF) without authorization. #99122 (pufit). - Fix Keeper crash (segfault in NuRaft) during dynamic reconfiguration and leadership transfer. #99133 (JIaQi Tang).
- Fix crash on usage of Buffer table with SAMPLE when destination does not support it. #99141 (Kseniia Sumarokova).
- Fix LOGICAL_ERROR due to patch parts column order mismatch. #99164 (Pablo Marcos).
- Fix very rare crash when Iceberg table contains files of mixed format (ORC and Parquet). Fixes #88126. #99168 (alesapin).
- Fix max_execution_time not being applied for backup/restore. #99205 (Kseniia Sumarokova).
- Fix
insert_deduplication_tokenbeing silently ignored forINSERT SELECTqueries withoutORDER BY ALL. Previously, deduplication was disabled entirely for unsortedINSERT SELECT, even when an explicit user token was provided. Now, providinginsert_deduplication_tokenis sufficient to enable deduplication regardless ofORDER BY ALL. #99206 (Desel72). - Fix excessive access checks during
InverseDictionaryLookupPassoptimization by checkingCREATE_TEMPORARY_TABLEgrant once before the pass instead of for every visited node. #99210 (Mikhail Artemenko). - Fix
clickhouse format --obfuscateproducing invalid SQL by obfuscating skip index types, compression codec names, database engine names, and dictionary layout/source definitions. #99260 (Raúl Marín). - Fixed a bug where, in some cases, comparing between Time[64] and DateTime[64] types was confusing; now, in cases like this, Time[64] values are promoted to DateTime[64] by adding the
1970-01-01as a date part. #99267 (Yarik Briukhovetskyi). - Clamp settings constraints in DDL worker for distributed DDL queries. #99317 (Pablo Marcos).
- Fix minor issues with TOTP authentication: the
--one-time-passwordCLI option with empty password, validation of<digits>and<period>configuration values. #99322 (Vladimir Cherkasov). - Fix logical error
unordered_map::at: key not foundin Avro output format when serializingEnum8/Enum16columns with values not present in the enum definition. #99332 (Desel72). - Fix CHECK TABLE with sparse serialization inside Tuple with Dynamic. Closes #96588. #99351 (Pavel Kruglov).
- Fixed too strict validation of text index preprocessor. #99359 (Anton Popov).
- Fix compatibility when upgrading replicated tables with implicit minmax indices from 25.10 to newer versions. #99392 (Raúl Marín).
- Removed support for negated functions (
notEquals,notLike,notIn) in text index analysis. These functions could never skip any granules, so analyzing the index for them only added overhead without any benefit. #99393 (Anton Popov). - Fix
optimize_skip_unused_shardswith a new analyzer for the case when aDistributedtable was used inside an IN subquery. #99436 (Nikolai Kochetov). - Fix heap-use-after-free in
INTERSECT/EXCEPTwhen the query produces duplicate column names. #99471 (Alexey Milovidov). - Fix logical error in
ALTER TABLE ... DROP PARTwhen a typed query parameter is used for the part name. #99489 (Alexey Milovidov). - Fixed
NOT_FOUND_COLUMN_IN_BLOCKexception when a text index predicate (e.g.hasAllTokens) is referenced in bothSELECTandWHEREclauses via an alias. #99504 (Anton Popov). - Fix incorrect results when using
hasAllTokenswith OR across columns that have separate text indexes. #99505 (Anton Popov). - Initialize page cache in
clickhouse-localso thatpage_cache_max_sizesetting takes effect. #99510 (Alexey Milovidov). - Fixed rare incorrect marking of a data part as broken and detaching it after
DETACH/ATTACH TABLEquery. #99529 (Anton Popov). - Fix
std::length_errorexception when querying empty system tables with Pretty format via HTTP interface. #99541 (Alexey Milovidov). - Fix
LOGICAL_ERRORwhen usingALTER TABLE ADD COLUMNto create anEPHEMERALcolumn with the same name as a virtual column (e.g._part_offset). #99549 (Alexey Milovidov). - Fix
VectorSimilarityIndexCacheentries never being evicted after part removal due to mismatched cache keys. #99575 (Seva Potapov). - Forbid reading Google credentials from a local file. This setting is insecure because it allows reading other credentials if the file path is known. #99584 (Konstantin Vedernikov).
- Fix performance degradation in the analyzer. Prune unused columns from ARRAY JOIN. #99587 (Dmitry Novik).
- Fixed reading of text index in table with existing lightweight deletes and row policies. #99661 (Anton Popov).
- Fix nullptr dereference in Parquet reader when filter-in-decoder path encounters filtered-out pages. Closes #99676. #99677 (Alexey Milovidov).
- Fix incorrect seek in AsynchronousReadBufferFromFileDescriptor with O_DIRECT. Closes #99358. #99678 (Pavel Kruglov).
- Fixed heap-buffer-overflow in
CompressionCodecT64and process abort inCompressionCodecMultiplewhen decompressing malformed compressed data. Both issues were found by new libFuzzer targets. The codecs now throw an exception instead of crashing. #99680 (Rahul). - Delay processing until server has finished loading all the tables. #99700 (Seva Potapov).
- Fix MySQL dictionary source bypassing
RemoteHostFilterfor inline DDL params. #99720 (Shaohua Wang). - Fix logical error when iterating over data lake tables in
system.tables. #99739 (Konstantin Vedernikov). - Fixed analysis of predicates with the
INfunction by text index with the preprocessor. Fixed the collision of searched tokens in the text index, which could lead to incorrect results. #99755 (Anton Popov). - Fix infinite loop when reading
Npyformat files with negative shape dimensions. #99812 (Desel72). - Fix global-buffer-overflow in
CRC32function onFixedStringarguments when evaluated with zero rows during query plan header computation. #99835 (Alexey Milovidov). - Fix crash (null pointer dereference) when executing
ALTER TABLE ... MODIFY COLUMN ... COMMENTon Iceberg tables. #99838 (Desel72). - Fix
aggregate_functions_null_for_emptysetting to work with aggregate functions returning non-Nullable types such asArrayorMap(e.g.,groupArray,sumMap). #99839 (Alexey Milovidov). - Fix LOGICAL_ERROR exception in
midpointfunction when called with mixed signed/unsigned integer types. #99867 (Alexey Milovidov). - Fix “Block structure mismatch” exception in queries with HAVING clause where the filter expression contains both an aggregate wrapped in a NULL-producing function and
materialize(0). #99915 (Alexey Milovidov). - Fix assertion failure in
sipHash128Keyed(and similar keyed hash functions) when the data argument is a Map with array keys or other nested array types. #99921 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception “Not-ready Set” inINfunction during query plan optimization withconvertAnyJoinToSemiOrAntiJoin. #99939 (Alexey Milovidov).
Build/Testing/Packaging Improvement
- Reduce compilation time by removing heavy header includes and moving expensive template instantiations out of headers. #97893 (Raúl Marín).
- Reduce compile time of arithmetic functions and related headers by shrinking template dispatch matrices and removing heavy includes. #98204 (Raúl Marín).
- Use
mongo-c-driver2.2.2. #98304 (Konstantin Bogdanov). - Use
postgresREL_18_3. #98306 (Konstantin Bogdanov). - Enable jemalloc allocator for UBSan builds to avoid RSS accumulation from glibc malloc’s poor memory reclamation behavior. #98444 (Alexey Milovidov).
- Use Rust v0 symbol mangling and strip internal symbols from PRQL library to reduce symbol name bloat from parser combinator libraries. #98446 (Alexey Milovidov).
- Add TPC-H benchmark suite and TPC-DS README to
tests/benchmarks. #98495 (Raufs Dunamalijevs). - Add correctness tests for all 99 TPC-DS queries. #99204 (Raufs Dunamalijevs).
- Add integration test reproducing DDL CREATE TABLE + ALTER with offline replica bug (#44070), marked as expected failure. #99259 (Raufs Dunamalijevs).
- Integrate jemalloc with
je_prefix and remove usage of linker’s--wrap. #99342 (Azat Khuzhin).
ClickHouse release 26.2, 2026-02-26. Presentation, Video
Backward Incompatible Change
- Deduplication is turned ON for all inserts by default. It was OFF before for async inserts and for MV’s, but it was ON for sync inserts. The goal is to have the same defaults for both ways of inserts. If you have deduplication explicitly disabled on your cluster, you have to explicitly set
deduplicate_insert='backward_compatible_choice'to keep the old behavior. The same withdeduplicate_blocks_in_dependent_materialized_views. #95970 (Sema Checherinda). - Improved storage format of statistics. All statistics are now stored in a single file. #93414 (Anton Popov). If you didn’t explicitly enable table statistics, you can ignore this item.
- Limit S3(Azure)Queue in-memory metadata. System tables are renamed from
azure_queuetoazure_queue_metadata_cacheandsystem.s3queuetos3queue_metadata_cache. #95809 (Kseniia Sumarokova). - Previously, applying a function to a
Variantcolumn silently returned NULLs when a variant sub-type was incompatible with the function; now it throws an exception, which may break queries that relied on the silent NULL behavior. #95811 (Bharat Nallan). DATEcolumns from PostgreSQL are now inferred asDate32in ClickHouse (in previous versions they were inferred asDate, which led to overflow of the values outside of a narrow range). Allow insertingDate32values back to PostgreSQL. Closes #73084. #95999 (Alexey Milovidov).- The semantics of the
do_not_merge_across_partitions_select_finalsetting were made more obvious. Previously, the feature could be automatically enabled when the setting was not explicitly set in the configs. It caused confusion repeatedly and, unfortunately, led to some issues in production. Now, the rules are simpler:do_not_merge_across_partitions_select_final=1enables the functionality unconditionally. Ifdo_not_merge_across_partitions_select_final=0, then automatic is used only if the new settingenable_automatic_decision_for_merging_across_partitions_for_final=1and not used otherwise. To preserve the old behaviour as much as possible, the defaults were set todo_not_merge_across_partitions_select_final=0andenable_automatic_decision_for_merging_across_partitions_for_final=1. #96110 (Nikita Taranov). - When creating an S3 table with explicitly specified columns, ClickHouse now validates that those column names actually exist in the remote file’s schema. Queries that previously worked with mismatched column names will now fail at table creation time. This closes #96089. #96194 (Konstantin Vedernikov).
- Forbid using subqueries in ORDER BY and other table key expressions. #96847 (Alexey Milovidov).
- Enable
apply_row_policy_after_finalby default. Initially, whenoptimize_move_to_prewhere_if_final=0, both ROW POLICY and PREWHERE respect FINAL and were applied after FINAL. This was broken by #87303, which ignored theoptimize_move_to_prewhere_if_finalfor the ROW POLICY filter. To fix this, this PR enables the settingapply_row_policy_after_finalintroduced in #91065. Withapply_row_policy_after_finalenabled, ROW POLICY would continue to respect FINAL by default, as previously. This PR is an incompatible change because it changes the behaviour foroptimize_move_to_prewhere_if_final=1. Now, to get the ROW POLICY applied before FINAL,apply_row_policy_after_finalshould be used instead ofoptimize_move_to_prewhere_if_final. #97279 (Nikolai Kochetov). - The
Datetype is now serialized as Arrow’s nativedate32type in Arrow/ArrowStream formats, instead ofuint16. Tools like PyArrow will now correctly see the column as a date type. The old behavior can be restored with theoutput_format_arrow_date_as_uint16setting. Reading old Arrow files that useduint16forDatecolumns is still supported. #96860 (Alexey Milovidov).
New Feature
- Users can now use ClickStack (an observability UI) directly from ClickHouse, useful for debugging and local development. #96597 (Aaron Knudtson).
- Support time-based one-time password (TOTP) as an authentication method. #71273 (Vladimir Cherkasov).
- Add
lazy_load_tablesdatabase setting. When enabled, tables are not loaded during database startup — a lightweightStorageTableProxyis created instead and the real table engine is materialized on first access. #96283 (xiaohuanlin). - Added
input_format_max_block_wait_mssetting to emit data blocks by timeout and allowed processing of remaining data when an HTTP connection is closed unexpectedly. #94509 (Mostafa Mohamed Salah). - Google BigLake catalog integration. This closes #95339. #97104 (Konstantin Vedernikov).
- Added system table
system.tokenizerswhich shows all available tokenizers. #96753 (Robert Schulze). - Add new system table
system.user_defined_functionsto monitor UDF loading status and configuration. #90340 (Xu Jia). - Add
system.jemalloc_statstable exposing jemalloc memory allocator statistics (viamalloc_stats_print) for diagnosing memory usage on servers built with jemalloc. Also add a/jemalloc.htmlHTTP endpoint on the ClickHouse HTTP interface for interactive visualization of these statistics. #97077 (Antonio Andelic). - Added
system.jemalloc_profile_texttable for reading and analyzing jemalloc heap profiles. The output format is controlled by thejemalloc_profile_text_output_formatsetting (raw, symbolized, or collapsed; default collapsed). Inline frame resolution is controlled byjemalloc_profile_text_symbolize_with_inline(when enabled, inline frames are included at the cost of slower symbolization; when disabled, they are skipped for faster output). For the collapsed format,jemalloc_profile_text_collapsed_use_countcontrols whether stacks are weighted by live allocation count (true) or live bytes (false, default). This enables easier memory profiling and flame graph visualization of jemalloc heap profiles. Fixes #93248. #97218 (Antonio Andelic). - Add the
default_dictionary_databasesetting, which lets ClickHouse resolve external dictionaries referenced without a database qualifier in a specified default database. This simplifies migration from XML-defined global dictionaries to SQL-defined per-database dictionaries—allowing existing dictionary queries (e.g. dictGet(‘name’, …)) to continue working without modification. #91412 (Dmitrii Plotnikov). - Support auxiliary zookeeper for
DatabaseReplicated. #91683 (RinChanNOW). - Implement new table function
primesand new system tablesystem.primesthat contains prime numbers in ascending order. Closes #90839. #92776 (Nihal Z. Miaji). - Async inserts support parallel quorum. The inserted data is replicated to the quorum. If duplicates are found, query waits until previously inserted data is replicated as well. #93356 (Sema Checherinda).
- Added functions
colorOKLABToSRGB,colorSRGBToOKLABto convert value from sRGB to OKLAB and vice versa. #93361 (Pranav Tiwari). - A new
deduplicate_insertsetting which overridesinsert_deduplicateandasync_insert_deduplicate. #94413 (Sema Checherinda). - Server setting
insert_deduplication_versionmakes it possible to migrate on unified deduplication hash. #95409 (Sema Checherinda). - Add
xxh3_128hashing function. #96055 (Raúl Marín). - Added
OPTIMIZE <table> DRY RUN PARTS <part names>query to simulate merges without committing the result part. It may be useful for testing purposes: verifying merge correctness in the new version, deterministically reproducing merge-related bugs, and reliably benchmarking merge performance. #96122 (Anton Popov). - Add a new check enabled by default via setting
check_named_collection_dependenciesto avoid dropping named collections used by tables. #96181 (Pablo Marcos). - Added
system.fail_pointsto inspect existing failpoints in the server and whether they are enabled or not. This is going to help automate testing. #96762 (Pedro Ferreira). - Add role-based access to Glue catalog. Use settings
aws_role_arnand, optionally,aws_role_session_name. #90825 (Antonio Andelic). - Added a setting
add_minmax_index_for_temporal_columnsthat, when enabled, automatically creates minmax indexes for allDate,Date32,Time,Time64,DateTime, andDateTime64columns. #93355 (Michael Jarrett). - Support for extended table aliases for JOINs (queries like
SELECT * FROM (SELECT 1) AS t(a) JOIN (SELECT 1) AS u(b) ON a = b). Closes #95131. #95331 (Yarik Briukhovetskyi). - Added support for
ALTER TABLE RENAME COLUMNfor Iceberg tables. Previously onlyADD COLUMN, DROP COLUMN, and MODIFY COLUMNwere supported. #97455 (murphy-4o).
Experimental Feature
- The text index is now GA. #96794 (Robert Schulze).
- The
QBitdata type for quantized bit-packed vector storage (used for approximate nearest-neighbor search) is now generally available and no longer requires enabling an experimental setting. #95358 (Raufs Dunamalijevs). - Vector search in ClickHouse can now use replicas in the cluster to distribute the load and search of vector index parts. This enables ClickHouse to support large vector indexes that exceed the memory capacity of a single VM. #95876 (Shankar Iyer).
- Add server-side AST fuzzer controlled by
ast_fuzzer_runsandast_fuzzer_any_querysettings. When enabled, the server runs randomized mutations of each query after its normal execution, discarding the results. #97568 (Alexey Milovidov). - Add
iiffunction to the experimental KQL dialect. #94790 (happyso). - Schema inference now respects
allow_experimental_nullable_tuple_type. When enabled, it allows inferred tuple types to beNullable(Tuple(...)), so missing nested objects can becomeNULLinstead of a tuple ofNULLelements. #95525 (Nihal Z. Miaji). - The
use_statistics_cachesetting is now enabled by default, so column statistics are cached in memory to speed up query optimization without needing to reload them from each part. #95950 (Han Fei).
Performance Improvement
- Allow any deterministic expression in Primary Key to be used for data skipping (e.g.
ORDER BY cityHash64(user_id)/ORDER BY length(user_id)). For deterministic expressions, ClickHouse can apply the expression to query constants and use the result in the primary key index for predicates like=,IN, andhas. If the expression is also injective (e.g.ORDER BY hex(p)orORDER BY reverse(tuple(reverse(p), hex(p)))), we can effectively use the index for the negated forms:!=,NOT IN, andNOT has. Closes #10685. Closes #82161. #92952 (Nihal Z. Miaji). - Improved storage format of statistics. All statistics are now stored in a single file. #93414 (Anton Popov).
- Allow parallelized read for remote table engines/functions in the filesystem cache. #71781 (Kseniia Sumarokova).
- Allow using userspace page cache with local files and object storage table functions. #77874 (Michael Kolupaev).
- Avoid unnecessary memcpy in userspace page cache. #77884 (Michael Kolupaev).
- The default for
concurrent_threads_scheduleris nowmax_min_fairinstead offair_round_robin. This improves fairness under high load by prioritizing queries with fewer allocated slots, so short-running queries aren’t penalized by long-running ones. #95300 (Sergei Trifonov). - If a
FINALquery used primary key condition for filtering followed by skip indexes for other conditions, thePrimaryKeyExpandprocessing step will now only check the initial shortlisted primary key ranges for intersection. #94903 (Shankar Iyer). - When using parallel replicas with table functions like
s3(...), queries with a single subquery wrapping the table function are now automatically parallelized across replicas, whereas previously only direct table function references were parallelized. Closes #92264. #96332 (phulv94). - Enable splitting data and system files in cache into separate segments. #87834 (MikhailBurdukov).
- Speed up some hash join operations by implementing dynamic dispatch for
ColumnVector::replicate. #79573 (Raúl Marín). - Performance improvement for parallel hash join in cases of complex predicates. Previously, we were processing non-joined rows in one thread, which is suboptimal the idea of the optimization is to parallelize the processing of the non-joined rows across multiple threads. Can be toggled by the
parallel_non_joined_rows_processingsetting. Enabled by default. #92068 (Yarik Briukhovetskyi). - Slightly optimize parsing of JSON type. #93614 (Pavel Kruglov).
- Improve memory footprint of AST. Optimization makes sense as fields are not used when highlighting is not used and there is no VALUES parsing. #93974 (Ilya Yatsishin).
- Optimize memory consumption of named Tuple AST objects. Place column names as strings in tuple object instead of having them in generic AST literal nodes. #94704 (Ilya Yatsishin).
- Devirtualization is improved with additional linker options. #94737 (Nikita Taranov).
- Improve clone replica performance for ReplicatedMergeTree tables with many parts by batching ZooKeeper requests. #94847 (c-end).
- When read step already has PREWHERE filters a new filter couldn’t be added. This change postpones PREWHERE optimization until after JOIN runtime filter optimization so that runtime filters can be also pushed to PREWHERE. #95838 (Alexander Gololobov).
- Speedup
T64codec compression by using dynamic dispatch on x86. #95881 (Raúl Marín). - Speed up
uniqover numeric types by batching inserts when possible (not null, not -If, no GROUP BY, no IPv6 or String). #95904 (Raúl Marín). - Low-level optimizations for Keeper:
ZooKeeper::observeOperationshas been found to account for >20% of the ZooKeeper receive thread CPU consumption. This change addresses that by: 1. ForAggregatedZooKeeperLog::stats, useCityHash64instead ofSipHashwhich is >10x faster. 2. ForCoordination::ErrorCounter, usestd::array<std::atomic<UInt32>, N>instead ofstd::unordered_mapandstd::mutex. #95962 (Miсhael Stetsyuk). - Remove 64-byte alignment for ProfileEvents::Counter to save memory. #96097 (Azat Khuzhin).
- Memory optimization: trim size of
CachedOnDiskReadBufferFromFilestructure 50x. #96098 (Azat Khuzhin). - Don’t copy old data on hash table resizing if it’s empty. #96180 (Raúl Marín).
- Support JOIN runtime filters for
RIGHT OUTERJOINs. #96183 (Hechem Selmi). - The optimization
enable_join_runtime_filtersis now the default. #89314 (Alexey Milovidov). - Previously, text index direct read optimization was applied only when all parts had a materialized text index. This PR adds partial support: if some parts have a materialized text index, those parts will use it, while parts without a materialized text index will fall back to executing the original filter expression. #96411 (Anton Popov).
- Added
minmaxsecondary indexes on time columns andbloom_filterindexes onquery_id/initial_query_idcolumns to system log tables for faster filtering. #96712 (Alexey Milovidov). - Lazy materialization optimization is now applied to all branches of a
UNION ALLquery, not just the first one. Queries that combine multiple sorted and limited reads from differentMergeTreetables viaUNION ALLwill now benefit from deferred column reading on every branch, reducing I/O. #96832 (Federico Ginosa). - Optimize minmax skip index computation during INSERT by removing an unnecessary data copy and enabling vectorized min/max calculation for numeric columns. #97392 (Raúl Marín).
- Storage
DeltaLakenow takescount()result from delta lake metadata and shows correct table stats in system.tables (total bytes/rows). #96190 (Kseniia Sumarokova). - The unused columns are removed also from the reading step in case of reading from a MergeTree. It is especially useful when a filter is pushed down into
PREWHERE. #89982 (János Benjamin Antal). - Improved processing
SHOW TABLESquery by fetching only names of tables and improved getLightweightTablesIterator to return structure containing only table names. resolves #93835. #94467 (Smita Kulkarni). - Improve
assumeNotNull,coalesce,ifNullto enable primary key and skip index pruning for range predicates when key columns are wrapped in these functions. Closes #94689. #94754 (Nihal Z. Miaji). - Add with_data & with_stat extension to getChildren Keeper request. This allows fetching not only the list of children, but also their
statand/ordatain a single operation. #94826 (Nikolay Degterinsky). - The index analysis is done only once (in most cases) regardless of whether we end up executing a local plan or a plan with parallel replicas. #94854 (Nikita Taranov).
- Allow to enable distributed index analysis based on amount of parts (
distributed_index_analysis_min_parts_to_activate) and indexes size (distributed_index_analysis_min_indexes_size_to_activate). #95216 (Azat Khuzhin). - Enable PREWHERE optimization for Iceberg tables. #95476 (Konstantin Vedernikov).
- Reduce the memory footprint of some AST classes. #95514 (Raúl Marín).
- Limit the number of pipeline streams generated with
split_intersecting_parts_ranges_into_layersenabled. Helps to avoid excessive memory consumption. #96478 (Nikita Taranov). - Implement equivalent sets optimization for multiple joins. Queries with multiple consecutive
INNER JOINoperations now benefit from improved filter pushdown optimization. When tables are joined on equivalent columns (e.g.,t1 JOIN t2 ON t1.id = t2.id JOIN t3 ON t2.id = t3.id WHERE t1.id > 10), filters applied to any table in the chain are automatically pushed down to all tables. Close #96550. #96596 (Vladimir Cherkasov). - Optimize delta lake metadata scan. Uses changes from delta-kernel PR https://github.com/delta-io/delta-kernel-rs/pull/1827. #96686 (Kseniia Sumarokova).
- In Replicated database, don’t update the cached cluster for every dummy query. #96897 (Tuan Pham Anh).
- Use the primary key index when filtering with
startsWithUTF8if the prefix contains only ASCII characters. #97055 (vkcku).
Improvement
- Add OpenTelemetry tracing for Keeper requests. #91332 (Miсhael Stetsyuk).
- New configuration options:
logger.startup_console_level&logger.shutdown_console_levelto allow for overriding the console log level during the startup & shutdown of ClickHouse respectively. #95919 (Garrett Thomas). - Respect command-line overrides when reloading configuration. Closes #80294. #80295 (Alexey Milovidov).
- Allow key-value overrides for named collection parameters in
mongodbtable function. #89616 (vanchaklar). - The read-in-order optimization for Iceberg tables now works with complex sorting functions like
icebergBucketandicebergTruncate, not just simple column references. #90256 (Konstantin Vedernikov). - Add a new column named parts_postpone_reasons in system.mutations to improve diagnostics, which shows the parts postpone reasons. #92206 (Shaohua Wang).
- Track changes in the number of rows to read (due to inserts/deletes or query condition cache usage) in
DataflowStatisticsCache. #93636 (Nikita Taranov). - Support SYSTEM RESET DDL WORKER [ON CLUSTER] query. It requests to reset the state of DDLWorker in its main thread. It is helpful to refresh the replica active when host IDs are updated. #93780 (Tuan Pham Anh).
- Support
mutation_idsinsystem.part_logfor event type ofMUTATE_PARTandMUTATE_PART_START. #93811 (Shaohua Wang). - Background operations (Mutate, Merge) can now be configured independently via ‘background’ profile. Previously such operations shared settings with regular queries via ‘default’ profile. #93905 (Arsen Muk).
- Add more information to
system.crash_log. #94112 #95857 (Miсhael Stetsyuk). - Added new
QueryNonInternalmetric to track the number of executing non-internal queries. This metric is exposed asClickHouseMetrics_QueryNonInternaland helps operators monitor query concurrency against themax_concurrent_querieslimit, which only applies to non-internal queries. #94284 (Ashwath Singh). - Support input bytes statistics collection for columns from compact parts in
RuntimeDataflowStatisticsCacheUpdater. #94626 (Nikita Taranov). - Add a check for Keeper misconfiguration leading to cluster assembly failures. Closes #60932. #94682 (Konstantin Bogdanov).
- Improve JSON prefixes deserialization during part loading. #94848 (Pavel Kruglov).
- Refactor the write using full INSERT pipeline, which triggers materialized views on the target table. #94890 (Kai Zhu).
- Use vector similarity search plan optimizations only if the index exists for the search column. #94998 (Eduard Karacharov).
- Check for the total memory limit before the user authentication and throw
(total) memory limit exceededif the total limit is more than allowed. #95003 (Nikolai Kochetov). - Added the
throw_on_unmatched_row_policiesconfiguration option which, when enabled, throws an exception if a user queries a table that has row policies but none of them apply to that user — preventing the ambiguous behavior of returning all rows due to access control misconfiguration. #95014 (Vitaly Baranov). - Dynamic update s3 access tokens in long queries with unity catalog. This closes #93981. #95069 (Konstantin Vedernikov).
- Disable jemalloc’s dirty page decay if ClickHouse is under sustained memory pressure for
memory_worker_decay_adjustment_period_msmilliseconds. Enable jemalloc’s dirty page decay back if ClickHouse is working under normal conditions for same amount of time. #95145 (Antonio Andelic). - S3Queue auxiliary Zookeeper support using
keeper_pathsetting from s3Queue. #95203 (Diego Nieto). - Respect
max_parts_to_merge_at_oncein TTL drop part merges. #95315 (Kseniia Sumarokova). - Add
connection_addressandconnection_portto query_log to reflect physical connection (addressandportare replaced when connected through proxy and auth_use_forwarded_address=1). #95471 (Yakov Olkhovskiy). - Fix incorrect memory accounting for the query conditions cache. The key problem was that it didn’t take into account the cache key that composed of several strings (like part_name, the table id and the whole SQL condition). #95478 (Nikita Mikhaylov).
- Server started with the embedded configuration will allow to manipulate users and grants, saving them to the
accessdirectory, as the regular configuration does. This improves testing. Also enabled all access_control_improvements in the embedded config and in clickhouse-local. #95481 (Alexey Milovidov). - Improved S3 authentication error messages to include a hint to check credentials when access is denied. #95648 (Gerald Latkovic).
- Enable statistics cache and set the update period of cache to 300s. #95841 (Han Fei).
- Add component name to
system.aggregated_zookeeper_log. #95882 (Antonio Andelic). - Skip object storage reads when querying
DeltaLaketables fromsystem.tables. #95899 (Antonio Andelic). - Enable
enable_max_bytes_limit_for_min_age_to_force_mergeby default if thecompatibilitysetting is26.2or higher. #95917 (Christoph Wurm). - Delta Lake is now available on macOS. Closes #95979. #95985 (Alexey Milovidov).
- In previous versions, when combining conflicting ALTER expressions with UPDATE and RENAME COLUMN, a logical error was thrown instead of a proper exception. Closes #70678. #96022 (Alexey Milovidov).
- Improve the help output for all ClickHouse applications and add a
--no-sudooption with a few fixes. This is a continuation of #58244 from Ilya Yatsishin. #96025 (Alexey Milovidov). - Add
distanceCosinealias forcosineDistancebecause all other distance functions already have alias of this form. #96065 (Raufs Dunamalijevs). - Add support for the
with_dataKeeper extension to improve table fetching in Database Replicated. #96090 (Nikolay Degterinsky). - Update chdig to v26.2.1 (new features and MacOS support). #96113 (Azat Khuzhin).
- Improve filter pushdown for
numbersandprimes. ClickHouse can now derive conservative value bounds fromWHEREconditions when exact bounds cannot be derived, and restrict sequence generation accordingly (for example, forWHERE number % 5 < 2 AND number > 100 AND number < 300, ClickHouse will only generate numbers between 100 and 300, then apply the predicate), avoiding unbounded scans. Closes #84853. Closes #93913. #96115 (Nihal Z. Miaji). - The formatter previously wrapped SELECT in parentheses when a
COMMENTclause was present to disambiguate parsing. Instead, outputCOMMENTbeforeAS SELECT, which eliminates the ambiguity without parentheses. #96293 (Alexey Milovidov). - The
allow_impersonate_userconfig setting is now located inside theaccess_control_improvementssection rather than being a standalone server setting. #96451 (Vitaly Baranov). - Make
core_dump.size_limitconfiguration setting hot-reloadable, to avoid having to restart servers for configuration changes to take place. #96524 (Miсhael Stetsyuk). - Improves CPU and real-time profiler interoperability with socket timeouts. #96601 (Sergei Trifonov).
- Prevent the resurrection of dropped data if ADD COLUMN is run quickly after the DROP COLUMN mutation. #96713 (Alexey Milovidov).
- Change
function_idtype insystem.instrumentationfrom LowCardinality(Int32) to Int32. #96726 (Copilot). - Synchronous waiting for mutations will respect query cancellation and time limits. #96756 (Alexey Milovidov).
- Added system command
SYSTEM RELOAD DELTA KERNEL TRACING <level>to be able to change delta-kernel logging, which can be useful for debugging. #96763 (Kseniia Sumarokova). - Filtering by IP address family, i.e.
dns_allow_resolve_names_to_ipv4/ipv6settings, are applied even if DNS cache is disabled. #96810 (c-end). - Better jemalloc introspection. #96840 (Azat Khuzhin).
- Fix
/playWeb UI throwingQUERY_CACHE_USED_WITH_SYSTEM_TABLEwhen querying system tables. #96869 (Alexey Milovidov). - Improve Web UI: change favicon to indicate running query state; display errors from auxiliary queries (loading databases and tables) instead of silently ignoring them. Closes #85055. #96883 (Alexey Milovidov).
- Make the left panel in
/playUI clickable to toggle the database list. #96884 (Alexey Milovidov). DROP DATABASEnow drops tables in reverse dependency order, improving crash-safety when the database contains tables with loading dependencies (e.g.Distributedtables usingjoinGet). #97057 (Alexey Milovidov).- Bump yaml-cpp to prevent skipping invalid YAML. #97333 (Azat Khuzhin).
- Show a loading indicator in the
play.htmlsidebar while tables are being fetched. #97531 (Alexey Milovidov). - Add a copy-to-clipboard button for raw query results in the built-in web UI (play.html). #97532 (Alexey Milovidov).
- Fix query obfuscator (
clickhouse-format --obfuscate) to produce parseable SQL in more cases. #97584 (Alexey Milovidov).
Bug Fix (user-visible misbehavior in an official stable release)
- After metadata-only ALTERs, such as extending the elements of Enums, the optimization of aggregation with projection may end up producing an exception. #84143 (Alexey Milovidov).
- Materialized views now use the database where they were created as execution context, meaning that: - it is possible to omit explicit database qualification on names referred in view’s select query - if no explicit database qualification is given, the same database where the materialized view was created is assumed. #88193 (Dmitry Kovalev).
- Fix query parameter substitution in CREATE USER authentication methods when using ON CLUSTER. Query parameters in authentication methods (e.g., password) were not being replaced, causing UNKNOWN_QUERY_PARAMETER errors on remote nodes. #92777 (xiaohuanlin).
- Fixed inconsistencies in text index analysis for
has,mapContainsKey, andmapContainsValuefunctions. Previously, queries using these functions could return different results depending on whether the expression was evaluated with or without a text index. #93578 (Anton Popov). - Fix crash when attaching a table to a
MaterializedPostgreSQLdatabase ifdropReplicationSlotthrows during stack unwinding. #96871 (Alexey Milovidov). - Backups could crash the server if you do many concurrent backups clashing over the same files. #93659 (Alexey Milovidov).
- Fixes queries with parallel replicas and JOIN with non-MT table. Closes #92056. #93902 (Igor Nikonov).
- Fixes an issue when Iceberg columns with dot in names returned NULL as values. #94335 (Mikhail Koviazin).
- Fixed handling of UTF8 strings in
stringJaccardIndexUTF8and improve performance. #94613 (Joanna Hulboj). - Fix possible overflows in
WITH FILL STALENESS(that leads to UB or/and endless loops). Fix possible endless loop due to big jumps. Add old analyzer support (mostly for stress tests). #94663 (Azat Khuzhin). - Fix possible hung distributed queries when hostnames resolve to multiple addresses and a remote replica freezes. #94726 (c-end).
- Fix invalid result on joining multiple table expressions, when leftmost table expression is a
-Clustertable function. Resolves #89996. #94748 (Konstantin Bogdanov). - Fix incorrect primary key and skip index pruning for predicates involving
toWeek,toYearWeek,toStartOfWeek,toLastDayOfWeek, andtoDayOfWeek, and fix exceptions in some of these functions for valid queries withLowCardinality(String). #94816 (Nihal Z. Miaji). - Remove unnecessary skip permissions check in
ATTACHqueries for a view with SQL Security. This prevents potential privilege escalation when a user attaches a view with a definer without validating required access. #94865 (pufit). - Fixes a crash during
ReplicatedMergeTreestartup caused by concurrent removal ofdelete_tmp_*directories. #94892 (myeongjun). - Fix
INSERTinto Iceberg tables with materialized views losing deduplication information, which caused an exception. #94938 (Daniil Ivanik). - Fix a bug where
SYSTEM DROP QUERY CACHE TAG 'TAGNAME' ON CLUSTER <CLUSTERNAME>would drop the full cache on the cluster. #94978 (Rory Crispin). - Preserve constant index granularity (use_const_adaptive_granularity) after Vertical merges (v2 with a fix for Nested, and in general). #95013 (Azat Khuzhin).
- Fixes race in filesystem cache in version 26.1 after [ClickHouse/ClickHouse#82764](https://github.com/ClickHouse/ClickHouse/pull/82764). #95042 (Kseniia Sumarokova).
- Fix postgresql() table function canceling by KILL QUERY and cancel query (Ctrl+C) in clickhouse-client. #95136 (Roman Vasin).
- Fixed type inference for qualified columns from source tables when multiple joins are used with
USINGclause. Previously, subsequent joins incorrectly updated types of underlying source columns to a common supertype even when the column was not involved in that join (e.g., inSELECT t2.a FROM t1 LEFT JOIN t2 USING (a) LEFT JOIN t3 USING (a), thet2.acolumn is only used by the first join, so its type should be the supertype oft1.aandt2.a, excludingt3.a). This could lead to logical errors or crashes when functions expected different column types than what actually appeared in the execution plan. #95157 (Vladimir Cherkasov). - Make column transform only once during getting content of manifest .avro list and files. #95164 (Daniil Ivanik).
- Fix incorrect calculation of JSON column sizes that could lead to excessive memory usage or wrong column statistics. #95207 (Azat Khuzhin).
- Fixed inaccurate memory accounting when applying large patch parts after lightweight updates. Previously, applying large patches could cause excessive memory usage and result in the server process being killed by the OOM killer. #95231 (Anton Popov).
- Fix undefined behavior that could cause incorrect results or an exception when a distributed query with
max_parallel_replicasfell back to a local replica during index analysis. #95263 (Azat Khuzhin). - Fix aggregation of sparse columns for
sumand timeseries whengroup_by_overflow_modeis set toany. #95301 (Mikhail Koviazin). - Fix a reliability issue in
plain_rewritabledisk policy where a network error mid-way through unlinking a metadata file could leave the storage in an inconsistent state. #95302 (Mikhail Artemenko). - Replace Date with Date32 for iceberg. #95322 (Konstantin Vedernikov).
- The password argument of the
redistable function now will be masked in the logs and system tables (e.g.:query_log). #95325 (János Benjamin Antal). - Fix a bug where tables could be dropped or altered while a distributed query was still executing against them, potentially causing exceptions or incorrect results. #95356 (Azat Khuzhin).
- Fix a logical error in some cases when negative
LIMIT/OFFSETis used in distributed queries. #95357 (Nihal Z. Miaji). - Fix a bug where clickhouse-client would ask for password twice when connecting using ssh. #95372 (Isak Ellmer).
- Fix a data race in storage S3(Azure)Queue. #95385 (Kseniia Sumarokova).
- Fix the prewhere filter error caused by lambda expressions in prewhere. #95395 (Xiaozhe Yu).
- Fix
optimize_syntax_fuse_functionsto not rewritesum/count/avgintosumCount()when the aggregate argument isNullable. Closes #95390. #95441 (Nihal Z. Miaji). - Avoid possible crash for distributed queries in case of cancellation. #95466 (Aleksandr Musorin).
- Fix deduplication for streaming from S3(Azure)Queue engine. #95467 (Kseniia Sumarokova).
- Fix updating row policies assigned to the initial user in distributed queries. #95469 (Vitaly Baranov).
- Fix check for encrypted disks over plain_rewritable (Fixes possible
It is not possible to register multiple plain-rewritable disks with the same object storage prefix). #95470 (Azat Khuzhin). - The
mergeTreeProjectiontable function was missing an access check, allowing users without SELECT permission on a table (but with permissions for table functions) to read data from its projections. This fix adds the same access check thatmergeTreeIndexandmergeTreeAnalyzeIndexesalready have. #95480 (Alexey Milovidov). - Fix possible logical error during reading of size subcolumn from dynamic subcolumns of Dynamic/JSON types. #95573 (Pavel Kruglov).
- Fix regression in (experimental) zero‑copy replication introduced by #94262 where shared parts could be deleted before other replicas finished fetching them. #95597 (filimonov).
- Fix crash during
tupleElementapplied to arrays of JSON. Closes #95581. #95647 (Pavel Kruglov). - Fix logical error exception when using a matcher (
*) inside a lambda function within a VALUES clause in a JOIN with USING. Close #93675. #95661 (Vladimir Cherkasov). - Fixed
There was an error: Cannot obtain error messagelogical error when waiting for a distributed DDL and dropping the Replicated database concurrently. Fixes #95539. #95664 (Alexander Tokmakov). - Fix
INfunction returning incorrect results withNULLvalues whentransform_null_inis enabled. Closes #65776. #95674 (Nihal Z. Miaji). - Correctly handle LowCardinality Nullable types in
CASTwhen the settingcast_keep_nullableis enabled. Closes #95670. #95747 (Alexey Milovidov). - Fix squashing partitioned delta lake data. #95773 (Kseniia Sumarokova).
- Fix race condition for Nullable join column in runtime filters. #95775 (Hechem Selmi).
- Fix possible logical error in query with matcher (
*,table.*) andanalyzer_compatibility_join_using_top_level_identifierwhenUSINGcolumn has different types in tables and select list. Close #90477. #95808 (Vladimir Cherkasov). - Fix memory safety bugs in parallel thread pool operations (backups, aggregation, distributed queries) that could cause exceptions when an error occurred during task scheduling. #95818 (Raúl Marín).
- Fixes a crash on the DROP WORKLOAD while running concurrently with queries using the workload being dropped. #95856 (Alexey Milovidov).
- Fix slow performance when querying system tables with a user that has limited grants on many databases. Closes #89371. #95874 (pufit).
- Fix executing tupleElement on JSON with nested paths, previously it could lead to wrong query result. #95907 (Pavel Kruglov).
- Fixed a
NOT_SUPPORTEDerror that could occur when using thedirectjoin algorithm with an empty MergeTree table. #95935 (Vladimir Cherkasov). - Fix the client not suggesting and auto-completing alias names for settings, closes #92190. #95945 (phulv94).
- Fix event_date in system.asynchronous_metric_log. #95947 (Raúl Marín).
- Fix skipping paths in JSON data type. Previously with
JSON(SKIP path)all JSON keys with prefixpathwere skipped, even keys like"pathpath", so it could lead to data loss for these paths during insert. Now it’s fixed and only key"path"is skipped. #95948 (Pavel Kruglov). - Part with unknown projections should not be marked as lost forever. #95952 (Mikhail Artemenko).
- Fix empty string becoming
NULLinJointable withNullable(String)key. Closes #71414. #96002 (Alexey Milovidov). - Now the PostgreSQL engine can correctly read
BOOLEAN[]. Closes #72754. #96006 (Alexey Milovidov). - Fix the
ProtobufListformat for the case of reading from an empty file. Closes #70059. #96007 (Alexey Milovidov). - Fix
ProtobufListformat producing ghost record for empty tables. Closes #72596. #96010 (Alexey Milovidov). - Fix
iffunction type mismatch betweenUInt64andInt32in an unusual case of distributed queries and PREWHERE, with type inference. Closes #70017. #96012 (Alexey Milovidov). - Fix
JITcompiled queries involvingBooltypes. #96013 (Alexey Milovidov). - Fix logical error when reading UUID column from SQLite TEXT column. Closes #71263. #96016 (Alexey Milovidov).
- Fix SQLite engine type conversion for
DateTime,Date,UUID, and other types. Closes #73481. #96017 (Alexey Milovidov). FixedStringvalues were escaped incorrectly in queries to external databases, SQLite and PostgreSQL. Closes #73519. Co-authored with @jh0x. #96019 (Alexey Milovidov).- Fix assertion failure in WindowTransform with a large PRECEDING offset. Closes #75852. #96026 (Alexey Milovidov).
- Fix a bug with possible data corruption when concurrent async inserts are using the same parameter names but contain different values. #96035 (Seva Potapov).
- Fix period for global profilers (controlled by
global_profiler_real_time_period_nsandglobal_profiler_cpu_time_period_ns). Instead of set value, a truncated value was used, causing profiler to wakeup more than intended. #96048 (Antonio Andelic). - Earlier if reference data file inside iceberg manifest file for position delete was present in an entry but was null, we didn’t get correct bounds for a corresponding data files. This PR fixes this bug. #96061 (Daniil Ivanik).
- Fix revoking default roles. #96103 (Vitaly Baranov).
- Fix use-after-free in the index analysis in a rare combination of disabled
use_primary_keyand a very large number of disjunctions of conditions that use the index. #96112 (Alexey Milovidov). - Fix a regression with the
Gorillacodec when an explicitly specified size does not correspond to the data type size, and the buffer size is too small. In previous versions, it threw an exception on decompression. Closes #78253. #96118 (Alexey Milovidov). - Avoid a deadlock in dictionaries loaded when one dictionary references a Merge table that references it recursively. Closes #78360. #96120 (Alexey Milovidov).
- Fix use-of-uninitialized-value in
formatDateTimewith non-fixed-width formatters, such as MySQL and JODA-style. #96133 (Alexey Milovidov). - The combination of settings
use_const_adaptive_granularityandindex_granularity_bytes(which means “non-adaptive granularity”) led to a miscalculation of the number of rows to read and an exception. #96143 (Alexey Milovidov). - Running an invalid ALTER UPDATE mutation on object storage file-like tables, such as S3 and Azure, could lead to a nullptr dereference. Closes #92994. #96162 (Alexey Milovidov).
- Fix
AccessRights::containsreturning incorrect results with partial revokes. #96170 (pufit). - Fix query condition cache hash collision for CTE folded constants, which could lead to a wrong query result. Closes #96060. #96172 (Alexey Milovidov).
- Fix possible deadlock in ProcessList. It can happen because of possible lock inversion if memory overcommit tracker triggers when we are adding task to cancellation checker. #96182 (Antonio Andelic).
- Fixed a bug where queries involving outer joins (LEFT, RIGHT, or FULL) combined with multiple INNER JOINs could return incorrect results due to illegal join reordering. When an outer join’s ON condition referenced columns from multiple previously joined tables, the optimizer failed to account for all table dependencies and could reorder the joins incorrectly, producing missing rows. Close #95972. #96193 (Vladimir Cherkasov).
- When a table has no statistics defined, ClickHouse shouldn’t try to load them. This avoids some overhead (100+ms) for checking if the statistics files exist. (issue #96068). #96233 (Han Fei).
- Fix
optimize_syntax_fuse_functionsto not rewritesum/count/avgintosumCount()when the aggregate argument isLowCardinality(Nullable). Closes #95390. #96239 (Nihal Z. Miaji). - Fix incorrect partition pruning for
not INandnot hasfunction in some cases. #96241 (Nihal Z. Miaji). - Fix
stack-use-after-scopein the vector similarity index. #96259 (Alexey Milovidov). - Fix test runner not recognizing error hint comments when a query is preceded by a SQL comment. #96336 (Yakov Olkhovskiy).
- Fix logical error in KeyCondition when a table has a nullable primary key, and the query uses the
coalescefunction, which has its first argument constant. #96340 (Alexey Milovidov). - The interaction of
GROUPING SETS,group_by_use_nulls, and theTupledata type withLowCardinalityinside it, could produce an unexpected block structure in the query pipeline, which led to a logical error. This appeared after the introduction ofNullableTuples. #96358 (Alexey Milovidov). - It was possible to create a table with an empty expression
()as an index, which led to an invalid memory access. #96363 (Alexey Milovidov). - Fixed crash in old analyzer if JOIN and duplicated aliases. #96405 (Ilya Golshtein).
- Fix
Nested columns sizes are inconsistent with local_discriminatorserror due to a wrong in-place filtering optimization for Variant columns. #96410 (Alexey Milovidov). - Fix
CREATE TABLE ... CLONE AS ...ignoring full qualifier of source table. #96415 (Hasyimi Bahrudin). - Fix
mysqltable function canceling by KILL QUERY and cancel query (Ctrl+C) in clickhouse-client. #96437 (Roman Vasin). - Fixes livelock in the cancellation checker thread for queries with high
max_execution_timevalues. #96450 (Sergei Trifonov). - Fix a logical error in some cases when fractional
LIMIT/OFFSETis used in distributed queries. #96475 (Nihal Z. Miaji). - Fix null pointer dereference in certain expressions with lambda functions. #96479 (Alexey Milovidov).
- Fix incorrect results when
LowCardinalitycolumns are converted toNullable. #96483 (Nihal Z. Miaji). - Fix a crash when creating an Iceberg table with an
ORDER BYclause referencing a non-existent column or using a positional argument. Closes #93280. #96484 (Konstantin Vedernikov). - Fix runtime filter exception for Tuple columns with Nullable subfields. #96509 (Alexey Milovidov).
- Fix
LOGICAL_ERRORexception in Parquet V3 native reader whenPREWHEREfilter column contains non-boolean UInt8 values. #96594 (Alexey Milovidov). - Fix implicit index regeneration in replicated tables during metadata changes. #96600 (Raúl Marín).
- Fixes a datarace on DROP WORKLOAD. #96614 (Sergei Trifonov).
- Fix a bug in Iceberg table writes where partitioned inserts could produce incorrect data distribution across partition files. #96620 (Konstantin Vedernikov).
- Fixed
heap-use-after-freeinCREATE TABLEwith constraints. #96669 (Nikita Taranov). - Validate witness version in bech32 to avoid buffer overflow. #96671 (Raúl Marín).
- Fix
system.tablesreturning errors when a Data Lake REST catalog is created with an invalidauth_headersetting. #96680 (Han Fei). - Fix
min(timestamp)returning epoch (1970-01-01) via_minmax_count_projectionafter TTL merge when all rows in a block are filtered out. #96703 (Raquel Barbadillo). - Improve validation of the
iceberg_metadata_file_pathsetting to prevent path traversal and ensure the specified metadata file is within the table directory. #96754 (Daniil Ivanik). - Fix crash in
ifNullwithVariantargument used inGROUP BY. #96790 (Alexey Milovidov). - Fixed cache key collisions between tables with
table_disk=1setting. #96818 (Raufs Dunamalijevs). - Fix MemoryWorker’s purging thread being stuck because of a race condition. #96819 (Antonio Andelic).
- Don’t log data with credentials in iceberg catalogs. #96831 (Konstantin Vedernikov).
- Fix exit status of clickhouse-client after server error. #96841 (Vitaly Baranov).
- Queries with CROSS JOINs and enabled parallel replicas could return incorrect result. Fixes #74337. #96848 (Igor Nikonov).
- Fixed
ALTER TABLE DROP COLUMNqueries failing after a lightweight update was previously performed on the same column. #96861 (Anton Popov). - Fix stack overflow (crash) when creating archive-based backups (
.zip,.tzst) to aplain_rewritableobject storage disk. #96872 (Alexey Milovidov). - Fix server crash when backup fails due to full disk or other I/O errors on the destination filesystem. #96873 (Alexey Milovidov).
- Fix
EXCEPT ALLandINTERSECT ALLignoring row multiplicities and behaving like theirDISTINCTcounterparts. #96876 (Alexey Milovidov). - Fix
std::terminateexception inindexOfAssumeSortedwhen called with incompatible types (e.g.,IPv4array with integer search value). #96877 (Alexey Milovidov). - Fix exception
Bad cast from type DB::ColumnNullable to DB::ColumnStringwhen using window functions withgroup_by_use_nulls = 1and CUBE/ROLLUP/GROUPING SETS. #96878 (Alexey Milovidov). - Fix incorrect results when JIT-compiled expressions convert
DateTimetoDateTime64(e.g., inCASE/if/multiIfwith mixed DateTime types). The value was reinterpreted instead of properly scaled, producing wrong timestamps after expression compilation kicked in. #96879 (Alexey Milovidov). - Fix logical error exception in
CoalescingMergeTreewhen a skip index expression produces a constant column (e.g.,bloom_filteronifNotFinite(1, c0)for an integer column). #96880 (Alexey Milovidov). - Fix wrong port number in error message when accidentally connecting with HTTP to the TLS-enabled native protocol port. #96881 (Alexey Milovidov).
- Fix per-subquery
SETTINGSnot being applied to table functions likefilein CTEs and subqueries. #96882 (Alexey Milovidov). - Fix memory leak of BIO objects when reading X509 certificates. #96885 (Alexey Milovidov).
- Fix
LOGICAL_ERRORexception in query analyzer when a lambda expression is passed where a concrete value is expected (e.g., as the accumulator argument ofarrayFold). #96892 (Alexey Milovidov). - Fix
ColumnNullable is not compatible with originalexception when casting complex nested types (Array of Nullable Tuple containing Map with Nullable Enum values). #96924 (Alexey Milovidov). - Fix a race condition in sharded
HASHEDdictionary parallel loading that could occasionally cause some rows to not be loaded. #96953 (Alexey Milovidov). - Fix a race condition between
REPLACE PARTITIONand background mutations that could result in both old and new data being visible after the replace. #96955 (Alexey Milovidov). - Fix
arrayJoinfunction producing duplicate rows when used with INNER JOIN and WHERE clause, caused by the partial predicate push-down optimization incorrectly pushing filters containingarrayJoinbelow a JOIN. #96989 (Alexey Milovidov). - Fix crash (SEGFAULT) in
clearCachescaused byBlockIO::operator=not movingquery_metadata_cache, leading to premature destruction of cached storage snapshots and use-after-free ofMergeTreeDatastorage. #96995 (Alexey Milovidov). - Fix assertion failure in
IfTransformStringsToEnumPasswhen theifortransformfunction returnsNullable(String)(e.g. withGROUP BY ... WITH CUBEandgroup_by_use_nulls = true). #97002 (Alexey Milovidov). - Fix incorrect data written during
INSERT ... SELECTwithUNION ALLandJOIN, where constant string columns could receive wrong values after block squashing. #97019 (Hasyimi Bahrudin). - Fix
assert_castexception (or silent data corruption in release builds) when building column statistics afterALTER TABLE MODIFY COLUMNchanges the column type. #97027 (Alexey Milovidov). - Fix reads of uninitialized memory in Azure Blob Storage, SSH protocol, and Arrow Flight interfaces. #97053 (Alexey Milovidov).
- Fix cases where indexes were affecting the result for queries with row policy/PREWHERE and FINAL. #97076 (Yarik Briukhovetskyi).
- Fix remaining race condition between
REPLACE PARTITIONand background mutations inMergeTreetables that could cause old data to reappear. #97105 (Alexey Milovidov). - Fix implicit indices with alias columns and do full validation before creating them. #97115 (Raúl Marín).
- Fix logical error in
FunctionVariantAdaptorwith functions requiring const arguments likearrayROCAUC. #97116 (Bharat Nallan). - Fix stuck mutations when
PartCheckThreadre-enqueues aGET_PARTfor an already-mutated part, leaving phantom entries inparts_to_do. #97162 (Alexey Milovidov). - Fix query plan row count estimation for subqueries with
ORDER BY ... LIMIT, which could cause the optimizer to choose a suboptimal join order. #97193 (Alexander Gololobov). - Fix
LOGICAL_ERRORexception inFunctionVariantAdaptorwhen a function operating on Variant columns returnsNothingtype, which can happen with empty arrays inUNION ALLqueries. #97213 (Alexey Milovidov). - Fix a data race during S3 multipart copy operations (e.g., during
BACKUP/RESTOREto S3) that could cause exceptions under concurrent access. #97227 (Azat Khuzhin). - Fix
LOGICAL_ERRORexception whenarrayJoininWHEREclause references columns from both sides of aJOIN. #97239 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception when reading.sizesubcolumn of a sparseNullable(String)in a Tuple with PREWHERE. #97264 (Alexey Milovidov). - Fix exception “Number of rows in lazy chunk does not match number of offsets” in
LazyMaterializingTransformwhen reading from tables with non-adaptive index granularity (index_granularity_bytes = 0) usingORDER BY ... LIMIT. #97270 (Alexey Milovidov). - Fix
SYSTEM RESTART REPLICAlosing table from database when table re-creation fails with a non-ZooKeeper exception (e.g. memory limit), causing metadata digest mismatches inDatabaseReplicated. #97276 (Alexey Milovidov). - Field
readonlyinsystem.merge_tree_settingsnow properly reflects that certain merge tree settings (e.g.index_granularity) are unconditionally readonly. #97277 (Robert Schulze). - Fix a crash during
count()optimization onMergeTreetables when the storage snapshot was created without data. #97281 (Pablo Marcos). - Fix a possible crash when resolving function names from debug information for stack traces. #97294 (Azat Khuzhin).
- Fix logical error with analyzer_compatibility_join_using_top_level_identifier and ALIAS columns. Close #96228. #97297 (Vladimir Cherkasov).
- Fix
LOGICAL_ERRORexception inapplyOrderwhen using text-indexed columns withQUALIFYclause. #97313 (Alexey Milovidov). - System table
system.functionsnow shows for internal functionscategories = 'Internal'instead ofcategories = ''. #97315 (Robert Schulze). - Query with RIGHT JOIN chain and enabled parallel replicas can produce incorrect result. Fixes #74341. #97316 (Igor Nikonov).
- Fix spurious
TABLE_UUID_MISMATCHerrors that could occur with refreshable materialized views and other scenarios where tables are renamed. #97323 (Azat Khuzhin). - Fix segfault in
StorageKeeperMapbackup due to use-after-free of dangling storage pointer in lazy backup batch. #97336 (Alexey Milovidov). - Fix the
existsfunction with a scalar subquery inside anALTER UPDATE/DELETEwhenmutations_execute_subqueries_on_initiatoris enabled. The scalar subquery was incorrectly evaluated, which could lead to an error or a corrupt mutation command that made the table unloadable on the next server restart. #97347 (Kirill Kopnev). - Fix logical exception
Unexpected return type from equals. Expected Nullable(UInt8). Got Const(LowCardinality(Nullable(UInt8)))when comparing NULL with a Variant column containing LowCardinality types. #97379 (Alexey Milovidov). - Fix a possible race condition when
EXCHANGE TABLESis executed in parallel with the sharded query cache enabled. #97411 (Konstantin Vedernikov). - Fix
LOGICAL_ERRORexception in Array-to-QBitconversion whennullable_sourcefrom an outerTuplewrapper replaces the converted array column with a mismatched column type. Closes #97389. #97413 (Alexey Milovidov). - Fix AST formatting roundtrip inconsistency for aliased tuple literals inside parentheses, e.g.,
(('a', 'b') AS x)was incorrectly reformatted astuple(('a', 'b') AS x). #97418 (Alexey Milovidov). - Fix an exception during asynchronous inserts with deduplication when a parsing failure produced an empty block with zero rows. #97460 (Sema Checherinda).
- Fix exception “Number of rows in lazy chunk does not match number of offsets” in
LazyMaterializingTransformwhen reading from tables with non-adaptive index granularity (index_granularity_bytes = 0) usingORDER BY ... LIMIT. #97482 (Alexey Milovidov). - Fix insert iceberg settings. Add alias for the
allow_experimental_insert_into_icebergsetting. #97483 (Konstantin Vedernikov). - Fix
ACCESS_DENIEDfor users withoutCREATE TEMPORARY TABLEpermission whenoptimize_inverse_dictionary_lookupoptimization rewritesdictGet(...)predicates. ClickHouse now skips the rewrite and executes the original expression. Closes #97269. #97484 (Nihal Z. Miaji). - Fix assertion failure (exception in debug/sanitizer builds) in
SetandMergeTreeIndexSetwhen processing columns with inner sparse subcolumns (e.g.,Tuplecolumns from MergeTree parts with different sparse serialization profiles). #97493 (Alexey Milovidov). - Fix a possible use after free in StorageKafka2. #97520 (Bharat Nallan).
- Fix
INTO OUTFILEwithTRUNCATEandinto_outfile_create_parent_directoriessetting when the output path contains directories. #97549 (Alexey Milovidov). - Fix
BAD_ARGUMENTSerror when querying tables with lambda expressions inside ALIAS columns through themerge()table function with the analyzer enabled. #97551 (Alexey Milovidov). - Fix
system.zookeeper_infoexception when Keeper zxid is 0. #97553 (Alexey Milovidov). - Fix a possible logical error in
ip_triedictionary when key type is not String. #97555 (Bharat Nallan). - Fix REST catalog OAuth authentication not working for the base
RestCatalog(it only worked for derived catalogs likeOneLakeCatalog). This broke the default REST catalog after BigLake catalog was introduced. #97561 (Konstantin Vedernikov). - Geometry functions (
perimeterSpherical,areaSpherical, etc.) now accept individual geometry subtypes (Polygon,Ring,Point, etc.) in addition to theGeometryvariant type. #97571 (Alexey Milovidov). - Fix
LOGICAL_ERRORexception when usingisNull/isNotNullon subcolumns ofNullable(Tuple(... Nullable(T) ...))types. Closes #97224. #97582 (Alexey Milovidov). - Fix null pointer dereference when applying patch parts during lightweight updates. #97583 (Alexey Milovidov).
BaseSettings::readBinarypasses the index fromaccessor.findtofield_infos[]without checking for the not-found sentinel value (i.e.,-1), which may cause astd::vectorout-of-bounds access. The issue was caught thanks to libcxx hardening. This probably happened during query plan deserialization when a newer server sends a setting unknown to an older server. The string-based read method already handles this correctly;readBinarywas missing the same check. #97585 (Miсhael Stetsyuk).- Fix incorrect query results for
UNION ALLqueries where one branch had a constant-false predicate — the branch would incorrectly read data instead of returning nothing. #97620 (Bharat Nallan). - Fix
IN (col)with a single column reference failing withUNSUPPORTED_METHODerror. #97646 (Alexey Milovidov). - Fix logical error exception during
GROUP BY ... WITH ROLLUP/CUBEwhen keys includeLowCardinality(Nullable(...))insideNullable(Tuple(...)). #97647 (Alexey Milovidov). - Fix AST formatting inconsistency for
NOT (1, 1, 1)that could causeLOGICAL_ERRORin debug builds. #97653 (Alexey Milovidov). - Fix
keeper-converterexception when encountering empty ZooKeeper transaction log files. #97673 (Alexey Milovidov).
Build/Testing/Packaging Improvement
- ClickHouse can be built with clang-23 (master). #95578 (Alexey Milovidov).
- Fix force
is_localto false whenbind_hostis configured and replace with integration test. Follow-up for #74741. #93109 #96018 (Zhigao Hong). - Stress tests: fix stress and upgrade tests in CI. ignore
no-{build}tags. add compatibility randomization. #94693 (Nikita Fomichev). - Publish parser_memory_profiler binary from build. Tool can be used to analyze AST memory consumption. #95826 (Ilya Yatsishin).
- Add
--symbolizeflag forparser_memory_profilertool that produces.heap.symfiles with resolved symbols in results. #96477 (Ilya Yatsishin). - Pin third-party Docker images in integration tests to specific versions. #96500 (Alexey Milovidov).
- Restore the possibility to link
OpenSSLdynamically. This is not recommended and not used by any production builds, but the option still exists for enthusiasts on the Internet. #96506 (Govind R Nair). - Reduce
magic_enumrange from [-100, 1000] to default [-128, 127] by using a per-type specialization forCoordination::OpNum, improving build time. #96632 (Alexey Milovidov). - Remove unnecessary C++ templates from Function classes to reduce build times. #96646 (Alexey Milovidov).
- Move
StorageSystemLicensesgeneration to configure time to improve build parallelism. #96697 (Alexey Milovidov). - Parallelize license scanning. #96727 (Raúl Marín).
- Add stateless functional test for SSH protocol support. #96996 (Alexey Milovidov).
- Add Kafka 3.9.0 to the stateless functional test infrastructure, enabling direct testing of Kafka and Kafka2 table engines using ClickHouse Keeper as ZooKeeper. Six new stateless tests cover basic produce/consume, virtual columns, INSERT, multiple formats, broken message handling, and Keeper-based offset storage. #96997 (Alexey Milovidov).
- Add a CI workflow to build PGO+BOLT optimized clang toolchain. #96991 (Alexey Milovidov).
- Use the PGO-optimized LLVM/Clang build in CI, which should give 20..30% build speed improvement. #97031 (Alexey Milovidov).
- Replace math functions from glibc with llvm-libc implementations. #90151 (Konstantin Bogdanov).
- Update Boost from 1.83 to 1.90, fixing a
devectorassertion failure in debug builds. #97037 (Alexey Milovidov). - Update
postgresto REL_18_1. #95189 (Konstantin Bogdanov). - Use
libexpat2.7.3. #95218 (Konstantin Bogdanov). - Use
OpenSSL3.5.5. #95345 (Konstantin Bogdanov). - Use
simdjsonv4.2.4. #97129 (Konstantin Bogdanov). - Use
libarchive3.8.5. #97131 (Konstantin Bogdanov). - Use
fast_floatv8.2.3. #97133 (Konstantin Bogdanov). - Use
abseil-cpp20260107.1,s2geometryto v0.13.1. #97134 (Konstantin Bogdanov). - Bump
libxml2to 2.15.1. #95574 (Robert Schulze). - Upgraded 7 Tier-3 integration test Docker images from EOL or removed base images to current supported versions. #97314 (Rahul).
- Add TPC-DS benchmark queries. #97349 (Raufs Dunamalijevs).
- Replace individual x86 instruction-set cmake options (
ENABLE_SSSE3,ENABLE_AVX2,NO_SSE3_OR_HIGHER,ARCH_NATIVE, etc.) with a single numericX86_ARCH_LEVELoption (1/2/3/4), matching the standard x86-64 microarchitecture levels already used by the runtime dispatch system. #97354 (Raúl Marín). - Avoid instantiating
division_by_nullable=truetemplate variants for non-division operations inFunctionBinaryArithmetic, reducing compilation time and binary size. #97496 (Raúl Marín). - Reduce the include footprint of
Exception.hby removing it from high-fan-out headers liketypeid_cast.h,assert_cast.h,Context_fwd.h,IDataType.h, and various Column headers. #97497 (Raúl Marín). - Always use bundled
compiler-rtheaders (sanitizer and XRay interfaces) instead of the host compiler’s headers, and buildcompiler-rtlibraries from source by default. #97499 (Raúl Marín). - Avoid including boost/multiprecision headers in
wide_integer_impl.hon platforms with adequatelong double, improving build time. #96633 (Alexey Milovidov). - Implement LLVM Code Coverage job and enable it initially for master branch. #90952 (Alexey Bakharew).
- Enable fast libcxx hardening for release builds. This is mostly needed for out-of-bounds checks. Given performance tests results, no noticeable performance impact is expected. #94757 (Miсhael Stetsyuk).
ClickHouse release 26.1, 2026-01-29. Presentation, Video
Backward Incompatible Change
- Fix inconsistent formatting caused by an incorrect substitution of aliases in the formatter. This closes #82833. This closes #82832. This closes #68296. This change is potentially backward incompatible: when the analyzer is disabled, certain CREATE VIEW queries with IN referencing an alias cannot be processed. To prevent the incompatibility, enable the analyzer (it is enabled by default since 24.3). #82838 (Alexey Milovidov).
- Codecs
DEFLATE_QPLandZSTD_QATwere removed. Users are advised to convert existing data compressed withDEFLATE_QPLorZSTD_QATto another codec before upgrade. Note that in order to use the codecs, settingsenable_deflate_qpl_codecandenable_zstd_qat_codechad to be enabled. #92150 (Robert Schulze). - Improve UDF debugging by enabling stderr capture in
system.query_log.exception. Previously, UDF stderr was only logged to files and not exposed in query logs, making debugging impossible. Now stderr triggers exceptions by default and is fully accumulated (up to 1MB) before throwing, so complete Python tracebacks and error messages appear insystem.query_log.exceptionfor effective troubleshooting. #92209 (Xu Jia). - Empty column list in
JOIN USING ()clause is now considered a syntax error. Previously it was supposed to beINVALID_JOIN_ON_EXPRESSIONduring query execution. In some cases such as joining withJoinstorage it led toLOGICAL_ERROR, close #82502. #92371 (Vladimir Cherkasov). - Use partial match for SKIP REGEXP in JSON type by default. Closes #79250. #92847 (Pavel Kruglov).
- Revert “Allow INSERT into simple ALIAS columns” (Reverts ClickHouse/ClickHouse#84154). It does not work with custom formats, and is not guarded with a setting. #92849 (Azat Khuzhin).
- Setting to throw an error if a data lake catalog doesn’t have access to object storage. #93606 (Konstantin Vedernikov).
- The
Lazydatabase engine is removed and no longer available. Closes #91231. #93627 (Alexey Milovidov). - Remove the
transposed_with_wide_viewmode of themetric_log- it is unusable due to a bug. It is no longer possible to definesystem.metric_logwith this mode. This partially reverts #78412. #93867 (Alexey Milovidov). - CPU scheduling for workloads is now preemptive by default. See
cpu_slot_preemptionserver setting. #94060 (Sergei Trifonov). - Escape index filenames to prevent broken parts. With this change ClickHouse will fail to load indices with non-ascii characters in their name created by previous versions. To handle it you can use the merge tree setting
escape_index_filenames. #94079 (Raúl Marín). - Format settings
exact_rows_before_limit,rows_before_aggregation,cross_to_inner_join_rewrite,regexp_dict_allow_hyperscan,regexp_dict_flag_case_insensitive,regexp_dict_flag_dotallanddictionary_use_async_executorwere changed to be regular (non-format) settings now. This is a purely internal change without user-visible side effects except in the (unlikely) case that you specified any of these settings in Iceberg or DeltaLake or Kafka or S3 or S3Queue or Azure or Hive or RabbitMQ or Set or FileLog or NATS table engine definitions. In these cases, these settings were previously ignored, now such definitions throw an error. #94106 (Robert Schulze). - The
joinGet/joinGetOrNullfunctions now enforceSELECTprivileges on the underlying Join table. After this change, executingjoinGet('db.table', 'column', key)requires the user to haveSELECTprivilege on both the key columns defined in the Join table and the attribute column being retrieved. Queries lacking these privileges will fail withACCESS_DENIED. To migrate, grant the necessary permissions usingGRANT SELECT ON db.join_table TO userfor full table access, orGRANT SELECT(key_col, attr_col) ON db.join_table TO userfor column-level access. This change affects all users and applications relying onjoinGet/joinGetOrNullwhere explicitSELECTgrants were not previously configured. #94307 (Vladimir Cherkasov). - Check
SHOW COLUMNSforCREATE TABLE ... AS ...queries. Previously, it checkedSHOW TABLES, which is an incorrect grant for this type of permission check. #94556 (pufit). - Make the
Hashoutput format independent of block sizes. #94503 (Alexey Milovidov). Note that this changes the output hash values compared to previous versions.
New Feature
- HTTP API and embedded Web UI for ClickHouse Keeper. #78181 (pufit and speeedmaster).
- Async insert deduplication now works with dependent materialized views. When collision by block_id occurs, the original block is filtered to remove rows associated with the block_id, and the remaining rows are transformed with all relevant materialized views select queries, this rebuilds original block without conflicting rows. #89140 (Sema Checherinda). It is allowed to use deduplication with async inserts when materialized views are involved. #93957 (Sema Checherinda).
- Introduced a new syntax and framework to simplify and extend projection index feature. This follows up https://github.com/ClickHouse/ClickHouse/pull/81021. #91844 (Amos Bird).
- Add text index support for
Arraycolumns. #89895 (Jimmy Aguilar Mena). - Enable
use_variant_as_common_typeby default, which lets you use incompatible types inside anArray, inUNIONqueries, and in branches ofif/multiIf/case. #90677 (Alexey Milovidov). - New system table
zookeeper_info. Implements #88014. #90809 (Smita Kulkarni). - Support the
Varianttype in all functions. #90900 (Bharat Nallan). - Adds a
ClickHouse_Infometric to the Prometheus/metricsendpoint containing mainly version information so it’s possible to build charts tracking detailed version information over time. #91125 (Christoph Wurm). - Introduce a new four letter
rcfgcommand for keeper which allows to change cluster configuration. This command provides broader possibilities for configuration changes than standardreconfigurerequest. Command takesjsonstring as an argument. The whole set of bytes sent to TCP interface should look like this:rcfg{json_string_length_big_endian}{json_string}. Some examples of command may look like this:{"preconditions": {"leaders": [1, 2], "members": [1, 2, 3, 4, 5]}, "actions": [{"transfer_leadership": [3]}, {"remove_members": [1, 2]}, {"set_priority": [{"id": 4, "priority": 100}, {"id": 5, "priority": 100}]}, {"transfer_leadership": [4, 5]}, {"set_priority": [{"id": 3, "priority": 0}]}]}. #91354 (alesapin). - Add function
reverseBySeparatorwhich reverses the order of substrings in a string separated by a specified separator. Close #91463. #91780 (Xuewei Wang). - Adds new setting
max_insert_block_size_byteswhich control the formation of inserted blocks in finer detail. #92833 (Kirill Kopnev). - It is possible to execute DDL queries with
ON CLUSTERclause for a Replicated database if theignore_on_cluster_for_replicated_databasesetting is enabled. In this case, the cluster name will be ignored. #92872 (Kirill). - Implement
mergeTreeAnalyzeIndexesfunction. #92954 (Azat Khuzhin). - Add new setting
use_primary_key. Set it tofalseto disable granule pruning based on the primary key. #93319 (Nihal Z. Miaji). - Add
icebergLocalClustertable function. #93323 (Anton Ivashkin). - Added
cosineDistanceTransposedfunction that approximates the cosine distance between two points. #93621 (Raufs Dunamalijevs). - Add
filescolumn to system.parts table that shows the number of files in each data part. #94337 (Match). - Adds a max-min fair scheduler for concurrency control. Provides better fairness under high oversubscription, where many queries compete for limited CPU slots. Short-running queries are not penalized by long-running queries that have accumulated more slots over time. Enabled by the
concurrent_threads_schedulerserver settingmax_min_fairvalue. #94732 (Sergei Trifonov). - Added the ability for ClickHouse client to override TLS SNI when connecting to the server. #89761 (Matt Klein).
- Support temporary tables in
joinGetfunction calls. #92973 (Eduard Karacharov). - Support deletion vectors in
DeltaLaketable engine. #93852 (Kseniia Sumarokova). - Support deletion vectors for
deltaLakeCluster. #94365 (Kseniia Sumarokova). - Google cloud storage support for data lakes. #93866 (Konstantin Vedernikov).
Experimental Feature
- Move
QBitfrom Experimental to Beta. #93816 (Raufs Dunamalijevs). - Add support for
Nullable(Tuple). Setallow_experimental_nullable_tuple_type = 1to enable it. #89643 (Nihal Z. Miaji). - Support Paimon REST catalog, continuing from https://github.com/ClickHouse/ClickHouse/pull/84423. #92011 (JIaQi Tang).
Performance Improvement
- Setting
use_skip_indexes_on_data_readis now enabled by default. This setting allows filtering in a streaming fashion, at the same time as reading, improving query performance and startup time. #93407 (Shankar Iyer). - Improve performance of
DISTINCTonLowCardinalitycolumns. Closes #5917. #91639 (Nihal Z. Miaji). - Optimize
distinctJSONPathsaggregate function so it reads only JSON paths from data parts and not the whole JSON column. #92196 (Pavel Kruglov). - More filters pushed down JOINs. #85556 (Nikita Taranov).
- Support more cases for push down from join ON condition when the filter uses inputs only from one side. Support
ANY,SEMI,ANTIjoins. #92584 (Dmitry Novik). - Allow using equivalent sets to push down filters for
SEMI JOIN. Closes #85239. #92837 (Dmitry Novik). - Skip reading left side of hash join when right side is empty. Previously we were reading left side until first non-empty block, which might do a lot of work in case when there is heavy filtering or aggregation. #94062 (Alexander Gololobov).
- Using the “fastrange” (Daniel Lemire) method for partitioning data inside the query pipeline. This could improve parallel sorting and JOINs. #93080 (Alexey Milovidov).
- Improve performance of window functions when PARTITION BY matches or is a prefix of the sorting key. #87299 (Nikita Taranov).
- Outer filter is pushed down into views which allows applying PREWHERE on local and remote nodes. Resolves #88189. #88316 (Igor Nikonov).
- Implement JIT compilations for more functions. Closes #73509. #88770 (Alexey Milovidov with Taiyang Li).
- If a skip index used in a
FINALquery is on a column that is part of the primary key, the additional step to check for primary key intersection in other parts is unnecessary and now not performed. Resolves #85897. #93899 (Shankar Iyer). - Optimize performance and memory usage for fractional
LIMITandOFFSET. #91167 (Ahmed Gouda). - Fix using of faster random read logic for Parquet Reader V3 prefetcher. Closes #90890. #91435 (Arsen Muk).
- Improve performance of
icebergCluster. Closes #91462. #91537 (Yang Jiang). - Don’t filter by virtual columns on constant filters. #91588 (c-end).
- Reduce INSERT/merges memory usage with wide parts for very wide tables by enabling adaptive write buffers. Add support of adaptive write buffers for encrypted disks. #92250 (Azat Khuzhin).
- Improved performance of full text search with text index and
sparseGramstokenizer by reducing the number of searched tokens in the index. #93078 (Anton Popov). - Function
isValidASCIIwas optimized for positive outcomes, i.e. all-ASCII input values. #93347 (Robert Schulze). - The read-in-order optimization now recognizes when ORDER BY columns are constant due to WHERE conditions, enabling efficient reverse-order reads. This benefits multi-tenant queries like
WHERE tenant='42' ORDER BY tenant, event_time DESCwhich can now use InReverseOrder instead of requiring a full sort.”. #94103 (matanper). - Introduce Enum AST specialized class to store value parameters in (string, integer) pairs instead of ASTLiteral children to optimize memory consumption. #94178 (Ilya Yatsishin).
- Distributed index analysis on multiple replicas. Beneficial for shared storage and huge amount of data in cluster. This is applicable for SharedMergeTree (ClickHouse Cloud) and could be applicable for other types of MergeTree tables on a shared storage. #86786 (Azat Khuzhin).
- Reduce overhead of join runtime filters by disabling them in the following cases: - too many bits are set in the bloom filter - too few rows are filtered out at runtime. #91578 (Alexander Gololobov).
- Use an in-memory buffer for correlated subqueries input to avoid evaluating it multiple times. Part of #79890. #91205 (Dmitry Novik).
- Allow all replicas to steal orphaned ranges in parallel replicas reading. This improves load balancing and reduces long-tail latency. #91374 (zoomxi).
- External aggregation/sorting/join now respects query setting
temporary_files_codecin all contexts. Fixed missing profile events for grace hash join. #92388 (Vladimir Cherkasov). - Make query memory usage detection for spilling to disk during aggregation/sorting more robust. #92500 (Azat Khuzhin).
- Estimate total rows count and NDV (number of distinct values) statistics of aggregation key columns. #92812 (Alexander Gololobov).
- Optimize postings list compression with simdcomp. #92871 (Peng Jian).
- Refactor S3Queue Ordered mode processing with buckets. This should also improve performance, reducing the number of keeper requests. #92889 (Kseniia Sumarokova).
- Functions
mapContainsKeyLikeandmapContainsValueLikecan now leverage a text index onmapKeys()ormapValues(), respectively. #93049 (Michael Jarrett). - Reduce memory usage on non-Linux systems (enable immediate purging of jemalloc dirty pages). #93360 (Eduard Karacharov).
- Force purging of jemalloc arenas in case the ratio of dirty pages size to
max_server_memory_usageexceedsmemory_worker_purge_dirty_pages_threshold_ratio. #93500 (Eduard Karacharov). - Reduce memory usage for AST. #93601 (Nikolai Kochetov).
- In some cases we’ve seen ClickHouse doesn’t respect a memory limit when reading from a table. This behaviour is fixed. #93715 (Nikita Mikhaylov).
- Enable
CHECK_STATandTRY_REMOVEKeeper extension by default. #93886 (Mikhail Artemenko). - Parse lower and upper bounds of file names corresponding to position deletes from Iceberg manifest file entries for better selection of corresponding data files. #93980 (Daniil Ivanik).
- Add two more settings to control maximum number of dynamic subcolumns in JSON column. First is MergeTree setting
merge_max_dynamic_subcolumns_in_compact_part(similar to already addedmerge_max_dynamic_subcolumns_in_wide_part) that limits number of dynamic subcolumns created during merge into a Compact part. Second is query level settingmax_dynamic_subcolumns_in_json_type_parsingthat limits number of dynamic subcolumns created during parsing of JSON data, it will allow to specify the limit on insert. #94184 (Pavel Kruglov). - Slightly optimize squashing of JSON columns for some cases. #94247 (Pavel Kruglov).
- Lower the thread pool queue sizes based on the production experience. Add an explicit memory consumption check before reading any data from the MergeTree. #94692 (Nikita Mikhaylov).
- Make sure the scheduler would prefer MemoryWorker thread under the CPU starvation, because it protects ClickHouse process from an existential threat. #94864 (Nikita Mikhaylov).
- Run purging of jemalloc dirty pages in a different thread from main thread of MemoryWorker. If purging is slow, it could delay updates of RSS usage which could lead to out of memory kills of the process. Introduce new config
memory_worker_purge_total_memory_threshold_ratioto start purging dirty pages based on ratio of total memory usage. #94902 (Antonio Andelic).
Improvement
system.blob_storage_logis now available for Azure Blob Storage. #93105 (Alexey Milovidov).- Implement
blob_storage_logfor Local and HDFS. Fix an error whenS3Queueused something other than the disk name for logging inblob_storage_log. Adderror_codecolumn toblob_storage_log. Split the test configuration file to simplify local testing. #93106 (Alexey Milovidov). clickhouse-clientandclickhouse-localwill highlight digit groups (thousands, millions, etc.) inside numeric literals while typing. This closes #93100. #93108 (Alexey Milovidov).- Adds support in
clickhouse-clientfor command-line arguments with a space surrounding the equals sign. Closes #93077. #93174 (Cole Smith). - With
<interactive_history_legacy_keymap>true</interactive_history_legacy_keymap>, the CLI client can now fall back to Ctrl-R for regular search like before, while Ctrl-T does fuzzy search. #87785 (Larry Snizek). - The statement to clear caches
SYSTEM DROP [...] CACHEgave the false impression that the statement disables the cache. ClickHouse now supports statementSYSTEM CLEAR [...] CACHEwhich is more obvious. The old syntax remains available. #93727 (Pranav Tiwari). - Support multiple columns as primary key in
EmbeddedRocksDB. Closes #32819. #33917 (usurai). - It is now possible to use non-constant IN for scalars (queries like
val1 NOT IN if(cond, val2, val3)). #93495 (Yarik Briukhovetskyi). - Prevent
x-amz-server-side-encryptionheaders from being propagated toHeadObject,UploadPart&CompleteMultipartUploadS3 requests as they’re not supported. #64577 (Francisco J. Jurado Moreno). - Tracking hive partitioning for ordered mode in S3Queue. Resolves #71161. #81040 (Anton Ivashkin).
- Optimize space reservation in filesystem cache.
FileCache::collectCandidatesForEvictionwill be executed without unique lock. #82764 (Kseniia Sumarokova). - Support composite rotation strategy (size + time) for server log. #87620 (Jianmei Zhang).
- CLI client can now specify
<warnings>false</warnings>instead of the command line--no-warnings. #87783 (Larry Snizek). - Add support for the
avgaggregate function with Date, DateTime and Time values as arguments. Closes #82267. #87845 (Yarik Briukhovetskyi). - The optimization
use_join_disjunctions_push_downis enabled by default. #89313 (Alexey Milovidov). - Support more table engines and data source kinds in the correlated subqueries. Closes #80775. #90175 (Dmitry Novik).
- If the schema of parameterized view is specified explicitly, it is shown. Close #88875, #81385. #90220 (Grigorii Sokolik).
- Correctly handle the gap in Keeper log entries if logs are before the last committed index. #90403 (Antonio Andelic).
- Improve
min_free_disk_bytes_to_perform_insertsetting to work correctly with JBOD volumes. #90878 (Aleksandr Musorin). - Make it possible to specify
storage_class_namesetting in named collections forS3table engine ands3table function. #91926 (János Benjamin Antal). - Support inserting auxiliary zookeeper by
system.zookeeper. #92092 (RinChanNOW). - Add new metrics for the keeper:
KeeperChangelogWrittenBytes,KeeperChangelogFileSyncMicroseconds,KeeperSnapshotWrittenBytesandKeeperSnapshotFileSyncMicrosecondsprofile events as well asKeeperBatchSizeElementsandKeeperBatchSizeByteshistogram metrics. #92149 (Miсhael Stetsyuk). - Add a new setting,
trace_profile_events_list, which limits tracing withtrace_profile_eventto the specified list of event names. This allows more precise data collection on large workloads. #92298 (Alexey Milovidov). - Support SYSTEM NOTIFY FAILPOINT for pausable failpoints. - Support SYSTEM WAIT FAILPOINT fp PAUSE/RESUME. #92368 (Shaohua Wang).
- Add
creation(implicit/explicit) column tosystem.data_skipping_indices. #92378 (Raúl Marín). - Allow passing the description of columns for YTsaurus dyn tables to the dictionary source. #92391 (MikhailBurdukov).
- In #63985, we made it possible to specify all the parameters needed for TLS configuration on a per-port basis (see composable protocols), so we don’t have to rely on global TLS config. However, the implementation still implicitly requires a global
openSSL.serverconfig section to exist, which conflicts with setups where different TLS configurations are needed for different ports. For example, in keeper-in-server deployments, we need separate TLS configs for inter-keeper communication and clickhouse client connections. #92457 (Miсhael Stetsyuk). - Introduce a new setting
input_format_binary_max_type_complexitythat limits the total number of type nodes that can be decoded in binary format to prevent malicious payloads. #92519 (Raufs Dunamalijevs). - Reflect running tasks in
system.background_schedule_pool{,_log}. Add documentation. #92587 (Azat Khuzhin). - Execute current query in Ctrl+R search in client if no history match found. #92749 (Azat Khuzhin).
- Support
EXPLAIN indices = 1as an alias forEXPLAIN indexes = 1. Closes #92483. #92774 (Pranav Tiwari). - Parquet reader now allows reading Tuple or Map columns as JSON:
select x from file(f.parquet, auto, 'x JSON')works even if the type of columnxinf.parquetis tuple or map. #92864 (Michael Kolupaev). - Support empty tuples in parquet reader. #92868 (Michael Kolupaev).
- Fallback to read-write copy for Azure Blob Storage when native copy fails with BadRequest (e.g. invalid block list). Previously this was only done for Unauthorized error which was seen while copying blob to different storage accounts. But we also sometimes see “The specified block list is invalid” error. So now updated the condition to fallback to read & write for all native copy fails. #92888 (Smita Kulkarni).
- Fix EC2 metadata endpoint throttling when running many concurrent S3 queries with EC2 instance profile credentials. Previously, each query created its own
AWSInstanceProfileCredentialsProvider, causing concurrent requests to the EC2 metadata service which could result in timeouts andHTTP response code: 403errors. Now the credentials provider is cached and shared across all queries. #92891 (Sav). - Rework
insert_select_deduplicatesetting to add an ability to keep backward compatibility. #92951 (Sema Checherinda). - Log background tasks that are slower than average (
background_schedule_pool_log.duration_threshold_milliseconds=30) to avoid excessive tasks logging. #92965 (Azat Khuzhin). - In previous versions, some of C++ function names were displayed incorrectly (“mangled”) in the
system.trace_logandsystem.symbols, and thedemanglefunction didn’t process them well. Closes #93074. #93075 (Alexey Milovidov). - Introduced the
backup_data_from_refreshable_materialized_view_targetsbackup setting to skip back up of refreshable materialized views. RMVs with APPEND refresh strategy which are always backed up. #93076 (Julia Kartseva). #93658 (Julia Kartseva) - Use minimal debug info instead of no debug info for heavy translation units, such as functions. #93079 (Alexey Milovidov).
- Added MinIO compatibility support to AWS S3 C++ SDK by implementing error code mapping for MinIO-specific errors. This change allows ClickHouse to properly handle and retry MinIO server errors when using MinIO deployments instead of AWS S3, improving reliability for users running object storage on self-hosted MinIO clusters. #93082 (XiaoBinMu).
- Write symbolized jemalloc profiles (eliminating the need for a binary during heap profile generation). #93099 (Azat Khuzhin).
- Resurrect
clickhouse git-importtool - it was broken on large and invalid commits. See https://presentations.clickhouse.com/2020-matemarketing/. #93202 (Alexey Milovidov). - Don’t show passwords from URL storage in query log. #93245 (Konstantin Vedernikov).
- Support
Geometrytype forflipCoordinates. #93303 (Bharat Nallan). - Improve the UX of SYSTEM INSTRUMENT ADD/REMOVE: use String literals for function names, patch all functions that match and allow using function_name in
REMOVE. #93345 (Pablo Marcos). - Add a new setting
materialize_statistics_on_mergewhich enables/disables materializing statistics during merge. The default value is1. #93379 (Han Fei). - ClickHouse can now parse
SELECTwithout parentheses aroundDESCRIBE SELECTqueries. Closes #58382. #93429 (Yarik Briukhovetskyi). - Add randomization of cache correctness checks under probability. #93439 (Kseniia Sumarokova).
- Add setting
type_json_allow_duplicated_key_with_literal_and_nested_objectto allow duplicated paths in JSON where one is a literal and another is a nested object, e.g.{"a" : 42, "a" : {"b" : 42}}. Some data could be created before this restriction on duplicated paths was added in https://github.com/ClickHouse/ClickHouse/pull/79317 and further manipulation with this data can lead to errors now. With this setting, such old data cane still be used with no errors. #93604 (Pavel Kruglov). - Don’t print values of simple types on separate lines in Pretty JSON. #93836 (Pavel Kruglov).
- When there are many
alter table ... modify setting ...statements, it’s possible not to acquire lock for 5 seconds. Better to returntimeoutthanlogical error. #93856 (Han Fei). - Prevent excessive output on a syntax error. Before this change, it output the whole SQL script, which could contain a lot of queries. #93876 (Alexey Milovidov).
- Do proper byte size calculation of the
checkrequest with stats in Keeper. #93907 (Mikhail Artemenko). - Added
use_hash_table_stats_for_join_reorderingsetting to control whether runtime hash table size statistics are used for join reordering. This setting is enabled by default, preserving the existing behavior ofcollect_hash_table_stats_during_joins. #93912 (Vladimir Cherkasov). - Users can now partially view nested global server settings in the
system.server_settingstable (e.g.logger.level). This only covers settings with a fixed structure (no lists, enumerations, repetitions etc.). #94001 (Hechem Selmi). QBitcan now be compared for equality. #94078 (Raufs Dunamalijevs).- When Keeper detects broken snapshot or inconsistent changelogs, throw exception instead of manually aborting or cleaning up files automatically. This should lead to a safer behaviour of Keeper relying on manual intervention. #94168 (Antonio Andelic).
- Fix leaving possible leftovers in case of
CREATE TABLEfails. #94174 (Azat Khuzhin). - Fix uninitialized memory access (a bug in OpenSSL) when password protected TLS key is used. #94182 (Konstantin Bogdanov).
- Bump chdig to v26.1.1. #94290 (Azat Khuzhin).
- Support more generic partitioning for S3Queue ordered mode. #94321 (Bharat Nallan).
- Added alias
use_statisticsfor settingallow_statistics_optimize. This is more consistent with existing settingsuse_primary_keyanduse_skip_indexes. #94366 (Robert Schulze). - Enabled setting
input_format_numbers_enum_on_conversion_errorfor conversion from Numbers to Enums to check whether the element exists. #94384 (Elmi Ahmadov). - In S3(Azure)Queue ordered mode clean up failed nodes by tracking limits (before that was done only in Unordered mode for both failed and processed, so now this will also be done for Ordered but only for failed nodes). #94412 (Kseniia Sumarokova).
- Enable access management for
defaultuser in clickhouse-local. The default user inclickhouse-localwas missing the access_management privilege, which caused operations likeDROP ROW POLICY IF EXISTSto fail withACCESS_DENIEDerror, even though the user should be unrestricted. #94501 (Alexey Milovidov). - Enable named collection for YTsaurus dictionaries and tables. #94582 (MikhailBurdukov).
- Add support for SQL-defined named collections in BACKUP/RESTORE for S3 and Azure Blob Storage. Closes #94604. #94605 (Pablo Marcos).
- Support bucketing based on partition key for S3Queue in ordered mode. #94698 (Bharat Nallan).
- Add an asynchronous metric with the longest running merge elapsed time. #94825 (Raúl Marín).
- Add belonging file check before apply position delete using IcebergBitmapPositionDeleteTransform. #94897 (Yang Jiang).
- Now
view_duration_msshows the time when group was active, not the sum of the threads duration in it. #94966 (Sema Checherinda). - Remove limit of the max number of search tokens in
hasAnyTokensandhasAllTokensfunctions which was limited to 64. Example:SELECT count() FROM table WHERE hasAllTokens(text, ['token_1', 'token_2', [...], 'token_65']]);The query would result in aBAD_ARGUMENTSerror because there are 65 search tokens. With this PR, the limit has been removed completely and the same query would run without an error. #95152 (Elmi Ahmadov). - Add a setting
input_format_numbers_enum_on_conversion_errorfor conversion from Numbers to Enums to check whether the element exists. Closes: #56144. #56240 (Nikolay Degterinsky). - Share format parser resources between data file and position delete file reading in Iceberg tables to reduce memory allocations. #94701 (Yang Jiang).
Bug Fix (user-visible misbehavior in an official stable release)
- Fixes a bug where predefined query handlers would have trailing whitespace interpreted as data during inserts. #83604 (Fabian Ponce).
- Fix INCOMPATIBLE_TYPE_OF_JOIN error for Join storage and outer to inner join optimization applied. Resolves #80794. #84292 (Vladimir Cherkasov).
- Fix exception “Invalid number of rows in Chunk” when using hash join with
allow_experimental_join_right_table_sortingenabled. #86440 (yanglongwei). - Always replace file names to hash in MergeTree if filesystem is case insensitive. Previously on systems with case insensitive filesystem (like MacOS) it could lead to data corruption when several column/subcolumn names differs only in the case. #86559 (Pavel Kruglov).
- Add a full permissions check on the create stage for the underlying query inside a materialized view. #89180 (pufit).
- Fixed crash in
icebergHashfunction on constant argument. #90335 (Michael Kolupaev). - Fix logical error when mutation without transaction mutates parts in an active transaction, which is rolled back finally. #90469 (Shaohua Wang).
- Update
system.warningscorrectly after an ordinary database was converted to an atomic database. #90473 (sdk2). - Fixes an assertion when reading from Parquet file, and part of a prewhere expression is used elsewhere in the query. #90635 (Max Kainov).
- Fix crash in a single-node cluster when reading from Iceberg in split-by-buckets mode. This closes #90913. #91553 (Konstantin Vedernikov).
- Fix possible logical error in Log engine during subcolumns reading. Closes #91710. #91711 (Pavel Kruglov).
- Fix Logical error: ‘Storage does not support transaction’ during ATTACH AS REPLICATED. #91772 (Shaohua Wang).
- Fix for runtime filters working incorrectly when LEFT ANTI JOIN has extra post-condition. #91824 (Alexander Gololobov).
- Fixes an error where we have a null-safe comparison involving the Nothing type. Closes #91834. Closes #84870. Closes #91821. #91884 (Yarik Briukhovetskyi).
- Fix DELTA_BYTE_ARRAY decoding bugs in native Parquet reader affecting highly repetitive string data. #91929 (Daniel Muino).
- Cache schema only for the file it was inferred from in globs instead of all files during schema inference. Closes #91745. #92006 (Pavel Kruglov).
- Fix the
Couldn't pack tar archive: Failed to write all byteserror caused by an incorrect archive entry size header. Fixes #89075. #92122 (Julia Kartseva). - Release request stream in insert select to prevent closing http connection. #92175 (Sema Checherinda).
- Fix logical error for queries with multiple JOINs with
USINGclause andjoin_use_nulls. #92251 (Vladimir Cherkasov). - Fix logical error while join reordering with join_use_nulls, close https://github.com/clickhouse/clickhouse/issues/90795. #92289 (Vladimir Cherkasov).
- Fix inconsistent AST formatting of arrayElement with negate literal. Closes #92288 Closes #92212 Closes #91832 Closes #91789 Closes #91735 Closes #88495 Closes #92386. #92293 (Pavel Kruglov).
- Fix a possible crash with
join_on_disk_max_files_to_mergesetting. #92335 (Bharat Nallan). - Related issue #https://github.com/ClickHouse/support-escalation/issues/6365. #92339 (Tuan Pham Anh).
- Fix missing access check in
SYSTEM SYNC FILE CACHE. Closes #92101. #92372 (Kseniia Sumarokova). - Fix
count_distinct_optimizationpass over window functions and over multiple arguments. #92376 (Raúl Marín). - Fix “Cannot write to finalized buffer” error when using certain aggregate functions with window functions. Closes #91415. #92395 (Jimmy Aguilar Mena).
- Fix logical error with
CREATE TABLE ... AS urlCluster()and database engineReplicated. Closes #92216. #92418 (Kseniia Sumarokova). - Inherit source part serialization info settings during mutation in MergeTree. It fixes possible incorrect result of the query over mutated part after changes in data types serialization. #92419 (Pavel Kruglov).
- Fix possible conflict in column and subcolumn with the same name leading in using wrong serialization and query failures. Closes #90219. Closes #85161. #92453 (Pavel Kruglov).
- Fix a
LOGICAL_ERRORs that caused by not wanted modification of query plan when converting outer join to inner join. Also relax the requirements of optimization to be able to apply it in cases when injective functions are applied to the aggregating keys during joins. #92503 (János Benjamin Antal). - Fix possible error
SIZES_OF_COLUMNS_DOESNT_MATCHduring sorting of emty tuple column. Closes #92422. #92520 (Pavel Kruglov). - Check for incompatible typed paths in JSON type. Closes #91577. #92539 (Pavel Kruglov).
- Fix deadlock for SHOW CREATE DATABASE for Backup database. #92541 (Azat Khuzhin).
- Use proper error code when validating hypothesis index. #92559 (Raúl Marín).
- Fix dynamic subcolumns resolution in column aliases in analyzer. Previously dynamic subcolumn in column alias was wrapped in
getSubcolumnand in some cases could be not resolved at all. Closes #91434. #92583 (Pavel Kruglov). - Prevent crash in tokens() with null second argument. #92586 (Raúl Marín).
- Fix potential crash caused by in place mutation of underlying const PREWHERE columns. This could’ve happened at column shrinking (
IColumn::shrinkToFit) or filtering (IColumn::filter), which could’ve triggered concurrently from several threads. #92588 (Arsen Muk). - Creating and materializing text indexes on tables containing large parts (over 4,294,967,295 rows) is temporarily disabled. This limitation prevents incorrect query results, as the current index implementation does not yet support such large parts. #92644 (Anton Popov).
- Fixes a logical error
Too large size (A) passed to allocatorwhile executing JOINs. Closes #92043. #92667 (Yarik Briukhovetskyi). - Remove a bug that
ngrambf_v1indexes with ngram length (1st parameter) > 8 would throw an exception. #92672 (Robert Schulze). - Fix uncaught exception during background named collections reload when zookeeper storage is used. Closes https://github.com/ClickHouse/clickhouse-private/issues/44180. #92717 (Kseniia Sumarokova).
- Reworks incorrect logic in access grant checks for wildcard grants. The previous attempt https://github.com/ClickHouse/ClickHouse/pull/90928 addressed a critical vulnerability but ended up being too restrictive, resulting in some wildcard
GRANTstatements failing due to unrelated revokes. #92725 (pufit). - Fix bug in data skipping logic when
not match(...)is used inWHEREcausing incorrect results. Closes #92492. #92726 (Nihal Z. Miaji). - Do not attempt to delete temporary directories at startup if a MergeTree table is created over a read-only disk. #92748 (Alexey Milovidov).
- Fix “Cannot add action to empty ExpressionActionsChain” for ALTER TABLE REWRITE PARTS (v2). #92754 (Azat Khuzhin).
- Avoid crash due to reading from a disconnected
Connection. #92807 (Raufs Dunamalijevs). - Fix logical error
Failed to set file processing within 100 retriesin storgaeS3QueueinOrderedmode. It is now replaced with a warning. This error could happen before 25.10 version if keeper session expired, however it will still be a warning in 25.10+ versions, as it is still theoretically possible to get this error in case of high processing concurrency inOrderedmode. #92814 (Kseniia Sumarokova). - Previously, some queries that used PK sharding with a false condition were failing. Now they’re not. Needed for https://github.com/ClickHouse/ClickHouse/pull/89313. #92815 (Yarik Briukhovetskyi).
- Fixed calculation of uncompressed sizes of text indexes in the
system.partstable. #92832 (Anton Popov). - Fixed usage of primary index in lightweight updates that have an
INclause with subqueries in the predicate of theWHEREclause. #92838 (Anton Popov). - Fix creating type hint for path ‘skip’ in JSON. Closes #92731. #92842 (Pavel Kruglov).
- In the S3 table engine, we should avoid caching the partition key if there are non-deterministic functions. #92844 (Miсhael Stetsyuk).
- Fix possible error
FILE_DOESNT_EXISTafter mutation of a sparse column withratio_of_defaults_for_sparse_serialization=0.0. Closes #92633. #92860 (Pavel Kruglov). - Fix parquet schema inference in the old parquet reader (not used by default) when a JSON column comes after a Tupe column. Fix the old parquet reader (not used by default) failing on empty tuples. #92867 (Michael Kolupaev).
- Fix logical error with multiple joins on constant condition and
join_use_nulls, close #92640. #92892 (Vladimir Cherkasov). - Fix possible error
NOT_FOUND_COLUMN_IN_BLOCKduring insert into a table with subcolumn in partition expression. Closes #93210. Closes #83406. #92905 (Pavel Kruglov). - Fix error
NO_SUCH_COLUMN_IN_TABLEin Merge engine over tables with aliases. Closes #88665. #92910 (Pavel Kruglov). - Fix NULL != NULL case for full_sorting_join on LowCardinality(Nullable(T)) column. #92924 (Vladimir Cherkasov).
- Fixed several crashes during merges of text indexes in
MergeTreetables. #92925 (Anton Popov). - Restore LowCardinality wrappers on SET expression results if needed during TTL aggregation to prevent exceptions during table optimization. #92971 (Seva Potapov).
- Fix logical error during index analysis when empty array is used in
hasfunction. Closes #92906. #92995 (Nihal Z. Miaji). - Fix possible hung on terminating background schedule pool (may lead to server hungs on shutdown). #93008 (Azat Khuzhin).
- Fix possible error FILE_DOESNT_EXIST after sparse column mutation when setting
ratio_of_defaults_for_sparse_serializationwas changed to1.0via alter. #93016 (Pavel Kruglov). - Fix bug in data skipping logic when
not materialize(...)ornot CAST(...)is used in WHERE causing incorrect results. Closes #88536. #93017 (Nihal Z. Miaji). - Fix possible usage of outdated parts due to TOCTOU race for shared parts. #93022 (Azat Khuzhin).
- Fix crash when deserialising malformed
groupConcataggregate state with out-of-bounds offsets. #93028 (Raufs Dunamalijevs). - Fix leaving connection in a broken state after preliminary cancellation distributed queries. #93029 (Azat Khuzhin).
- Fix join results when the right-side join key is a sparse column. This closes #92920. I can only reproduce the bug with
set compatibility='23.3'. Not sure if it should be backported. #93038 (Amos Bird). - Fix possible
Cannot finalize buffer after cancellationinestimateCompressionRatio(). Fixes: #87380. #93068 (Azat Khuzhin). - Fixed merges of text indexes built on top of the complex expressions (such as
concat(col1, col2)). #93073 (Anton Popov). - Fix applying projection when filter contains subcolumns. Closes #92882. #93141 (Pavel Kruglov).
- Fix logical error in some cases triggered when join runtime filters are added to query plan. It was caused by incorrectly returning duplicated const columns from one of join sides. #93144 (Alexander Gololobov).
- Special function
__applyFilterused by join runtime filters was returning ILLEGAL_TYPE_OF_ARGUMENT in some valid cases. #93187 (Alexander Gololobov). - Prevent different interpolated columns from collapse into the same column in a block when interpolated columns are effectively aliases of the same column. #93197 (Yakov Olkhovskiy).
- Do not add runtime filter when joining with already filled right table. #93211 (Alexander Gololobov).
- Fix keeper persistent watches cleanup after dead session. This closes #92480. #93213 (Konstantin Vedernikov).
- Fix order by tuple in iceberg. This closes #92977. #93225 (Konstantin Vedernikov).
- Fix bug with S3Queue setting
s3queue_migrate_old_metadata_to_buckets. Closes #93392, #93196, #81739. #93232 (Kseniia Sumarokova). - Remove unused columns when the projection is rebuilt during the merge. It reduces memory usage and creates fewer temporary parts. #93233 (Nikolai Kochetov).
- Fix unused columns removal from subqueries in the presence of a scalar correlated subquery. Before the fix column could have been removed if it was used only in the correlated subquery, and the query would fail with
NOT_FOUND_COLUMN_IN_BLOCKerror. #93273 (Dmitry Novik). - Fix possible missing subcolumn in MV during alter of source table. Closes #93231. #93276 (Pavel Kruglov).
- Fix the
Mergetable engine query planning with the analyzer that could throw ILLEGAL_COLUMN forhostName()when merging local and remote/Distributed tables. Closes #92059. #93286 (Jinlin). - Fixes a case where NOT IN with non-constant array arguments was returning the wrong value + Support for non-constant Array functions. Closes #14980. #93314 (Yarik Briukhovetskyi).
- Fix
Not found columnforuse_top_k_dynamic_filteringoptimization. Fixes #93186. #93316 (Nikolai Kochetov). - Fixed rebuilding of text indexes created on top of subcolumns. #93326 (Anton Popov).
- Fixed handling of empty array as a second argument in
hasAllTokensandhasAnyTokensfunctions. #93328 (Anton Popov). - Fix logical error when runtime filters are used in a query with totals for right side table. #93330 (Alexander Gololobov).
- The server no longer crashes if function
tokensis called with non-const tokenizer parameters (the 2th, 3rd, 4th parameter), e.g.,SELECT tokens(NULL, 1, materialize(1)). #93383 (Robert Schulze). - Fixed integer overflow vulnerability in
groupConcatstate deserialisation that could cause memory safety issues with crafted aggregate states. #93426 (Raufs Dunamalijevs). - Fixed text index analysis on array columns when the index contains no tokens (all arrays are empty or all tokens are skipped by the tokenizer). #93457 (Anton Popov).
- Avoids oauth login in ClickHouse Client when username/password are within the connection string. #93459 (Krishna Mannem).
- Fix Azure ADLS Gen2 vended credentials support in DataLakeCatalog - parse
adls.sas-token.*keys from Iceberg REST catalogs and fix ABFSS URL parsing. #93477 (Karun Anantharaman). - Fix GLOBAL IN support with analyzer (previously set was created on the remote node again). #93507 (Azat Khuzhin).
- Fix extracting subcolumn during deserialization directly into Sparse columns. #93512 (Pavel Kruglov).
- Fixed direct reading from text index with duplicate search queries. #93516 (Anton Popov).
- Fix for NOT_FOUND_COLUMN_IN_BLOCK error when runtime filter is enabled and joined tables have the same column returned multiple times (e.g. SELECT a, a, a FROM t). #93526 (Alexander Gololobov).
- Fix a bug where clickhouse-client would ask for password twice when connecting using ssh. #93547 (Isak Ellmer).
- Make sure that zookeeper is finalized on shutdown (fix possible hung on shutdown in very unlikely cases). #93602 (Azat Khuzhin).
- Fix LOGICAL_ERROR when restoring ReplicatedMergeTree with deduplication race. #93612 (Pablo Marcos).
- Fix using Sparse column for TTL update during direct deserialization into Sparse columns in some input formats. It fixes possible logical error
Unexpected type of result TTL column. #93619 (Pavel Kruglov). - Fixed h3 index functions sometimes crashing or getting stuck when called on invalid inputs. #93657 (Michael Kolupaev).
- The usage of
ngram_bfindex on a non-UTF-8 data led to an uninitialized memory read, with values that could reside in the resulting index structure. Closes #92576. #93663 (Alexey Milovidov). - Validate that the decompressed buffer size is as expected. #93690 (Raúl Marín).
- Prevent users to get the list of columns from a table without checking
SHOW COLUMNSpermission using themergetable engine. #93695 (János Benjamin Antal). - Fixed materialization of skip indexes created on top of subcolumns. #93708 (Anton Popov).
- We store storages’ shared pointers in
QueryPipeline::resources::storage_holdersto make sure that theIStorageobjects are not destroyed whilePipelineExecutoris alive. #93746 (Miсhael Stetsyuk). - Fix attaching Replicated DBs when the interserver host changed after restarting. #93779 (Tuan Pham Anh).
- Fix assert
!read_until_positioninReadBufferFromS3which happened when cache is enabled. #93809 (Kseniia Sumarokova). - Fix logical error in a rare case when empty tuple is used with
Mapcolumn. Closes #93784. #93814 (Nihal Z. Miaji). - Fixed
_part_offsetcorruption when projections are rebuilt during merges, and optimized projection processing by avoiding unnecessary reads of the_part_offsetcolumn and skipping unneeded columns in projection calculations. This continues the optimizations introduced in #93233. #93827 (Amos Bird). - Remove ‘Bad version’ handling. #93843 (Anton Ivashkin).
- Fix
optimize_inverse_dictionary_lookupnot working with distributed query when key is signed integral type. Closes #93259. #93848 (Nihal Z. Miaji). - Fix
lag/leadnot working with distributedremote()query. Closes #90014. #93858 (Nihal Z. Miaji). - Fix system instrument dispatch bug. #93937 (Pablo Marcos).
- In https://github.com/ClickHouse/ClickHouse/pull/89173, we added an extra field to the structure that
TraceSendersends through an internal pipe. However, the buffer size was not updated (here), therefore we are writing more data to buffer thanbuffer_sizewhich results in multiple flushes. And becauseTraceSender::sendis called from different threads, different threads’ flushes may interleave which breaks the invariant that the receiving end (TraceCollector) relies on. #93966 (Miсhael Stetsyuk). - Fix type conversion to super type during the join operation of the storage
JoinwithUSINGclause. Fixes #91672. Fixes #78572. #94000 (Dmitry Novik). - Fix for FilterStep not properly added when join runtime filter is applied over Merge table. #94021 (Alexander Gololobov).
- A
SELECTquery containing a predicate on multiple columns with bloom filter skip indexes and bothORandNOTconditions are present could return inconsistent results. That is fixed now. #94026 (Shankar Iyer). - Fix CLEAR column with dependent indices. #94057 (Raúl Marín).
- Fix use-of-uninitialized-value in
ReadWriteBufferFromHTTP. #94058 (Alexey Milovidov). - Fix bad check for typed paths in JSON. The check was introduced in https://github.com/ClickHouse/ClickHouse/pull/92842 and can lead to an error during existing tables startup. #94070 (Pavel Kruglov).
- Fix the crash during filter analysis in the presence of OUTER JOIN. Fixes #90979. #94080 (Dmitry Novik).
- Fix accuracy of
uniqThetawhen using UInt8 aggregation keys in parallel (max_threads> 1 - default). #94095 (Azat Khuzhin). - Fix crash caused by exception thrown from a
socket.setBlocking(true)call insideSCOPE_EXIT. #94100 (Miсhael Stetsyuk). - Fix data loss when
DROP PARTITIONremoves parts created by later log entries in ReplicatedMergeTree. #94123 (Tuan Pham Anh). - Fixed parquet reader v3 incorrectly handling arrays that cross page boundaries. This happens e.g. for files written by Arrow without enabling page statistics or page index. Affects only columns of Array data type. Likely symptom is that one array every ~1 MB of data gets truncated. Before this fix, use this setting as workaround:
input_format_parquet_use_native_reader_v3 = 0. #94125 (Michael Kolupaev). - Fix too many watches in ReplicatedMergeTree while waiting for log entry. #94133 (Azat Khuzhin).
- Functions
arrayShuffle,arrayPartialShuffleandarrayRandomSampleto materialize const columns - so that different rows get different results. #94134 (Joanna Hulboj). - Fix data race in evaluating table functions in materialized views. #94171 (Alexey Milovidov).
- Fix nullptr dereference in
PostgreSQLdatabase engines (when the query is incorrect). Closes #92887. #94180 (Alexey Milovidov). - Fix memory leak in refreshable materialized views using
SELECTqueries with multiple subqueries. #94200 (Antonio Andelic). - Fix data race in
DataPartStorageOnDiskBase::removevssystem.parts. Closes #49076. #94262 (Alexey Milovidov). - Remove the wrong
noexceptspecifier at HashTable copy assignment that may lead to crash (std::terminate) on memory exceptions. #94275 (Nikita Taranov). - Previously, creating a projection with duplicate columns in GROUP BY (e.g.,
GROUP BY c0, c0) and inserting data caused astd::length_errorifoptimize_row_orderis enabled. Closes #94065. #94277 (Alexey Milovidov). - Fix obscure bug in ZooKeeper client on connect which leads to hungs and crashes. #94320 (Azat Khuzhin).
- Fix function to subcolumns optimization not applied to subcolumns. #94323 (Pavel Kruglov).
- Fix possibly incorrect result in nested RIGHT JOINs when
enable_lazy_columns_replicationis enabled. The bug caused all rows in replicated columns to incorrectly return the same value instead of their distinct values. Close #93891. #94339 (Vladimir Cherkasov). - Fix filter pushdown for SEMI JOIN using equivalence sets. Do not push the filter down if argument types have changed. Fixes #93264. #94340 (Dmitry Novik).
- Fix usage of DeltaLake CDF with database DataLake database engine (delta lake catalogs integration). Closes #94122. #94342 (Kseniia Sumarokova).
- Fix incorrect value of current metric
FilesystemCacheSizeLimitin caseSLRUcache policy was used. #94363 (Kseniia Sumarokova). - Creating a Backup database engine with less than two arguments now returns a more descriptive error message (
Wrong number of argumentsinstead ofstd::out_of_range: InlinedVector::at(size_type) const failed bounds check.). #94374 (Robert Schulze). - Ignores impossible revokes of global grants on the database level for grants with grant option. #94386 (pufit).
- Fix reading sparse offsets from compact parts. Closes #94385. #94399 (Pavel Kruglov).
- Don’t prevent ALTER of columns using implicit indexes, even if
alter_column_secondary_index_mode’sthrowmode is used. #94425 (Raúl Marín). - Fix crash in
TCPHandlerwhen multiplereceivePacketsExpectQuerycalls readProtocol::Client::IgnoredPartUUIDs. #94434 (Miсhael Stetsyuk). - Fix masking sensitive data in
system.functions. #94436 (Vitaly Baranov). - Fix nullptr dereference with disabled
send_profile_events. This feature was introduced recently for the ClickHouse Python driver. Closes #92488. #94466 (Alexey Milovidov). - Fix text index .mrk incompatibility during merges. #94494 (Peng Jian).
- When
read_in_order_use_virtual_rowis enabled, the code was accessing index columns based on the full primary key size without checking if the index was truncated, leading to use-after-free / uninitialized memory. Closes #85596. #94500 (Alexey Milovidov). - Fix an error due to a type mismatch when sending external tables for subqueries with GLOBAL IN if the types are Nullable. Closes #94097. #94511 (Alexey Milovidov).
- In previous versions, queries with multiple index conditions over the same expression may erroneously throw an exception
Not found column. Closes #60660. #94515 (Alexey Milovidov). - Fix incorrect handling of Nullable join column in runtime filters. #94555 (Alexander Gololobov).
- Creating a workload in another workload that is currently in use no longer causes a crash. #94599 (Sergei Trifonov).
- Fix a crash during ANY LEFT JOIN optimization when
isNotNullis evaluated on a missing column. #94600 (Molly). - Fix default expression evaluation when referencing other columns with computed defaults. #94615 (Alexey Milovidov).
- Fix permission issues in BACKUP/RESTORE operations. #94617 (Pablo Marcos).
- Fix crash due to incorrect type cast when the data type is
Nullable(DateTime64). #94627 (Miсhael Stetsyuk). - Fixes a bug where certain distributed queries with
ORDER BYcould returnALIAScolumns with swapped values (i.e., columnashowing columnb’s data and vice versa). #94644 (filimonov). - Fix storing results of keeper-bench to file. #94654 (Antonio Andelic).
- Fix incorrect estimations with MinMax-type statistics when the column contains negative floating-point values. #94665 (zoomxi).
- Fix reading Parquet files when a map’s key is a struct. #94670 (Konstantin Vedernikov).
- Fix possibly incorrect RIGHT join result when using complex ON conditions. Close #92913. #94680 (Vladimir Cherkasov).
- Preserve constant index granularity (use_const_adaptive_granularity) after Vertical merges. #94725 (Azat Khuzhin).
- Fix mutation bug with scalar subqueries and table dependencies. If a table had dependencies (index or projections) over a column, scalar subqueries might be evaluated and cached without data and lead to incorrect changes. #94731 (Raúl Marín).
- Fix AsynchronousMetrics cpu_pressure fallback on error. #94827 (Raúl Marín).
- The
getURLHostRFCfunction was missing bounds checks before dereferencing pointers. When an empty string was passed todomainRFC, it would read uninitialized memory, triggering MSan errors. #94851 (Alexey Milovidov). - Fix readonlyness of encrypted disks. #94852 (Azat Khuzhin).
- Fix logical error in fractional
LIMIT/OFFSETwhen using the old analyzer with Distributed tables. Closes #94712. #94999 (Ahmed Gouda). - Fix crash under some conditions when join runtime filters are enabled by default. #95000 (Alexander Gololobov).
- Improve masking passwords in url used in table engine
URL()and table functionurl(). #95006 (Vitaly Baranov). - Function
toStartOfIntervalnow works in the same way astoStartOfX, whereXisDay, Week, Month, Quarter, Yearwhen theenable_extended_results_for_datetime_functionsis on. #95011 (Kirill Kopnev). - Fix constant string comparisons not respecting the settings
cast_string_to_date_time_mode,bool_true_representation,bool_false_representation, andinput_format_null_as_default. Closes #91681. #95040 (Nihal Z. Miaji). - Fix data race in the filesystem cache. #95064 (Alexey Milovidov).
- Fix a rare race condition in the Parquet reader. #95068 (Alexey Milovidov).
- Fix crash in the top K optimization when
LIMITis zero. Closes #93893. #95072 (Alexey Milovidov). - Converting from DateTime/integers to Time64 extracts the time-of-day component using
toTime, which is not monotonic. TheToDateTimeMonotonicitytemplate incorrectly claimed this conversion was monotonic, causing “Invalid binary search result in MergeTreeSetIndex” exception in debug builds. #95125 (Alexey Milovidov). - Recreated list of manifest file entries only if necessary (previously it was done on each iteration). #95162 (Daniil Ivanik).
Build/Testing/Packaging Improvement
- Add a set of tools for profiling memory allocations in the ClickHouse SQL parser using jemalloc’s heap profiling capabilities. #94072 (Ilya Yatsishin).
- Added a tool that simplifies debugging of memory allocations in parser. It uses jemalloc
stats.allocatedmetric before and after we parse query to AST representation to show what is allocated. Also it supports memory profiling mode that dumps profile before and after to build reports where allocations occurred. #93523 (Ilya Yatsishin). - Remove transitive libc++ includes. #92523 (Raúl Marín).
- Make some sequential tests parallel: https://github.com/ClickHouse/ClickHouse/pull/93030/changes#diff-c3a73510dae653c9bbfa24300b32f5d6ec663fd4e72cc4a3d5daa6e4342915df. #93030 (Nikita Fomichev).
- Cleanup some build flags. #93679 (Raúl Marín).
- Bump c-ares from v1.34.5 to v1.34.6. This addresses c-ares’
CVE-2025-62408, which is not relevant for ClickHouse. #94129 (Govind R Nair). - Use
curl8.18.0. #94742 (Konstantin Bogdanov).