Merge pull request #71553 from ClickHouse/backport/24.9/71494

Backport #71494 to 24.9: Prevent crash in SortCursor with 0 columns
This commit is contained in:
Raúl Marín 2024-11-07 12:55:13 +01:00 committed by GitHub
commit 67dac32251
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 57 additions and 12 deletions

View File

@ -35,6 +35,11 @@
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
/** Cursor allows to compare rows in different blocks (and parts). /** Cursor allows to compare rows in different blocks (and parts).
* Cursor moves inside single block. * Cursor moves inside single block.
* It is used in priority queue. * It is used in priority queue.
@ -83,21 +88,27 @@ struct SortCursorImpl
SortCursorImpl( SortCursorImpl(
const Block & header, const Block & header,
const Columns & columns, const Columns & columns,
size_t num_rows,
const SortDescription & desc_, const SortDescription & desc_,
size_t order_ = 0, size_t order_ = 0,
IColumn::Permutation * perm = nullptr) IColumn::Permutation * perm = nullptr)
: desc(desc_), sort_columns_size(desc.size()), order(order_), need_collation(desc.size()) : desc(desc_), sort_columns_size(desc.size()), order(order_), need_collation(desc.size())
{ {
reset(columns, header, perm); reset(columns, header, num_rows, perm);
} }
bool empty() const { return rows == 0; } bool empty() const { return rows == 0; }
/// Set the cursor to the beginning of the new block. /// Set the cursor to the beginning of the new block.
void reset(const Block & block, IColumn::Permutation * perm = nullptr) { reset(block.getColumns(), block, perm); } void reset(const Block & block, IColumn::Permutation * perm = nullptr)
{
if (block.getColumns().empty())
throw Exception(ErrorCodes::LOGICAL_ERROR, "Empty column list in block");
reset(block.getColumns(), block, block.getColumns()[0]->size(), perm);
}
/// Set the cursor to the beginning of the new block. /// Set the cursor to the beginning of the new block.
void reset(const Columns & columns, const Block & block, IColumn::Permutation * perm = nullptr) void reset(const Columns & columns, const Block & block, UInt64 num_rows, IColumn::Permutation * perm = nullptr)
{ {
all_columns.clear(); all_columns.clear();
sort_columns.clear(); sort_columns.clear();
@ -125,7 +136,7 @@ struct SortCursorImpl
} }
pos = 0; pos = 0;
rows = all_columns[0]->size(); rows = num_rows;
permutation = perm; permutation = perm;
} }

View File

@ -24,7 +24,12 @@ void IMergingAlgorithmWithDelayedChunk::initializeQueue(Inputs inputs)
continue; continue;
cursors[source_num] = SortCursorImpl( cursors[source_num] = SortCursorImpl(
header, current_inputs[source_num].chunk.getColumns(), description, source_num, current_inputs[source_num].permutation); header,
current_inputs[source_num].chunk.getColumns(),
current_inputs[source_num].chunk.getNumRows(),
description,
source_num,
current_inputs[source_num].permutation);
inputs_origin_merge_tree_part_level[source_num] = getPartLevelFromChunk(current_inputs[source_num].chunk); inputs_origin_merge_tree_part_level[source_num] = getPartLevelFromChunk(current_inputs[source_num].chunk);
} }
@ -41,7 +46,7 @@ void IMergingAlgorithmWithDelayedChunk::updateCursor(Input & input, size_t sourc
last_chunk_sort_columns = std::move(cursors[source_num].sort_columns); last_chunk_sort_columns = std::move(cursors[source_num].sort_columns);
current_input.swap(input); current_input.swap(input);
cursors[source_num].reset(current_input.chunk.getColumns(), header, current_input.permutation); cursors[source_num].reset(current_input.chunk.getColumns(), header, current_input.chunk.getNumRows(), current_input.permutation);
inputs_origin_merge_tree_part_level[source_num] = getPartLevelFromChunk(current_input.chunk); inputs_origin_merge_tree_part_level[source_num] = getPartLevelFromChunk(current_input.chunk);

View File

@ -31,7 +31,8 @@ void IMergingAlgorithmWithSharedChunks::initialize(Inputs inputs)
source.skip_last_row = inputs[source_num].skip_last_row; source.skip_last_row = inputs[source_num].skip_last_row;
source.chunk = chunk_allocator.alloc(inputs[source_num].chunk); source.chunk = chunk_allocator.alloc(inputs[source_num].chunk);
cursors[source_num] = SortCursorImpl(header, source.chunk->getColumns(), description, source_num, inputs[source_num].permutation); cursors[source_num] = SortCursorImpl(
header, source.chunk->getColumns(), source.chunk->getNumRows(), description, source_num, inputs[source_num].permutation);
source.chunk->all_columns = cursors[source_num].all_columns; source.chunk->all_columns = cursors[source_num].all_columns;
source.chunk->sort_columns = cursors[source_num].sort_columns; source.chunk->sort_columns = cursors[source_num].sort_columns;
@ -49,7 +50,7 @@ void IMergingAlgorithmWithSharedChunks::consume(Input & input, size_t source_num
auto & source = sources[source_num]; auto & source = sources[source_num];
source.skip_last_row = input.skip_last_row; source.skip_last_row = input.skip_last_row;
source.chunk = chunk_allocator.alloc(input.chunk); source.chunk = chunk_allocator.alloc(input.chunk);
cursors[source_num].reset(source.chunk->getColumns(), header, input.permutation); cursors[source_num].reset(source.chunk->getColumns(), header, source.chunk->getNumRows(), input.permutation);
source.chunk->all_columns = cursors[source_num].all_columns; source.chunk->all_columns = cursors[source_num].all_columns;
source.chunk->sort_columns = cursors[source_num].sort_columns; source.chunk->sort_columns = cursors[source_num].sort_columns;

View File

@ -59,7 +59,7 @@ void MergingSortedAlgorithm::initialize(Inputs inputs)
if (!chunk) if (!chunk)
continue; continue;
cursors[source_num] = SortCursorImpl(header, chunk.getColumns(), description, source_num); cursors[source_num] = SortCursorImpl(header, chunk.getColumns(), chunk.getNumRows(), description, source_num);
} }
if (sorting_queue_strategy == SortingQueueStrategy::Default) if (sorting_queue_strategy == SortingQueueStrategy::Default)
@ -84,7 +84,7 @@ void MergingSortedAlgorithm::consume(Input & input, size_t source_num)
{ {
removeConstAndSparse(input); removeConstAndSparse(input);
current_inputs[source_num].swap(input); current_inputs[source_num].swap(input);
cursors[source_num].reset(current_inputs[source_num].chunk.getColumns(), header); cursors[source_num].reset(current_inputs[source_num].chunk.getColumns(), header, current_inputs[source_num].chunk.getNumRows());
if (sorting_queue_strategy == SortingQueueStrategy::Default) if (sorting_queue_strategy == SortingQueueStrategy::Default)
{ {

View File

@ -394,7 +394,7 @@ void FullMergeJoinCursor::setChunk(Chunk && chunk)
convertToFullIfSparse(chunk); convertToFullIfSparse(chunk);
current_chunk = std::move(chunk); current_chunk = std::move(chunk);
cursor = SortCursorImpl(sample_block, current_chunk.getColumns(), desc); cursor = SortCursorImpl(sample_block, current_chunk.getColumns(), current_chunk.getNumRows(), desc);
} }
bool FullMergeJoinCursor::fullyCompleted() const bool FullMergeJoinCursor::fullyCompleted() const

View File

@ -42,7 +42,7 @@ MergeSorter::MergeSorter(const Block & header, Chunks chunks_, SortDescription &
/// Convert to full column, because some cursors expect non-contant columns /// Convert to full column, because some cursors expect non-contant columns
convertToFullIfConst(chunk); convertToFullIfConst(chunk);
cursors.emplace_back(header, chunk.getColumns(), description, chunk_index); cursors.emplace_back(header, chunk.getColumns(), chunk.getNumRows(), description, chunk_index);
has_collation |= cursors.back().has_collation; has_collation |= cursors.back().has_collation;
nonempty_chunks.emplace_back(std::move(chunk)); nonempty_chunks.emplace_back(std::move(chunk));

View File

@ -0,0 +1,4 @@
42
43
44
45

View File

@ -0,0 +1,24 @@
-- https://github.com/ClickHouse/ClickHouse/issues/70779
-- Crash in SortCursorImpl with the old analyzer, which produces a block with 0 columns and 1 row
DROP TABLE IF EXISTS t0;
DROP TABLE IF EXISTS t1;
CREATE TABLE t0 (c0 Int) ENGINE = AggregatingMergeTree() ORDER BY tuple();
INSERT INTO TABLE t0 (c0) VALUES (1);
SELECT 42 FROM t0 FINAL PREWHERE t0.c0 = 1;
DROP TABLE t0;
CREATE TABLE t0 (c0 Int) ENGINE = SummingMergeTree() ORDER BY tuple();
INSERT INTO TABLE t0 (c0) VALUES (1);
SELECT 43 FROM t0 FINAL PREWHERE t0.c0 = 1;
DROP TABLE t0;
CREATE TABLE t0 (c0 Int) ENGINE = ReplacingMergeTree() ORDER BY tuple();
INSERT INTO TABLE t0 (c0) VALUES (1);
SELECT 44 FROM t0 FINAL PREWHERE t0.c0 = 1;
DROP TABLE t0;
CREATE TABLE t1 (a0 UInt8, c0 Int32, c1 UInt8) ENGINE = AggregatingMergeTree() ORDER BY tuple();
INSERT INTO TABLE t1 (a0, c0, c1) VALUES (1, 1, 1);
SELECT 45 FROM t1 FINAL PREWHERE t1.c0 = t1.c1;
DROP TABLE t1;