diff --git a/src/Storages/MergeTree/MergeTask.cpp b/src/Storages/MergeTree/MergeTask.cpp index 5b8df976d475..1c543f2f5491 100644 --- a/src/Storages/MergeTree/MergeTask.cpp +++ b/src/Storages/MergeTree/MergeTask.cpp @@ -532,9 +532,7 @@ bool MergeTask::ExecuteAndFinalizeHorizontalPart::prepare() const !patch_parts.empty() || global_ctx->cleanup || global_ctx->deduplicate || - global_ctx->merging_params.mode == MergeTreeData::MergingParams::Collapsing || - global_ctx->merging_params.mode == MergeTreeData::MergingParams::Replacing || - global_ctx->merging_params.mode == MergeTreeData::MergingParams::VersionedCollapsing; + global_ctx->merging_params.mode != MergeTreeData::MergingParams::Ordinary; prepareProjectionsToMergeAndRebuild(); diff --git a/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.reference b/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.reference new file mode 100644 index 000000000000..5d778a7b1b43 --- /dev/null +++ b/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.reference @@ -0,0 +1,3 @@ +coalescing 1 +summing 1 +aggregating 1 diff --git a/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.sql b/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.sql new file mode 100644 index 000000000000..0c88a200237c --- /dev/null +++ b/tests/queries/0_stateless/03786_projection_part_offset_reducing_merge.sql @@ -0,0 +1,67 @@ +-- Regression test for a crash (Logical error: 'page_pos < pages.size()') that happened when +-- OPTIMIZE-ing a table whose engine combines rows (Coalescing/Summing/Aggregating/...) and that +-- has a projection carrying the parent _part_offset. +-- +-- Such merges reduce rows, so the source-to-merged offset mapping is incomplete and the projection +-- must be rebuilt rather than merged. Before the fix these engines were missing from +-- merge_may_reduce_rows, so the projection was merged and the offset remap read out of bounds. +-- +-- The self-join below checks that every rebuilt projection row points back to the base row with the +-- same key, i.e. its stored _parent_part_offset equals the base _part_offset. + +DROP TABLE IF EXISTS t_coalescing; +CREATE TABLE t_coalescing +( + a Int32, + v Nullable(Int64), + PROJECTION p (SELECT a, _part_offset ORDER BY a) +) +ENGINE = CoalescingMergeTree +ORDER BY a +SETTINGS deduplicate_merge_projection_mode = 'rebuild'; + +INSERT INTO t_coalescing SELECT number, number FROM numbers(1000); +INSERT INTO t_coalescing SELECT number, NULL FROM numbers(1000); +OPTIMIZE TABLE t_coalescing FINAL; +SELECT 'coalescing', count() = sum(l._part_offset = r._parent_part_offset) +FROM t_coalescing l JOIN mergeTreeProjection(currentDatabase(), t_coalescing, p) r USING (a) +SETTINGS enable_analyzer = 1; +DROP TABLE t_coalescing; + +DROP TABLE IF EXISTS t_summing; +CREATE TABLE t_summing +( + a Int32, + v Int64, + PROJECTION p (SELECT a, _part_offset ORDER BY a) +) +ENGINE = SummingMergeTree +ORDER BY a +SETTINGS deduplicate_merge_projection_mode = 'rebuild'; + +INSERT INTO t_summing SELECT number, 1 FROM numbers(1000); +INSERT INTO t_summing SELECT number, 10 FROM numbers(1000); +OPTIMIZE TABLE t_summing FINAL; +SELECT 'summing', count() = sum(l._part_offset = r._parent_part_offset) +FROM t_summing l JOIN mergeTreeProjection(currentDatabase(), t_summing, p) r USING (a) +SETTINGS enable_analyzer = 1; +DROP TABLE t_summing; + +DROP TABLE IF EXISTS t_aggregating; +CREATE TABLE t_aggregating +( + a Int32, + v SimpleAggregateFunction(sum, Int64), + PROJECTION p (SELECT a, _part_offset ORDER BY a) +) +ENGINE = AggregatingMergeTree +ORDER BY a +SETTINGS deduplicate_merge_projection_mode = 'rebuild'; + +INSERT INTO t_aggregating SELECT number, 1 FROM numbers(1000); +INSERT INTO t_aggregating SELECT number, 10 FROM numbers(1000); +OPTIMIZE TABLE t_aggregating FINAL; +SELECT 'aggregating', count() = sum(l._part_offset = r._parent_part_offset) +FROM t_aggregating l JOIN mergeTreeProjection(currentDatabase(), t_aggregating, p) r USING (a) +SETTINGS enable_analyzer = 1; +DROP TABLE t_aggregating;