dbms: fixed error with tuples of consts [#METR-18586].

This commit is contained in:
Alexey Milovidov 2015-10-29 00:21:18 +03:00
parent 400588148c
commit c9a8f19def
17 changed files with 98 additions and 42 deletions

View File

@ -266,6 +266,25 @@ public:
ColumnPtr replicate(const Offsets_t & replicate_offsets) const override;
ColumnPtr convertToFullColumnIfConst() const override
{
ColumnPtr new_data;
ColumnPtr new_offsets;
if (auto full_column = data->convertToFullColumnIfConst())
new_data = full_column;
else
new_data = data;
if (auto full_column = offsets->convertToFullColumnIfConst())
new_offsets = full_column;
else
new_offsets = offsets;
return new ColumnArray(new_data, new_offsets);
}
private:
ColumnPtr data;
ColumnPtr offsets; /// Смещения могут быть разделяемыми для нескольких столбцов - для реализации вложенных структур данных.

View File

@ -21,6 +21,7 @@ class IColumnConst : public IColumn
public:
bool isConst() const override { return true; }
virtual ColumnPtr convertToFullColumn() const = 0;
ColumnPtr convertToFullColumnIfConst() const override { return convertToFullColumn(); }
};

View File

@ -242,6 +242,16 @@ public:
columns[i]->getExtremes(min.get<Array &>()[i], max.get<Array &>()[i]);
}
ColumnPtr convertToFullColumnIfConst() const override
{
Block materialized = data;
for (size_t i = 0, size = materialized.columns(); i < size; ++i)
if (auto converted = materialized.unsafeGetByPosition(i).column->convertToFullColumnIfConst())
materialized.unsafeGetByPosition(i).column = converted;
return new ColumnTuple(materialized);
}
const Block & getData() const { return data; }
Block & getData() { return data; }

View File

@ -42,6 +42,15 @@ public:
*/
virtual bool isConst() const { return false; }
/** Если столбец не константа - возвращает nullptr (либо может вернуть самого себя).
* Если столбец константа, то превращает его в полноценный столбец (если тип столбца предполагает такую возможность) и возвращает его.
* Отдельный случай:
* Если столбец состоит из нескольких других столбцов (пример: кортеж),
* и он может содержать как константные, так и полноценные столбцы,
* то превратить в нём все константные столбцы в полноценные, и вернуть результат.
*/
virtual SharedPtr<IColumn> convertToFullColumnIfConst() const { return {}; }
/** Значения имеют фиксированную длину.
*/
virtual bool isFixed() const { return false; }

View File

@ -38,9 +38,10 @@ protected:
size_t columns = res.columns();
for (size_t i = 0; i < columns; ++i)
{
ColumnPtr col = res.getByPosition(i).column;
if (col->isConst())
res.getByPosition(i).column = dynamic_cast<IColumnConst &>(*col).convertToFullColumn();
auto & src = res.getByPosition(i).column;
ColumnPtr converted = src->convertToFullColumnIfConst();
if (converted)
src = converted;
}
return res;

View File

@ -23,9 +23,10 @@ public:
for (const auto i : ext::range(0, block.columns()))
{
ColumnPtr & col = block.getByPosition(i).column;
if (col->isConst())
col = dynamic_cast<IColumnConst &>(*col).convertToFullColumn();
auto & src = block.getByPosition(i).column;
ColumnPtr converted = src->convertToFullColumnIfConst();
if (converted)
src = converted;
}
output->write(block);

View File

