Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6f9244b
Backport #101936 to 25.8: Fix SIGSEGV in MergeTreeDataPartWriterWide:…
robot-clickhouse Apr 10, 2026
fb6469f
Backport #102606 to 25.8: Use `openssl` 3.5.6
robot-clickhouse Apr 15, 2026
879c46a
Pick changes from `bump-openssl-3.5.6`
thevar1able Apr 15, 2026
88b09dd
Fix build
thevar1able Apr 15, 2026
3f492ad
Fix build
thevar1able Apr 15, 2026
9a12454
Fix build
thevar1able Apr 15, 2026
360cc02
Merge pull request #102819 from ClickHouse/backport/25.8/102606
thevar1able Apr 16, 2026
e83a9e5
Backport #102674 to 25.8: Fix wrong date data type inference in case …
robot-clickhouse Apr 17, 2026
659b38c
Backport #102915 to 25.8: Optimize row policy OR-chains to IN in the …
robot-clickhouse Apr 17, 2026
3f6c029
Update autogenerated version to 25.8.22.28 and contributors
robot-clickhouse Apr 17, 2026
9201c77
Upgrade distroless base image from cc-debian12 to cc-debian13
motsc Apr 20, 2026
15e6e32
Merge pull request #103154 from ClickHouse/backport/25.8/distroless-d…
clickhouse-gh[bot] Apr 20, 2026
42b3a5f
Backport #103160 to 25.8: CI: disable automerge for backport branches
robot-clickhouse Apr 20, 2026
e01d4a3
Merge pull request #102968 from ClickHouse/backport/25.8/102674
Avogar Apr 20, 2026
bb6aa71
Backport #101918 to 25.8: Fix using wrong extreams in min-max index c…
robot-clickhouse Apr 20, 2026
9bb23d7
Merge pull request #103175 from ClickHouse/backport/25.8/103160
maxknv Apr 21, 2026
ac8c55c
Update 04098_row_policy_disjunction_optimization
azat Apr 21, 2026
44d8b06
Merge pull request #103018 from ClickHouse/backport/25.8/102915
azat Apr 21, 2026
e854a5f
Backport #102692 to 25.8: Fix flattened Dynamic type serialization wi…
robot-clickhouse Apr 21, 2026
5005b3c
Merge pull request #103300 from ClickHouse/backport/25.8/102692
Avogar Apr 22, 2026
4cce3bd
Update test reference
Avogar Apr 22, 2026
457bc28
Backport #103392 to 25.8: Check for malformed flattened Dynamic data …
robot-clickhouse Apr 23, 2026
a7ab2db
Merge pull request #103408 from ClickHouse/backport/25.8/103392
Avogar Apr 23, 2026
d4be641
Merge pull request #103184 from ClickHouse/backport/25.8/101918
Avogar Apr 23, 2026
5f8b23c
Refresh distroless base image digests to pick up libssl3t64 3.5.5-1~d…
motsc Apr 27, 2026
ce36607
Merge pull request #103582 from ClickHouse/backport/25.8/distroless-d…
motsc Apr 27, 2026
ebe77ef
Backport #103334 to 25.8: Fix Parquet ColumnIndex stats min_value > m…
robot-ch-test-poll1 Apr 28, 2026
e69ef71
Backport #103834 to 25.8: Reliable key receiving from a chain of keys…
robot-clickhouse May 1, 2026
df70b65
Merge pull request #103868 from ClickHouse/backport/25.8/103834
alexey-milovidov May 1, 2026
443620d
Merge pull request #102352 from ClickHouse/backport/25.8/101936
Algunenano May 4, 2026
ed89292
Merge tag 'v25.8.23.13-lts' into bump/antalya-25.8/25.8.23
zvonand May 7, 2026
c203250
Fix 02735_parquet_encoder reference for new string stats behavior
zvonand May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/workflows/backport_branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
enable_job_filtering_by_changes=True,
enable_cache=True,
enable_report=True,
enable_automerge=True,
enable_automerge=False,
enable_cidb=True,
enable_commit_status_on_failure=True,
pre_hooks=[
Expand Down
10 changes: 5 additions & 5 deletions cmake/autogenerated_versions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

# NOTE: VERSION_REVISION has nothing common with DBMS_TCP_PROTOCOL_VERSION,
# only DBMS_TCP_PROTOCOL_VERSION should be incremented on protocol changes.
SET(VERSION_REVISION 54522)
SET(VERSION_REVISION 54523)
SET(VERSION_MAJOR 25)
SET(VERSION_MINOR 8)
SET(VERSION_PATCH 22)
SET(VERSION_GITHASH 099badce0f7744623716d4efa2971d3e1c63d1cf)
SET(VERSION_DESCRIBE v25.8.22.20001.altinityantalya)
SET(VERSION_STRING 25.8.22.20001.altinityantalya)
SET(VERSION_PATCH 23)
SET(VERSION_GITHASH 6d29497525664acca46a1d1cd0d5787e9ad0857d)
SET(VERSION_DESCRIBE v25.8.23.20001.altinityantalya)
SET(VERSION_STRING 25.8.23.20001.altinityantalya)
# end of autochange

SET(VERSION_TWEAK 20001)
Expand Down
27 changes: 17 additions & 10 deletions docker/keeper/Dockerfile.distroless
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# The entrypoint is the compiled `clickhouse docker-init --keeper` subcommand.
#
# Build targets:
# production — gcr.io/distroless/cc-debian12:nonroot (default)
# debug — gcr.io/distroless/cc-debian12:debug-nonroot (includes busybox shell)
# production — gcr.io/distroless/cc-debian13:nonroot (default)
# debug — gcr.io/distroless/cc-debian13:debug-nonroot (includes busybox shell)
#
# Usage:
# docker build -f Dockerfile.distroless --target production -t clickhouse/clickhouse-keeper:distroless .
Expand Down Expand Up @@ -80,10 +80,17 @@ RUN clickhouse local -q 'SELECT 1' >/dev/null 2>&1 && exit 0 || : \
&& apt-get install --yes --no-install-recommends dirmngr gnupg2 \
&& mkdir -p /etc/apt/sources.list.d \
&& GNUPGHOME=$(mktemp -d) \
&& GNUPGHOME="$GNUPGHOME" gpg --batch --no-default-keyring \
--keyring /usr/share/keyrings/clickhouse-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 \
--recv-keys 3a9ea1193a97b548be1457d48919f6bd2b48d754 \
&& ( set +e; \
for KEYSERVER in \
hkp://keys.openpgp.org:80 \
hkp://pgp.mit.edu:80 \
hkp://keyserver.ubuntu.com:80; do \
GNUPGHOME="$GNUPGHOME" gpg --batch --no-default-keyring \
--keyring /usr/share/keyrings/clickhouse-keyring.gpg \
--keyserver "$KEYSERVER" \
--recv-keys 3a9ea1193a97b548be1457d48919f6bd2b48d754 && break; \
done || exit 1 \
) \
&& rm -rf "$GNUPGHOME" \
&& chmod +r /usr/share/keyrings/clickhouse-keyring.gpg \
&& echo "${REPOSITORY}" > /etc/apt/sources.list.d/clickhouse.list \
Expand Down Expand Up @@ -138,8 +145,8 @@ RUN mkdir -p \
# ──────────────────────────────────────────────────────────────────────────────
# Stage 2: Production distroless image.
# ──────────────────────────────────────────────────────────────────────────────
# Pinned 2026-03-10. Refresh: docker pull gcr.io/distroless/cc-debian12:nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian12:nonroot
FROM gcr.io/distroless/cc-debian12:nonroot@sha256:7e5b8df2f4d36f5599ef4ab856d7d444922531709becb03f3368c6d797d0a5eb AS production
# Pinned 2026-04-26. Refresh: docker pull gcr.io/distroless/cc-debian13:nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian13:nonroot
FROM gcr.io/distroless/cc-debian13:nonroot@sha256:8f960b7fc6a5d6e28bb07f982655925d6206678bd9a6cde2ad00ddb5e2077d78 AS production

COPY --from=ch-builder /output/ /

Expand All @@ -161,8 +168,8 @@ ENTRYPOINT ["/usr/bin/clickhouse", "docker-init", "--keeper"]
# Stage 3: Debug image — same as production but includes the busybox shell
# at /busybox/sh for interactive troubleshooting.
# ──────────────────────────────────────────────────────────────────────────────
# Pinned 2026-03-10. Refresh: docker pull gcr.io/distroless/cc-debian12:debug-nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian12:debug-nonroot
FROM gcr.io/distroless/cc-debian12:debug-nonroot@sha256:641f055b21555d5e4f77b7f1f3caca80840a76c4f7ae5df36a159a436941d2c2 AS debug
# Pinned 2026-04-26. Refresh: docker pull gcr.io/distroless/cc-debian13:debug-nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian13:debug-nonroot
FROM gcr.io/distroless/cc-debian13:debug-nonroot@sha256:55dd32378f7562c890342098a04726f4ef386bb86c87bec3db6ed4eef27d99fb AS debug

COPY --from=ch-builder /output/ /

Expand Down
27 changes: 17 additions & 10 deletions docker/server/Dockerfile.distroless
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# The entrypoint is the compiled `clickhouse docker-init` subcommand.
#
# Build targets:
# production — gcr.io/distroless/cc-debian12:nonroot (default)
# debug — gcr.io/distroless/cc-debian12:debug-nonroot (includes busybox shell)
# production — gcr.io/distroless/cc-debian13:nonroot (default)
# debug — gcr.io/distroless/cc-debian13:debug-nonroot (includes busybox shell)
#
# Usage:
# docker build -f Dockerfile.distroless --target production -t clickhouse/clickhouse-server:distroless .
Expand Down Expand Up @@ -87,10 +87,17 @@ RUN clickhouse local -q 'SELECT 1' >/dev/null 2>&1 && exit 0 || : \
&& apt-get install --yes --no-install-recommends dirmngr gnupg2 \
&& mkdir -p /etc/apt/sources.list.d \
&& GNUPGHOME=$(mktemp -d) \
&& GNUPGHOME="$GNUPGHOME" gpg --batch --no-default-keyring \
--keyring /usr/share/keyrings/clickhouse-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 \
--recv-keys 3a9ea1193a97b548be1457d48919f6bd2b48d754 \
&& ( set +e; \
for KEYSERVER in \
hkp://keys.openpgp.org:80 \
hkp://pgp.mit.edu:80 \
hkp://keyserver.ubuntu.com:80; do \
GNUPGHOME="$GNUPGHOME" gpg --batch --no-default-keyring \
--keyring /usr/share/keyrings/clickhouse-keyring.gpg \
--keyserver "$KEYSERVER" \
--recv-keys 3a9ea1193a97b548be1457d48919f6bd2b48d754 && break; \
done || exit 1 \
) \
&& rm -rf "$GNUPGHOME" \
&& chmod +r /usr/share/keyrings/clickhouse-keyring.gpg \
&& echo "${REPOSITORY}" > /etc/apt/sources.list.d/clickhouse.list \
Expand Down Expand Up @@ -156,8 +163,8 @@ RUN { \
# ──────────────────────────────────────────────────────────────────────────────
# Stage 2: Production distroless image.
# ──────────────────────────────────────────────────────────────────────────────
# Pinned 2026-03-10. Refresh: docker pull gcr.io/distroless/cc-debian12:nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian12:nonroot
FROM gcr.io/distroless/cc-debian12:nonroot@sha256:7e5b8df2f4d36f5599ef4ab856d7d444922531709becb03f3368c6d797d0a5eb AS production
# Pinned 2026-04-26. Refresh: docker pull gcr.io/distroless/cc-debian13:nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian13:nonroot
FROM gcr.io/distroless/cc-debian13:nonroot@sha256:8f960b7fc6a5d6e28bb07f982655925d6206678bd9a6cde2ad00ddb5e2077d78 AS production

COPY --from=ch-builder /output/ /

Expand All @@ -179,8 +186,8 @@ ENTRYPOINT ["/usr/bin/clickhouse", "docker-init"]
# Stage 3: Debug image — same as production but includes the busybox shell
# at /busybox/sh for interactive troubleshooting.
# ──────────────────────────────────────────────────────────────────────────────
# Pinned 2026-03-10. Refresh: docker pull gcr.io/distroless/cc-debian12:debug-nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian12:debug-nonroot
FROM gcr.io/distroless/cc-debian12:debug-nonroot@sha256:641f055b21555d5e4f77b7f1f3caca80840a76c4f7ae5df36a159a436941d2c2 AS debug
# Pinned 2026-04-26. Refresh: docker pull gcr.io/distroless/cc-debian13:debug-nonroot && docker inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian13:debug-nonroot
FROM gcr.io/distroless/cc-debian13:debug-nonroot@sha256:55dd32378f7562c890342098a04726f4ef386bb86c87bec3db6ed4eef27d99fb AS debug

COPY --from=ch-builder /output/ /

Expand Down
24 changes: 17 additions & 7 deletions src/Columns/ColumnObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1505,16 +1505,26 @@ bool ColumnObject::isFinalized() const

void ColumnObject::getExtremes(DB::Field & min, DB::Field & max) const
{
min = Object();
max = Object();

if (empty())
return;

size_t min_idx = 0;
size_t max_idx = 0;

size_t end = size();
for (size_t i = 1; i < end; ++i)
{
min = Object();
max = Object();
}
else
{
get(0, min);
get(0, max);
if (compareAt(i, min_idx, *this, /* nan_direction_hint = */ 1) < 0)
min_idx = i;
else if (compareAt(i, max_idx, *this, /* nan_direction_hint = */ -1) > 0)
max_idx = i;
}

get(min_idx, min);
get(max_idx, max);
}

void ColumnObject::prepareForSquashing(const std::vector<ColumnPtr> & source_columns, size_t factor)
Expand Down
3 changes: 2 additions & 1 deletion src/Common/FailPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ static struct InitFiu
REGULAR(patch_parts_reverse_column_order) \
ONCE(smt_commit_exception_before_op) \
ONCE(backup_add_empty_memory_table) \
REGULAR(refresh_task_stop_racing_for_running_refresh)
REGULAR(refresh_task_stop_racing_for_running_refresh) \
REGULAR(wide_part_writer_fail_in_add_streams)


namespace FailPoints
Expand Down
2 changes: 1 addition & 1 deletion src/DataTypes/Serializations/SerializationDynamic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ void SerializationDynamic::serializeBinaryBulkStatePrefix(
for (const auto & type : flattened_column.types)
{
if (settings.native_format && settings.format_settings && settings.format_settings->native.encode_types_in_binary_format)
encodeDataType(type);
encodeDataType(type, *stream);
else
writeStringBinary(type->getName(), *stream);
}
Expand Down
12 changes: 12 additions & 0 deletions src/DataTypes/Serializations/SerializationDynamicHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace DB
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
extern const int INCORRECT_DATA;
}

namespace
Expand Down Expand Up @@ -157,6 +158,17 @@ void fillDynamicColumn(
for (size_t i = 0; i != indexes_data.size(); ++i)
{
auto index = indexes_data[i];
if (index > null_index)
throw Exception(
ErrorCodes::INCORRECT_DATA,
"Incorrect index {} in indexes column of flattened Dynamic column at row {}: "
"the index should be in range [0, {}] (there are {} types, index {} is reserved for NULL values)",
static_cast<UInt64>(index),
i,
null_index,
flattened_column.types.size(),
null_index);

if (index == null_index)
{
local_discriminators.push_back(ColumnVariant::NULL_DISCRIMINATOR);
Expand Down
9 changes: 9 additions & 0 deletions src/IO/parseDateTimeBestEffort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,15 @@ ReturnType parseDateTimeBestEffortImpl(
}
res = *res_maybe;
adjust_time_zone();

/// After timezone adjustment, the value may have shifted outside the valid range.
/// For example, "2106-02-07 06:28:15-01:00" is within range before adjustment,
/// but after converting to UTC it exceeds UINT32_MAX.
if constexpr (!is_64)
{
if (res < 0 || static_cast<uint64_t>(res) > UINT32_MAX)
return false;
}
}
else
{
Expand Down
7 changes: 7 additions & 0 deletions src/Planner/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <Analyzer/JoinNode.h>
#include <Analyzer/QueryTreeBuilder.h>
#include <Analyzer/Passes/QueryAnalysisPass.h>
#include <Analyzer/Passes/LogicalExpressionOptimizerPass.h>
#include <Analyzer/WindowNode.h>

#include <Core/Settings.h>
Expand Down Expand Up @@ -536,6 +537,12 @@ FilterDAGInfo buildFilterInfo(ASTPtr filter_expression,
QueryAnalysisPass query_analysis_pass(table_expression);
query_analysis_pass.run(filter_query_tree, query_context);

/// Optimize logical expressions in the filter, e.g. convert OR-chains of
/// equalities into IN (important for row policies that produce many
/// permissive conditions like `x = 1 OR x = 2 OR ... OR x = N`).
LogicalExpressionOptimizerPass logical_expression_optimizer_pass;
logical_expression_optimizer_pass.run(filter_query_tree, query_context);

return buildFilterInfo(std::move(filter_query_tree), table_expression, planner_context, std::move(table_expression_required_names_without_filter));
}

Expand Down
17 changes: 11 additions & 6 deletions src/Processors/Formats/Impl/Parquet/Write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,12 @@ struct StatisticsStringRef
parq::Statistics s;
if (min.ptr == nullptr)
return s;
if (static_cast<size_t>(min.len) <= options.max_statistics_size)
if (static_cast<size_t>(min.len) <= options.max_statistics_size
&& static_cast<size_t>(max.len) <= options.max_statistics_size)
{
s.__set_min_value(std::string(reinterpret_cast<const char *>(min.ptr), static_cast<size_t>(min.len)));
s.__set_is_min_value_exact(true);
}
if (static_cast<size_t>(max.len) <= options.max_statistics_size)
{
s.__set_max_value(std::string(reinterpret_cast<const char *>(max.ptr), static_cast<size_t>(max.len)));
s.__set_is_min_value_exact(true);
s.__set_is_max_value_exact(true);
}
return s;
Expand All @@ -251,7 +249,7 @@ struct StatisticsStringRef
int t = memcmp(a.ptr, b.ptr, std::min(a.len, b.len));
if (t != 0)
return t;
return a.len - b.len;
return int(a.len) - int(b.len);
}
};

Expand Down Expand Up @@ -834,6 +832,10 @@ void writeColumnImpl(
if (options.write_page_index)
{
bool all_null_page = data_count == 0;
bool has_stats = page_stats.__isset.min_value && page_stats.__isset.max_value;
if (!all_null_page && !has_stats)
s.indexes.column_index_valid = false;

s.indexes.column_index.min_values.push_back(page_stats.min_value);
s.indexes.column_index.max_values.push_back(page_stats.max_value);
if (has_null_count)
Expand Down Expand Up @@ -1276,6 +1278,9 @@ static void writePageIndex(FileWriteState & file, WriteBuffer & out)
chassert(rg.column_indexes.size() == rg.row_group.columns.size());
for (size_t j = 0; j < rg.column_indexes.size(); ++j)
{
if (!rg.column_indexes.at(j).column_index_valid)
continue;

auto & column = rg.row_group.columns.at(j);
column.__set_column_index_offset(file.offset);
size_t length = serializeThriftStruct(rg.column_indexes.at(j).column_index, out);
Expand Down
3 changes: 3 additions & 0 deletions src/Processors/Formats/Impl/Parquet/Write.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct ColumnChunkIndexes
{
parq::ColumnIndex column_index; // if write_page_index
parq::OffsetIndex offset_index; // if write_page_index
/// Set to false when a non-null page has stats dropped (e.g. value exceeded max_statistics_size).
/// When false, the column index must not be written because it would contain invalid bounds.
bool column_index_valid = true;
parq::BloomFilterHeader bloom_filter_header;
PODArray<UInt32> bloom_filter_data; // if write_bloom_filter, and not flushed yet
};
Expand Down
42 changes: 42 additions & 0 deletions src/Processors/tests/gtest_write_parquet_page_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,5 +367,47 @@ TEST(Parquet, WriteParquetPageIndexArrowEncoder)
/// arrow doesn't write statistics to data page headers
/*expect_statistics_in_page_headers*/ false);
}

/// Regression test for https://github.com/ClickHouse/ClickHouse/issues/103039
/// When a page has a short min and a long max (exceeding max_statistics_size=4096),
/// the column index must not be written because it would contain invalid bounds
/// (e.g. min_value="a", max_value="" which violates min <= max).
TEST(Parquet, WriteParquetPageIndexOversizedStringStats)
{
FormatSettings format_settings;
format_settings.parquet.row_group_rows = 10000;
format_settings.parquet.use_custom_encoder = true;
format_settings.parquet.parallel_encoding = false;
format_settings.parquet.write_page_index = true;
format_settings.parquet.data_page_size = 32;

std::vector<std::vector<String>> values;
std::vector<String> col;
col.push_back("a");
col.push_back(String(5000, 'z'));
values.push_back(col);

auto source = multiColumnsSource<String>(
{std::make_shared<DataTypeString>()}, values, 1);
String path = "/tmp/test_oversized_stats.parquet";
writeParquet(source, format_settings, path);

auto reader = parquet::ParquetFileReader::OpenFile(path);
auto metadata = reader->metadata();

ASSERT_EQ(metadata->num_row_groups(), 1);
auto row_group = metadata->RowGroup(0);
ASSERT_EQ(row_group->num_columns(), 1);

auto column_chunk = row_group->ColumnChunk(0);
auto column_index_location = column_chunk->GetColumnIndexLocation();
auto offset_index_location = column_chunk->GetOffsetIndexLocation();

ASSERT_FALSE(column_index_location.has_value());

ASSERT_TRUE(offset_index_location.has_value());
ASSERT_GT(offset_index_location.value().offset, 0);
ASSERT_GT(offset_index_location.value().length, 0);
}
}
#endif
Loading
Loading