Better const resolution for LowCardinality type. [#CLICKHOUSE-3621]

This commit is contained in:
Nikolai Kochetov 2018-08-14 15:41:29 +03:00
parent 6b3375393d
commit f61fdf2076
3 changed files with 26 additions and 18 deletions

View File

@ -30,6 +30,11 @@ ColumnPtr ColumnConst::convertToFullColumn() const
return data->replicate(Offsets(1, s)); return data->replicate(Offsets(1, s));
} }
ColumnPtr ColumnConst::removeLowCardinality() const
{
return ColumnConst::create(data->convertToFullColumnIfWithDictionary(), s);
}
ColumnPtr ColumnConst::filter(const Filter & filt, ssize_t /*result_size_hint*/) const ColumnPtr ColumnConst::filter(const Filter & filt, ssize_t /*result_size_hint*/) const
{ {
if (s != filt.size()) if (s != filt.size())

View File

@ -36,6 +36,8 @@ public:
return convertToFullColumn(); return convertToFullColumn();
} }
ColumnPtr removeLowCardinality() const;
std::string getName() const override std::string getName() const override
{ {
return "Const(" + data->getName() + ")"; return "Const(" + data->getName() + ")";

View File

@ -253,14 +253,11 @@ static ColumnPtr replaceColumnsWithDictionaryByNestedAndGetDictionaryIndexes(Blo
} }
} }
if (!indexes)
throw Exception("Expected column with dictionary for any function argument.", ErrorCodes::LOGICAL_ERROR);
for (auto arg : args) for (auto arg : args)
{ {
ColumnWithTypeAndName & column = block.getByPosition(arg); ColumnWithTypeAndName & column = block.getByPosition(arg);
if (auto * column_const = checkAndGetColumn<ColumnConst>(column.column.get())) if (auto * column_const = checkAndGetColumn<ColumnConst>(column.column.get()))
column.column = column_const->cloneResized(num_rows); column.column = column_const->removeLowCardinality()->cloneResized(num_rows);
else if (auto * column_with_dict = checkAndGetColumn<ColumnWithDictionary>(column.column.get())) else if (auto * column_with_dict = checkAndGetColumn<ColumnWithDictionary>(column.column.get()))
{ {
auto * type_with_dict = checkAndGetDataType<DataTypeWithDictionary>(column.type.get()); auto * type_with_dict = checkAndGetDataType<DataTypeWithDictionary>(column.type.get());
@ -289,7 +286,9 @@ static void convertColumnsWithDictionaryToFull(Block & block, const ColumnNumber
for (auto arg : args) for (auto arg : args)
{ {
ColumnWithTypeAndName & column = block.getByPosition(arg); ColumnWithTypeAndName & column = block.getByPosition(arg);
if (auto * column_with_dict = checkAndGetColumn<ColumnWithDictionary>(column.column.get())) if (auto * column_const = checkAndGetColumn<ColumnConst>(column.column.get()))
column.column = column_const->removeLowCardinality();
else if (auto * column_with_dict = checkAndGetColumn<ColumnWithDictionary>(column.column.get()))
{ {
auto * type_with_dict = checkAndGetDataType<DataTypeWithDictionary>(column.type.get()); auto * type_with_dict = checkAndGetDataType<DataTypeWithDictionary>(column.type.get());
@ -325,10 +324,13 @@ void PreparedFunctionImpl::execute(Block & block, const ColumnNumbers & args, si
auto * column_with_dictionary = typeid_cast<ColumnWithDictionary *>(res_column.get()); auto * column_with_dictionary = typeid_cast<ColumnWithDictionary *>(res_column.get());
if (!column_with_dictionary) if (!column_with_dictionary)
throw Exception("Expected ColumnWithDictionary, got" + res_column->getName(), ErrorCodes::LOGICAL_ERROR); throw Exception("Expected LowCardinality column, got" + res_column->getName(), ErrorCodes::LOGICAL_ERROR);
const auto & keys = block_without_dicts.safeGetByPosition(result).column; const auto & keys = block_without_dicts.safeGetByPosition(result).column;
column_with_dictionary->insertRangeFromDictionaryEncodedColumn(*keys, *indexes); if (indexes)
column_with_dictionary->insertRangeFromDictionaryEncodedColumn(*keys, *indexes);
else
column_with_dictionary->insertRangeFromFullColumn(*keys->convertToFullColumnIfConst(), 0, keys->size());
res.column = std::move(res_column); res.column = std::move(res_column);
} }
@ -451,29 +453,28 @@ DataTypePtr FunctionBuilderImpl::getReturnType(const ColumnsWithTypeAndName & ar
{ {
if (useDefaultImplementationForColumnsWithDictionary()) if (useDefaultImplementationForColumnsWithDictionary())
{ {
bool has_type_with_dictionary = false; bool has_low_cardinality = false;
bool can_run_function_on_dictionary = true; size_t num_full_low_cardinality_columns = 0;
ColumnsWithTypeAndName args_without_dictionary(arguments); ColumnsWithTypeAndName args_without_dictionary(arguments);
for (ColumnWithTypeAndName & arg : args_without_dictionary) for (ColumnWithTypeAndName & arg : args_without_dictionary)
{ {
if (arg.column && arg.column->isColumnConst()) bool is_const = arg.column && arg.column->isColumnConst();
continue; if (is_const)
arg.column = static_cast<const ColumnConst &>(*arg.column).removeLowCardinality();
if (auto * type_with_dictionary = typeid_cast<const DataTypeWithDictionary *>(arg.type.get())) if (auto * type_with_dictionary = typeid_cast<const DataTypeWithDictionary *>(arg.type.get()))
{ {
if (has_type_with_dictionary)
can_run_function_on_dictionary = false;
has_type_with_dictionary = true;
arg.type = type_with_dictionary->getDictionaryType(); arg.type = type_with_dictionary->getDictionaryType();
has_low_cardinality = true;
if (!is_const)
++num_full_low_cardinality_columns;
} }
else
can_run_function_on_dictionary = false;
} }
if (canBeExecutedOnLowCardinalityDictionary() && has_type_with_dictionary && can_run_function_on_dictionary) if (canBeExecutedOnLowCardinalityDictionary() && has_low_cardinality && num_full_low_cardinality_columns <= 1)
return std::make_shared<DataTypeWithDictionary>(getReturnTypeWithoutDictionary(args_without_dictionary)); return std::make_shared<DataTypeWithDictionary>(getReturnTypeWithoutDictionary(args_without_dictionary));
else else
return getReturnTypeWithoutDictionary(args_without_dictionary); return getReturnTypeWithoutDictionary(args_without_dictionary);