@ -44,8 +44,8 @@ inline void evaluateMissingDefaults(Block & block,
/// move evaluated columns to the original block, materializing them at the same time
for (auto & column_name_type : copy_block.getColumns())
{
if (column_name_type.column->isConst())
column_name_type.column = static_cast<const IColumnConst &>(*column_name_type.column).convertToFullColumn();
if (auto converted = column_name_type.column->convertToFullColumnIfConst())
column_name_type.column = converted;
block.insert(std::move(column_name_type));
}

View File

@ -159,8 +159,8 @@ bool filterBlockWithQuery(ASTPtr query, Block & block, const Context & context)
/// Отфильтруем блок.
String filter_column_name = expression_ast->getColumnName();
ColumnPtr filter_column = block.getByName(filter_column_name).column;
if (IColumnConst * const_column = dynamic_cast<IColumnConst *>(&*filter_column))
filter_column = const_column->convertToFullColumn();
if (auto converted = filter_column->convertToFullColumnIfConst())
filter_column = converted;
const IColumn::Filter & filter = dynamic_cast<ColumnUInt8 &>(*filter_column).getData();
if (std::accumulate(filter.begin(), filter.end(), 0ul) == filter.size())

View File

@ -116,8 +116,8 @@ void IProfilingBlockInputStream::updateExtremes(Block & block)
ColumnPtr & column = extremes.getByPosition(i).column;
if (column->isConst())
column = dynamic_cast<const IColumnConst &>(*column).convertToFullColumn();
if (auto converted = column->convertToFullColumnIfConst())
column = converted;
column->insert(min_value);
column->insert(max_value);

View File

@ -37,9 +37,12 @@ void NativeBlockOutputStream::writeData(const IDataType & type, const ColumnPtr
/** Если есть столбцы-константы - то материализуем их.
* (Так как тип данных не умеет сериализовывать/десериализовывать константы.)
*/
ColumnPtr full_column = column->isConst()
? static_cast<const IColumnConst &>(*column).convertToFullColumn()
: column;
ColumnPtr full_column;
if (auto converted = column->convertToFullColumnIfConst())
full_column = converted;
else
full_column = column;
/** Для массивов требуется сначала сериализовать смещения, а потом значения.
*/

View File

@ -117,8 +117,8 @@ void Aggregator::initialize(const Block & block)
for (size_t i = 0; i < keys_size; ++i)
{
sample.insert(block.getByPosition(keys[i]).cloneEmpty());
if (sample.getByPosition(i).column->isConst())
sample.getByPosition(i).column = dynamic_cast<IColumnConst &>(*sample.getByPosition(i).column).convertToFullColumn();
if (auto converted = sample.getByPosition(i).column->convertToFullColumnIfConst())
sample.getByPosition(i).column = converted;
}
for (size_t i = 0; i < aggregates_size; ++i)
@ -593,9 +593,9 @@ bool Aggregator::executeOnBlock(Block & block, AggregatedDataVariants & result,
{
key_columns[i] = block.getByPosition(keys[i]).column;
if (const IColumnConst * column_const = dynamic_cast<const IColumnConst *>(key_columns[i]))
if (auto converted = key_columns[i]->convertToFullColumnIfConst())
{
materialized_columns.push_back(column_const->convertToFullColumn());
materialized_columns.push_back(converted);
key_columns[i] = materialized_columns.back().get();
}
}
@ -606,9 +606,9 @@ bool Aggregator::executeOnBlock(Block & block, AggregatedDataVariants & result,
{
aggregate_columns[i][j] = block.getByPosition(aggregates[i].arguments[j]).column;
if (const IColumnConst * column_const = dynamic_cast<const IColumnConst *>(aggregate_columns[i][j]))
if (auto converted = aggregate_columns[i][j]->convertToFullColumnIfConst())
{
materialized_columns.push_back(column_const->convertToFullColumn());
materialized_columns.push_back(converted);
aggregate_columns[i][j] = materialized_columns.back().get();
}
}

View File

@ -264,8 +264,8 @@ void ExpressionAction::execute(Block & block) const
throw Exception("No arrays to join", ErrorCodes::LOGICAL_ERROR);
ColumnPtr any_array_ptr = block.getByName(*array_joined_columns.begin()).column;
if (any_array_ptr->isConst())
any_array_ptr = dynamic_cast<const IColumnConst &>(*any_array_ptr).convertToFullColumn();
if (auto converted = any_array_ptr->convertToFullColumnIfConst())
any_array_ptr = converted;
const ColumnArray * any_array = typeid_cast<const ColumnArray *>(&*any_array_ptr);
if (!any_array)
@ -301,8 +301,8 @@ void ExpressionAction::execute(Block & block) const
ColumnPtr array_ptr = array_join_is_left ? non_empty_array_columns[current.name] : current.column;
if (array_ptr->isConst())
array_ptr = dynamic_cast<const IColumnConst &>(*array_ptr).convertToFullColumn();
if (auto converted = array_ptr->convertToFullColumnIfConst())
array_ptr = converted;
const ColumnArray & array = typeid_cast<const ColumnArray &>(*array_ptr);
if (!array.hasEqualOffsets(typeid_cast<const ColumnArray &>(*any_array_ptr)))

View File

@ -418,9 +418,9 @@ bool Join::insertFromBlock(const Block & block)
{
key_columns[i] = block.getByName(key_names_right[i]).column;
if (auto * col_const = dynamic_cast<const IColumnConst *>(key_columns[i]))
if (auto converted = key_columns[i]->convertToFullColumnIfConst())
{
materialized_columns.emplace_back(col_const->convertToFullColumn());
materialized_columns.emplace_back(converted);
key_columns[i] = materialized_columns.back();
}
}
@ -456,8 +456,8 @@ bool Join::insertFromBlock(const Block & block)
for (size_t i = 0, size = stored_block->columns(); i < size; ++i)
{
ColumnPtr col = stored_block->getByPosition(i).column;
if (auto * col_const = dynamic_cast<const IColumnConst *>(col.get()))
stored_block->getByPosition(i).column = col_const->convertToFullColumn();
if (auto converted = col->convertToFullColumnIfConst())
stored_block->getByPosition(i).column = converted;
}
if (kind != ASTJoin::Cross)
@ -604,9 +604,9 @@ void Join::joinBlockImpl(Block & block, const Maps & maps) const
{
key_columns[i] = block.getByName(key_names_left[i]).column;
if (auto * col_const = dynamic_cast<const IColumnConst *>(key_columns[i]))
if (auto converted = key_columns[i]->convertToFullColumnIfConst())
{
materialized_columns.emplace_back(col_const->convertToFullColumn());
materialized_columns.emplace_back(converted);
key_columns[i] = materialized_columns.back();
}
}
@ -623,8 +623,8 @@ void Join::joinBlockImpl(Block & block, const Maps & maps) const
{
auto & col = block.getByPosition(i).column;
if (auto * col_const = dynamic_cast<IColumnConst *>(col.get()))
col = col_const->convertToFullColumn();
if (auto converted = col->convertToFullColumnIfConst())
col = converted;
}
}

View File

@ -185,9 +185,9 @@ bool Set::insertFromBlock(const Block & block, bool create_ordered_set)
key_columns[i] = block.getByPosition(i).column;
data_types[i] = block.getByPosition(i).type;
if (key_columns[i]->isConst())
if (auto converted = key_columns[i]->convertToFullColumnIfConst())
{
materialized_columns.emplace_back(static_cast<const IColumnConst *>(key_columns[i])->convertToFullColumn());
materialized_columns.emplace_back(converted);
key_columns[i] = materialized_columns.back().get();
}
}
@ -475,11 +475,8 @@ ColumnPtr Set::execute(const Block & block, bool negative) const
/// Константный столбец слева от IN поддерживается не напрямую. Для этого, он сначала материализуется.
ColumnPtr materialized_column;
if (in_column->isConst())
{
materialized_column = static_cast<const IColumnConst *>(in_column)->convertToFullColumn();
if (materialized_column = in_column->convertToFullColumnIfConst())
in_column = materialized_column.get();
}
if (const ColumnArray * col = typeid_cast<const ColumnArray *>(in_column))
executeArray(col, vec_res, negative);
@ -507,9 +504,9 @@ ColumnPtr Set::execute(const Block & block, bool negative) const
Columns materialized_columns;
for (auto & column_ptr : key_columns)
{
if (column_ptr->isConst())
if (auto converted = column_ptr->convertToFullColumnIfConst())
{
materialized_columns.emplace_back(static_cast<const IColumnConst *>(column_ptr)->convertToFullColumn());
materialized_columns.emplace_back(converted);
column_ptr = materialized_columns.back().get();
}
}

View File

@ -254,7 +254,7 @@ Block LogBlockInputStream::readImpl()
rows = res.rows();
if (rows > 0)
{
ColumnPtr column_ptr = ColumnConst<String> (rows, current_table.first, new DataTypeString).convertToFullColumn();
ColumnPtr column_ptr = ColumnConst<String>(rows, current_table.first, new DataTypeString).convertToFullColumn();
ColumnWithTypeAndName column(column_ptr, new DataTypeString, storage._table_column_name);
res.insert(column);
}

View File

@ -0,0 +1,10 @@
(1)
(1)
(1)
(2)
(0)
(0)
(0)
(0)
(0)
(1)

View File

@ -0,0 +1,5 @@
select * from (select tuple(1) as a union all select tuple(1) as a) order by a;
select * from (select tuple(1) as a union all select tuple(2) as a) order by a;
select * from (select tuple(materialize(0)) as a union all select tuple(0) as a) order by a;
select * from (select tuple(range(1)[1]) as a union all select tuple(0) as a) order by a;
select * from (select tuple(range(1)[2]) as a union all select tuple(1) as a) order by a;