dbms: Better code for functions processing. Code cleanup. [#METR-19266]

This commit is contained in:
Alexey Arno 2016-08-15 14:14:29 +03:00
parent 96855a06b8
commit f4e77aaf97
18 changed files with 390 additions and 283 deletions

View File

@ -28,7 +28,7 @@ public:
String getName() const override
{
return nested_function.get()->getName();
return nested_function->getName();
}
void setArguments(const DataTypes & arguments) override
@ -38,7 +38,7 @@ public:
for (const auto & arg : arguments)
{
bool res = arg.get()->isNullable();
bool res = arg->isNullable();
is_nullable.push_back(res);
}
@ -47,7 +47,7 @@ public:
for (const auto & arg : arguments)
{
if (arg.get()->isNullable())
if (arg->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*arg);
const DataTypePtr & nested_type = nullable_type.getNestedType();
@ -57,42 +57,42 @@ public:
new_args.push_back(arg);
}
nested_function.get()->setArguments(new_args);
nested_function->setArguments(new_args);
}
void setParameters(const Array & params)
{
nested_function.get()->setParameters(params);
nested_function->setParameters(params);
}
DataTypePtr getReturnType() const override
{
return nested_function.get()->getReturnType();
return nested_function->getReturnType();
}
void create(AggregateDataPtr place) const override
{
nested_function.get()->create(place);
nested_function->create(place);
}
void destroy(AggregateDataPtr place) const noexcept override
{
nested_function.get()->destroy(place);
nested_function->destroy(place);
}
bool hasTrivialDestructor() const override
{
return nested_function.get()->hasTrivialDestructor();
return nested_function->hasTrivialDestructor();
}
size_t sizeOfData() const override
{
return nested_function.get()->sizeOfData();
return nested_function->sizeOfData();
}
size_t alignOfData() const override
{
return nested_function.get()->alignOfData();
return nested_function->alignOfData();
}
void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num) const override
@ -117,27 +117,27 @@ public:
passed_columns[i] = columns[i];
}
nested_function.get()->add(place, passed_columns, row_num);
nested_function->add(place, passed_columns, row_num);
}
void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs) const override
{
nested_function.get()->merge(place, rhs);
nested_function->merge(place, rhs);
}
void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override
{
nested_function.get()->serialize(place, buf);
nested_function->serialize(place, buf);
}
void deserialize(AggregateDataPtr place, ReadBuffer & buf) const override
{
nested_function.get()->deserialize(place, buf);
nested_function->deserialize(place, buf);
}
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
{
nested_function.get()->insertResultInto(place, to);
nested_function->insertResultInto(place, to);
}
static void addFree(const IAggregateFunction * that, AggregateDataPtr place, const IColumn ** columns, size_t row_num)

View File

@ -141,21 +141,34 @@ protected:
/// Returns the copy of a given block in which each column specified in
/// the "arguments" parameter is replaced with its respective nested
/// column if it is nullable.
static Block extractNonNullableBlock(const Block & block, ColumnNumbers args);
static Block createBlockWithNestedColumns(const Block & block, ColumnNumbers args);
private:
/// Internal method used for implementing both the execute() methods.
/// The "performer" argument specifies which version of executeImpl() must be used.
/// Except for functions, such as multiIf, whose method hasSpecialSupportForNulls()
/// returns true, we deal with nullable and null arguments as follows:
/// - if at least one argument is NULL, we return NULL;
/// - if at least one argument is nullable, we call the function implementation
/// Strategy to apply when executing a function.
enum Strategy
{
/// Merely perform the function on its columns.
DIRECTLY_EXECUTE = 0,
/// If at least one argument is nullable, call the function implementation
/// with a block in which nullable columns that correspond to function arguments
/// have been replaced with their respective nested columns;
/// - if at least one function argument is nullable, the result column is wrapped
/// into a nullable column.
template <typename Fun>
void perform(Block & block, const ColumnNumbers & arguments, size_t result, const Fun & performer);
/// have been replaced with their respective nested columns. Subsequently, the
/// result column is wrapped into a nullable column.
PROCESS_NULLABLE_COLUMNS,
/// If at least one argument is NULL, return NULL.
RETURN_NULL
};
private:
/// Choose the strategy for performing the function.
Strategy chooseStrategy(const Block & block, const ColumnNumbers & args);
/// If required by the specified strategy, process the given block, then
/// return the processed block. Otherwise return an empty block.
Block preProcessBlock(Strategy strategy, const Block & block, const ColumnNumbers & args);
/// If required by the specified strategy, post-process the result column.
void postProcessResult(Strategy strategy, Block & block, const Block & processed_block,
const ColumnNumbers & args, size_t result);
};

View File

@ -99,7 +99,7 @@ AggregateFunctionPtr AggregateFunctionFactory::get(const String & name, const Da
bool has_nullable_types = false;
for (const auto & arg_type : argument_types)
{
if (arg_type.get()->isNullable())
if (arg_type->isNullable())
{
has_nullable_types = true;
break;
@ -113,7 +113,7 @@ AggregateFunctionPtr AggregateFunctionFactory::get(const String & name, const Da
for (const auto & arg_type : argument_types)
{
if (arg_type.get()->isNullable())
if (arg_type->isNullable())
{
const DataTypeNullable & actual_type = static_cast<const DataTypeNullable &>(*arg_type.get());
const DataTypePtr & nested_type = actual_type.getNestedType();

View File

@ -103,7 +103,7 @@ ColumnPtr ColumnNullable::cloneResized(size_t size) const
/// Create a new null byte map for the cloned column.
/// Resize it if required.
new_col.null_map = null_map.get()->clone();
new_col.null_map = null_map->clone();
if (size != this->size())
new_col.getNullMapContent().getData().resize_fill(size, 0);
@ -114,7 +114,7 @@ ColumnPtr ColumnNullable::cloneEmpty() const
{
ColumnPtr new_col_holder = std::make_shared<ColumnNullable>(nested_column->cloneEmpty());
auto & new_col = static_cast<ColumnNullable &>(*new_col_holder);
new_col.null_map = null_map.get()->cloneEmpty();
new_col.null_map = null_map->cloneEmpty();
return new_col_holder;
}

View File

@ -40,7 +40,7 @@ Block MaterializingBlockInputStream::readImpl()
{
src = converted;
auto & type = element.type;
if (type.get()->isNull())
if (type->isNull())
{
/// A ColumnNull that is converted to a full column
/// has the type DataTypeNullable(DataTypeUInt8).

View File

@ -66,7 +66,7 @@ Block MaterializingBlockOutputStream::materialize(const Block & original_block)
{
src = converted;
auto & type = element.type;
if (type.get()->isNull())
if (type->isNull())
{
/// A ColumnNull that is converted to a full column
/// has the type DataTypeNullable(DataTypeUInt8).

View File

@ -49,13 +49,13 @@ void PrettyBlockOutputStream::calculateWidths(Block & block, Widths_t & max_widt
auto has_null_value = [](const ColumnPtr & col, size_t row)
{
if (col.get()->isNullable())
if (col->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*col);
if (nullable_col.isNullAt(row))
return true;
}
else if (col.get()->isNull())
else if (col->isNull())
return true;
return false;

View File

@ -83,13 +83,13 @@ void PrettyCompactBlockOutputStream::writeRow(
{
auto has_null_value = [](const ColumnPtr & col, size_t row)
{
if (col.get()->isNullable())
if (col->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*col);
if (nullable_col.isNullAt(row))
return true;
}
else if (col.get()->isNull())
else if (col->isNull())
return true;
return false;
@ -115,7 +115,7 @@ void PrettyCompactBlockOutputStream::writeRow(
ColumnPtr res_col = block.getByPosition(columns + j).column;
IColumn * observed_col;
if (res_col.get()->isNullable())
if (res_col->isNullable())
{
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*res_col);
observed_col = nullable_col.getNestedColumn().get();

View File

@ -56,7 +56,7 @@ DataTypeNullable::DataTypeNullable(DataTypePtr nested_data_type_)
std::string DataTypeNullable::getName() const
{
return "Nullable(" + nested_data_type.get()->getName() + ")";
return "Nullable(" + nested_data_type->getName() + ")";
}
bool DataTypeNullable::isNullable() const
@ -66,17 +66,17 @@ bool DataTypeNullable::isNullable() const
bool DataTypeNullable::isNumeric() const
{
return nested_data_type.get()->isNumeric();
return nested_data_type->isNumeric();
}
bool DataTypeNullable::behavesAsNumber() const
{
return nested_data_type.get()->behavesAsNumber();
return nested_data_type->behavesAsNumber();
}
DataTypePtr DataTypeNullable::clone() const
{
return std::make_shared<DataTypeNullable>(nested_data_type.get()->clone());
return std::make_shared<DataTypeNullable>(nested_data_type->clone());
}
void DataTypeNullable::serializeBinary(const IColumn & column, WriteBuffer & ostr, size_t offset, size_t limit) const
@ -85,7 +85,7 @@ void DataTypeNullable::serializeBinary(const IColumn & column, WriteBuffer & ost
if (col == nullptr)
throw Exception{"Discrepancy between data type and column type", ErrorCodes::LOGICAL_ERROR};
nested_data_type.get()->serializeBinary(*col->getNestedColumn(), ostr, offset, limit);
nested_data_type->serializeBinary(*col->getNestedColumn(), ostr, offset, limit);
}
void DataTypeNullable::deserializeBinary(IColumn & column, ReadBuffer & istr, size_t limit, double avg_value_size_hint) const
@ -94,17 +94,17 @@ void DataTypeNullable::deserializeBinary(IColumn & column, ReadBuffer & istr, si
if (col == nullptr)
throw Exception{"Discrepancy between data type and column type", ErrorCodes::LOGICAL_ERROR};
nested_data_type.get()->deserializeBinary(*col->getNestedColumn(), istr, limit, avg_value_size_hint);
nested_data_type->deserializeBinary(*col->getNestedColumn(), istr, limit, avg_value_size_hint);
}
void DataTypeNullable::serializeBinary(const Field & field, WriteBuffer & ostr) const
{
nested_data_type.get()->serializeBinary(field, ostr);
nested_data_type->serializeBinary(field, ostr);
}
void DataTypeNullable::deserializeBinary(Field & field, ReadBuffer & istr) const
{
nested_data_type.get()->deserializeBinary(field, istr);
nested_data_type->deserializeBinary(field, istr);
}
void DataTypeNullable::serializeBinary(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -113,7 +113,7 @@ void DataTypeNullable::serializeBinary(const IColumn & column, size_t row_num, W
if (col == nullptr)
throw Exception{"Discrepancy between data type and column type", ErrorCodes::LOGICAL_ERROR};
nested_data_type.get()->serializeBinary(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeBinary(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::deserializeBinary(IColumn & column, ReadBuffer & istr) const
@ -122,7 +122,7 @@ void DataTypeNullable::deserializeBinary(IColumn & column, ReadBuffer & istr) co
if (col == nullptr)
throw Exception{"Discrepancy between data type and column type", ErrorCodes::LOGICAL_ERROR};
nested_data_type.get()->deserializeBinary(*col->getNestedColumn(), istr);
nested_data_type->deserializeBinary(*col->getNestedColumn(), istr);
}
void DataTypeNullable::serializeTextEscaped(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -137,7 +137,7 @@ void DataTypeNullable::serializeTextEscaped(const IColumn & column, size_t row_n
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::Escaped::name, ostr);
else
nested_data_type.get()->serializeTextEscaped(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeTextEscaped(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::deserializeTextEscaped(IColumn & column, ReadBuffer & istr) const
@ -152,10 +152,10 @@ void DataTypeNullable::deserializeTextEscaped(IColumn & column, ReadBuffer & ist
if (Deserializer<NullSymbol::Escaped>::execute(column, istr, &null_map))
{
ColumnPtr & nested_col = col->getNestedColumn();
nested_col.get()->insertDefault();
nested_col->insertDefault();
}
else
nested_data_type.get()->deserializeTextEscaped(*col->getNestedColumn(), istr);
nested_data_type->deserializeTextEscaped(*col->getNestedColumn(), istr);
}
void DataTypeNullable::serializeTextQuoted(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -170,7 +170,7 @@ void DataTypeNullable::serializeTextQuoted(const IColumn & column, size_t row_nu
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::Quoted::name, ostr);
else
nested_data_type.get()->serializeTextQuoted(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeTextQuoted(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::deserializeTextQuoted(IColumn & column, ReadBuffer & istr) const
@ -185,10 +185,10 @@ void DataTypeNullable::deserializeTextQuoted(IColumn & column, ReadBuffer & istr
if (Deserializer<NullSymbol::Quoted>::execute(column, istr, &null_map))
{
ColumnPtr & nested_col = col->getNestedColumn();
nested_col.get()->insertDefault();
nested_col->insertDefault();
}
else
nested_data_type.get()->deserializeTextQuoted(*col->getNestedColumn(), istr);
nested_data_type->deserializeTextQuoted(*col->getNestedColumn(), istr);
}
void DataTypeNullable::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -203,7 +203,7 @@ void DataTypeNullable::serializeTextCSV(const IColumn & column, size_t row_num,
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::Quoted::name, ostr);
else
nested_data_type.get()->serializeTextCSV(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeTextCSV(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::deserializeTextCSV(IColumn & column, ReadBuffer & istr, const char delimiter) const
@ -218,10 +218,10 @@ void DataTypeNullable::deserializeTextCSV(IColumn & column, ReadBuffer & istr, c
if (Deserializer<NullSymbol::Quoted>::execute(column, istr, &null_map))
{
ColumnPtr & nested_col = col->getNestedColumn();
nested_col.get()->insertDefault();
nested_col->insertDefault();
}
else
nested_data_type.get()->deserializeTextCSV(*col->getNestedColumn(), istr, delimiter);
nested_data_type->deserializeTextCSV(*col->getNestedColumn(), istr, delimiter);
}
void DataTypeNullable::serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -236,7 +236,7 @@ void DataTypeNullable::serializeText(const IColumn & column, size_t row_num, Wri
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::Plain::name, ostr);
else
nested_data_type.get()->serializeText(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeText(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -251,7 +251,7 @@ void DataTypeNullable::serializeTextJSON(const IColumn & column, size_t row_num,
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::JSON::name, ostr);
else
nested_data_type.get()->serializeTextJSON(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeTextJSON(*col->getNestedColumn(), row_num, ostr);
}
void DataTypeNullable::deserializeTextJSON(IColumn & column, ReadBuffer & istr) const
@ -266,10 +266,10 @@ void DataTypeNullable::deserializeTextJSON(IColumn & column, ReadBuffer & istr)
if (Deserializer<NullSymbol::JSON>::execute(column, istr, &null_map))
{
ColumnPtr & nested_col = col->getNestedColumn();
nested_col.get()->insertDefault();
nested_col->insertDefault();
}
else
nested_data_type.get()->deserializeTextJSON(*col->getNestedColumn(), istr);
nested_data_type->deserializeTextJSON(*col->getNestedColumn(), istr);
}
void DataTypeNullable::serializeTextXML(const IColumn & column, size_t row_num, WriteBuffer & ostr) const
@ -284,12 +284,12 @@ void DataTypeNullable::serializeTextXML(const IColumn & column, size_t row_num,
if (isNullValue(&null_map, row_num))
writeCString(NullSymbol::XML::name, ostr);
else
nested_data_type.get()->serializeTextXML(*col->getNestedColumn(), row_num, ostr);
nested_data_type->serializeTextXML(*col->getNestedColumn(), row_num, ostr);
}
ColumnPtr DataTypeNullable::createColumn() const
{
ColumnPtr new_col_holder = std::make_shared<ColumnNullable>(nested_data_type.get()->createColumn());
ColumnPtr new_col_holder = std::make_shared<ColumnNullable>(nested_data_type->createColumn());
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*new_col_holder);
nullable_col.getNullValuesByteMap() = std::make_shared<ColumnUInt8>();
return new_col_holder;
@ -297,7 +297,7 @@ ColumnPtr DataTypeNullable::createColumn() const
ColumnPtr DataTypeNullable::createConstColumn(size_t size, const Field & field) const
{
ColumnPtr new_col_holder = std::make_shared<ColumnNullable>(nested_data_type.get()->createConstColumn(size, field));
ColumnPtr new_col_holder = std::make_shared<ColumnNullable>(nested_data_type->createConstColumn(size, field));
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*new_col_holder);
nullable_col.getNullValuesByteMap() = std::make_shared<ColumnUInt8>(size);
return new_col_holder;
@ -305,12 +305,12 @@ ColumnPtr DataTypeNullable::createConstColumn(size_t size, const Field & field)
Field DataTypeNullable::getDefault() const
{
return nested_data_type.get()->getDefault();
return nested_data_type->getDefault();
}
size_t DataTypeNullable::getSizeOfField() const
{
return nested_data_type.get()->getSizeOfField();
return nested_data_type->getSizeOfField();
}
DataTypePtr & DataTypeNullable::getNestedType()

View File

@ -98,7 +98,7 @@ struct TypeChecker
{
static bool execute(const DataTypePtr & arg)
{
if (arg.get()->isNullable())
if (arg->isNullable())
return false;
return typeid_cast<const TType *>(arg.get()) != nullptr;
}
@ -109,7 +109,7 @@ struct TypeChecker<Nullable<TType>>
{
static bool execute(const DataTypePtr & arg)
{
if (!arg.get()->isNullable())
if (!arg->isNullable())
return false;
const DataTypeNullable & nullable_type = static_cast<DataTypeNullable &>(*arg);
@ -203,7 +203,7 @@ bool hasArithmeticBranches(const DataTypes & args)
auto check = [&](size_t i)
{
return args[i].get()->behavesAsNumber();
return args[i]->behavesAsNumber();
};
for (size_t i = firstThen(); i < else_arg; i = nextThen(i))
@ -222,7 +222,7 @@ bool hasArrayBranches(const DataTypes & args)
auto check = [&](size_t i)
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -230,7 +230,7 @@ bool hasArrayBranches(const DataTypes & args)
else
observed_type = args[i].get();
return (typeid_cast<const DataTypeArray *>(observed_type) != nullptr) || args[i].get()->isNull();
return (typeid_cast<const DataTypeArray *>(observed_type) != nullptr) || args[i]->isNull();
};
for (size_t i = firstThen(); i < elseArg(args); i = nextThen(i))
@ -250,10 +250,10 @@ bool hasIdenticalTypes(const DataTypes & args)
for (size_t i = firstThen(); i < else_arg; i = nextThen(i))
{
if (!args[i].get()->isNullable())
if (!args[i]->isNullable())
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -273,10 +273,10 @@ bool hasIdenticalTypes(const DataTypes & args)
}
}
if (!args[else_arg].get()->isNull())
if (!args[else_arg]->isNull())
{
const IDataType * observed_type;
if (args[else_arg].get()->isNullable())
if (args[else_arg]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[else_arg]);
observed_type = nullable_type.getNestedType().get();
@ -302,7 +302,7 @@ bool hasFixedStrings(const DataTypes & args)
auto check = [&](size_t i)
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -310,7 +310,7 @@ bool hasFixedStrings(const DataTypes & args)
else
observed_type = args[i].get();
return (typeid_cast<const DataTypeFixedString *>(observed_type) != nullptr) || (args[i].get()->isNull());
return (typeid_cast<const DataTypeFixedString *>(observed_type) != nullptr) || (args[i]->isNull());
};
for (size_t i = firstThen(); i < elseArg(args); i = nextThen(i))
@ -341,7 +341,7 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
for (size_t i = firstThen(); i < else_arg; i = nextThen(i))
{
const IDataType * observed_type;
if (!args[i].get()->isNullable())
if (!args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -363,10 +363,10 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
}
}
if (!args[else_arg].get()->isNull())
if (!args[else_arg]->isNull())
{
const IDataType * observed_type;
if (args[else_arg].get()->isNullable())
if (args[else_arg]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[else_arg]);
observed_type = nullable_type.getNestedType().get();
@ -392,7 +392,7 @@ bool hasStrings(const DataTypes & args)
auto check = [&](size_t i)
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -401,7 +401,7 @@ bool hasStrings(const DataTypes & args)
observed_type = args[i].get();
return (typeid_cast<const DataTypeFixedString *>(observed_type) != nullptr) ||
(typeid_cast<const DataTypeString *>(observed_type) != nullptr) || args[i].get()->isNull();
(typeid_cast<const DataTypeString *>(observed_type) != nullptr) || args[i]->isNull();
};
for (size_t i = firstThen(); i < elseArg(args); i = nextThen(i))

View File

@ -32,7 +32,7 @@ const ColumnPtr CondSource::initMaterializedCol(const Block & block, const Colum
{
const ColumnPtr & col = block.getByPosition(args[i]).column;
if (col.get()->isNull())
if (col->isNull())
{
const ColumnNull & null_col = static_cast<const ColumnNull &>(*col);
return null_col.convertToFullColumn();
@ -40,7 +40,7 @@ const ColumnPtr CondSource::initMaterializedCol(const Block & block, const Colum
const IColumn * observed_col;
if (col.get()->isNullable())
if (col->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*col);
observed_col = nullable_col.getNestedColumn().get();
@ -91,7 +91,7 @@ const PaddedPODArray<UInt8> & CondSource::initDataArray(const Block & block, con
const PaddedPODArray<UInt8> & CondSource::initNullMap(const Block & block, const ColumnNumbers & args, size_t i)
{
const ColumnPtr & col = block.getByPosition(args[i]).column;
if (col.get()->isNullable())
if (col->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*col);
const ColumnPtr & null_map = nullable_col.getNullValuesByteMap();

View File

@ -89,7 +89,7 @@ struct TypeChecker
{
static bool execute(const DataTypePtr & arg)
{
if (arg.get()->isNullable())
if (arg->isNullable())
return false;
return typeid_cast<const TType *>(arg.get()) != nullptr;
}
@ -100,7 +100,7 @@ struct TypeChecker<Nullable<TType>>
{
static bool execute(const DataTypePtr & arg)
{
if (!arg.get()->isNullable())
if (!arg->isNullable())
return false;
const DataTypeNullable & nullable_type = static_cast<DataTypeNullable &>(*arg);

View File

@ -17,9 +17,9 @@ namespace DB
namespace
{
/// Check whether at least one of the specified columns is either nullable
/// or null inside its block.
bool hasNullableBranches(const Block & block, const ColumnNumbers & args)
/// Check whether at least one of the specified branches of the function multiIf
/// is either a nullable column or a null column inside a given block.
bool blockHasNullableBranches(const Block & block, const ColumnNumbers & args)
{
auto check = [](const Block & block, size_t arg)
{
@ -40,30 +40,30 @@ bool hasNullableBranches(const Block & block, const ColumnNumbers & args)
return false;
}
bool hasNullableArgs(const DataTypes & args)
bool hasNullableDataTypes(const DataTypes & args)
{
size_t else_arg = Conditional::elseArg(args);
for (size_t i = Conditional::firstThen(); i < else_arg; i = Conditional::nextThen(i))
{
if (args[i].get()->isNullable())
if (args[i]->isNullable())
return true;
}
return args[else_arg].get()->isNullable();
return args[else_arg]->isNullable();
}
bool hasNullArgs(const DataTypes & args)
bool hasNullDataTypes(const DataTypes & args)
{
size_t else_arg = Conditional::elseArg(args);
for (size_t i = Conditional::firstThen(); i < else_arg; i = Conditional::nextThen(i))
{
if (args[i].get()->isNull())
if (args[i]->isNull())
return true;
}
return args[else_arg].get()->isNull();
return args[else_arg]->isNull();
}
}
@ -138,7 +138,7 @@ void FunctionMultiIf::executeImpl(Block & block, const ColumnNumbers & args, siz
try
{
if (!hasNullableBranches(block, args))
if (!blockHasNullableBranches(block, args))
{
perform_multi_if(block, args, result, result);
return;
@ -162,21 +162,21 @@ void FunctionMultiIf::executeImpl(Block & block, const ColumnNumbers & args, siz
args_to_transform.push_back(args[i]);
args_to_transform.push_back(args[else_arg]);
Block non_nullable_block = extractNonNullableBlock(block, args_to_transform);
Block block_with_nested_cols = createBlockWithNestedColumns(block, args_to_transform);
/// Append a column that tracks, for each result of multiIf, the index
/// of the originating column.
ColumnWithTypeAndName elem;
elem.type = std::make_shared<DataTypeUInt16>();
size_t tracker = non_nullable_block.columns();
non_nullable_block.insert(elem);
size_t tracker = block_with_nested_cols.columns();
block_with_nested_cols.insert(elem);
/// Really perform multiIf.
perform_multi_if(non_nullable_block, args, result, tracker);
perform_multi_if(block_with_nested_cols, args, result, tracker);
/// Store the result.
const ColumnWithTypeAndName & source_col = non_nullable_block.unsafeGetByPosition(result);
const ColumnWithTypeAndName & source_col = block_with_nested_cols.unsafeGetByPosition(result);
ColumnWithTypeAndName & dest_col = block.unsafeGetByPosition(result);
if (source_col.column->isNull())
@ -189,7 +189,7 @@ void FunctionMultiIf::executeImpl(Block & block, const ColumnNumbers & args, siz
dest_col.column = std::make_shared<ColumnNullable>(source_col.column);
/// Setup the null byte map of the result column by using the branch tracker column values.
ColumnPtr tracker_holder = non_nullable_block.unsafeGetByPosition(tracker).column;
ColumnPtr tracker_holder = block_with_nested_cols.unsafeGetByPosition(tracker).column;
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*dest_col.column);
if (auto col = typeid_cast<ColumnConstUInt16 *>(tracker_holder.get()))
@ -213,29 +213,30 @@ void FunctionMultiIf::executeImpl(Block & block, const ColumnNumbers & args, siz
}
else if (auto col = typeid_cast<ColumnUInt16 *>(tracker_holder.get()))
{
/// Keep track of which columns are nullable.
/// Remember which columns are nullable. This avoids us many costly
/// calls to virtual functions.
std::vector<UInt8> nullable_cols_map;
nullable_cols_map.resize(args.size());
for (const auto & arg : args)
{
const auto & col = block.unsafeGetByPosition(arg).column;
bool may_have_null = col->isNullable();
nullable_cols_map[arg] = may_have_null ? 1 : 0;
bool is_nullable = col->isNullable();
nullable_cols_map[arg] = is_nullable ? 1 : 0;
}
/// Keep track of which columns are null.
/// Remember which columns are null. The same remark as above applies.
std::vector<UInt8> null_cols_map;
null_cols_map.resize(args.size());
for (const auto & arg : args)
{
const auto & col = block.unsafeGetByPosition(arg).column;
bool has_null = col->isNull();
null_cols_map[arg] = has_null ? 1 : 0;
bool is_null = col->isNull();
null_cols_map[arg] = is_null ? 1 : 0;
}
auto null_map = std::make_shared<ColumnUInt8>(row_count);
nullable_col.getNullValuesByteMap() = null_map;
auto & null_map_data = null_map.get()->getData();
auto & null_map_data = null_map->getData();
const auto & data = col->getData();
for (size_t row = 0; row < row_count; ++row)
@ -278,11 +279,11 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
}
/// Check conditions types.
/// Check that conditions have valid types.
for (size_t i = Conditional::firstCond(); i < Conditional::elseArg(args); i = Conditional::nextCond(i))
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -302,8 +303,8 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
}
}
bool has_nullable_args = hasNullableArgs(args);
bool has_null_args = hasNullArgs(args);
bool has_nullable_types = hasNullableDataTypes(args);
bool has_null_types = hasNullDataTypes(args);
if (Conditional::hasArithmeticBranches(args))
return Conditional::getReturnTypeForArithmeticArgs(args);
@ -315,12 +316,12 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
auto push_branch_arg = [&args, &new_args](size_t i)
{
if (args[i].get()->isNull())
if (args[i]->isNull())
new_args.push_back(args[i]);
else
{
const IDataType * observed_type;
if (args[i].get()->isNullable())
if (args[i]->isNullable())
{
const auto & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -350,14 +351,14 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
/// deal with null arguments and arrays that contain null elements.
/// For now we assume that arrays do not contain any such elements.
DataTypePtr elt_type = getReturnTypeImpl(new_args);
if (elt_type.get()->isNullable())
if (elt_type->isNullable())
{
DataTypeNullable & nullable_type = static_cast<DataTypeNullable &>(*elt_type);
elt_type = nullable_type.getNestedType();
}
DataTypePtr type = std::make_shared<DataTypeArray>(elt_type);
if (has_nullable_args || has_null_args)
if (has_nullable_types || has_null_types)
type = std::make_shared<DataTypeNullable>(type);
return type;
}
@ -384,14 +385,14 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
DataTypePtr type = std::make_shared<DataTypeFixedString>(fixed_str->getN());
if (has_nullable_args || has_null_args)
if (has_nullable_types || has_null_types)
type = std::make_shared<DataTypeNullable>(type);
return type;
}
else if (Conditional::hasStrings(args))
{
DataTypePtr type = std::make_shared<DataTypeString>();
if (has_nullable_args || has_null_args)
if (has_nullable_types || has_null_types)
type = std::make_shared<DataTypeNullable>(type);
return type;
}
@ -413,11 +414,11 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
/// Make it nullable if there is at least one nullable branch
/// or one null branch.
auto get_type_to_return = [has_nullable_args, has_null_args](const DataTypePtr & arg) -> DataTypePtr
auto get_type_to_return = [has_nullable_types, has_null_types](const DataTypePtr & arg) -> DataTypePtr
{
if (arg.get()->isNullable())
if (arg->isNullable())
return arg;
else if (has_nullable_args || has_null_args)
else if (has_nullable_types || has_null_types)
return std::make_shared<DataTypeNullable>(arg);
else
return arg;
@ -425,12 +426,12 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
for (size_t i = Conditional::firstThen(); i < Conditional::elseArg(args); i = Conditional::nextThen(i))
{
if (!args[i].get()->isNull())
if (!args[i]->isNull())
return get_type_to_return(args[i]);
}
size_t i = Conditional::elseArg(args);
if (!args[i].get()->isNull())
if (!args[i]->isNull())
return get_type_to_return(args[i]);
/// All the branches are null.
@ -452,9 +453,9 @@ bool FunctionMultiIf::performTrivialCase(Block & block, const ColumnNumbers & ar
size_t else_arg = Conditional::elseArg(args);
for (size_t i = Conditional::firstThen(); i < else_arg; i = Conditional::nextThen(i))
{
if (!block.getByPosition(args[i]).type.get()->isNull())
if (!block.getByPosition(args[i]).type->isNull())
{
const auto & name = block.getByPosition(args[i]).type.get()->getName();
const auto & name = block.getByPosition(args[i]).type->getName();
if (first_type_name.empty())
{
first_type_name = name;
@ -469,7 +470,7 @@ bool FunctionMultiIf::performTrivialCase(Block & block, const ColumnNumbers & ar
}
}
if (!block.getByPosition(args[else_arg]).type.get()->isNull())
if (!block.getByPosition(args[else_arg]).type->isNull())
{
if (first_type_name.empty())
{
@ -478,7 +479,7 @@ bool FunctionMultiIf::performTrivialCase(Block & block, const ColumnNumbers & ar
}
else
{
const auto & name = block.getByPosition(args[else_arg]).type.get()->getName();
const auto & name = block.getByPosition(args[else_arg]).type->getName();
if (name != first_type_name)
return false;
}
@ -514,8 +515,8 @@ bool FunctionMultiIf::performTrivialCase(Block & block, const ColumnNumbers & ar
auto make_result = [&](size_t index)
{
res_col = block.getByPosition(index).column;
if (res_col.get()->isNull())
res_col = type.get()->createConstColumn(row_count, sample);
if (res_col->isNull())
res_col = type->createConstColumn(row_count, sample);
if (tracker != result)
{
ColumnPtr & col = block.getByPosition(tracker).column;

View File

@ -308,9 +308,9 @@ DataTypePtr FunctionAssumeNotNull::getReturnTypeImpl(const DataTypes & arguments
+ toString(arguments.size()) + ", should be 1.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH};
if (arguments[0].get()->isNull())
if (arguments[0]->isNull())
throw Exception{"NULL is an invalid value for function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
else if (arguments[0].get()->isNullable())
else if (arguments[0]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*arguments[0]);
return nullable_type.getNestedType();
@ -324,9 +324,9 @@ void FunctionAssumeNotNull::executeImpl(Block & block, const ColumnNumbers & arg
const ColumnPtr & col = block.getByPosition(arguments[0]).column;
ColumnPtr & res_col = block.getByPosition(result).column;
if (col.get()->isNull())
if (col->isNull())
throw Exception{"NULL is an invalid value for function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
else if (col.get()->isNullable())
else if (col->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*col);
res_col = nullable_col.getNestedColumn();

View File

@ -22,11 +22,8 @@ void createNullValuesByteMap(Block & block, const ColumnNumbers & args, size_t r
for (const auto & arg : args)
{
if (arg == result)
continue;
const ColumnWithTypeAndName & elem = block.unsafeGetByPosition(arg);
if (elem.column && elem.column->isNullable())
if (elem.column->isNullable())
{
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*elem.column);
res_col.updateNullValuesByteMap(nullable_col);
@ -34,87 +31,105 @@ void createNullValuesByteMap(Block & block, const ColumnNumbers & args, size_t r
}
}
/// Check if a block contains at least one null column.
bool blockHasNullColumns(const Block & block, const ColumnNumbers & arguments)
/// In a set of objects (columns of a block / set of columns / set of data types),
/// are there any "special" (i.e. nullable or null) objects?
enum class Category
{
for (const auto & arg : arguments)
/// No nullable objects. No null objects.
IS_ORDINARY = 0,
/// At least one nullable object. No null objects.
IS_NULLABLE,
/// At least one null object.
IS_NULL
};
/// Check if a block contains at least one special column, in the sense
/// defined above, among the specified columns.
Category blockHasSpecialColumns(const Block & block, const ColumnNumbers & args)
{
bool found_nullable = false;
bool found_null = false;
for (const auto & arg : args)
{
const auto & elem = block.unsafeGetByPosition(arg);
if (elem.column && elem.column->isNull())
return true;
if (!found_null && elem.column->isNull())
{
found_null = true;
break;
}
return false;
else if (!found_nullable & elem.column->isNullable())
found_nullable = true;
}
if (found_null)
return Category::IS_NULL;
else if (found_nullable)
return Category::IS_NULLABLE;
else
return Category::IS_ORDINARY;
}
/// Check if at least one column is null.
bool hasNullColumns(const ColumnsWithTypeAndName & args)
/// Check if at least one column is special in the sense defined above.
Category hasSpecialColumns(const ColumnsWithTypeAndName & args)
{
bool found_nullable = false;
bool found_null = false;
for (const auto & arg : args)
{
if (arg.type.get()->isNull())
return true;
if (!found_null && arg.type->isNull())
{
found_null = true;
break;
}
else if (!found_nullable & arg.type->isNullable())
found_nullable = true;
}
return false;
if (found_null)
return Category::IS_NULL;
else if (found_nullable)
return Category::IS_NULLABLE;
else
return Category::IS_ORDINARY;
}
/// Check if at least one argument is null.
bool hasNullArguments(const DataTypes & args)
/// Check if at least one data type is special in the sense defined above.
Category hasSpecialDataTypes(const DataTypes & args)
{
bool found_nullable = false;
bool found_null = false;
for (const auto & arg : args)
{
if (arg.get()->isNull())
return true;
}
return false;
}
/// Check if a block contains at least one nullable column.
bool blockHasNullableColumns(const Block & block, const ColumnNumbers & arguments)
{
for (const auto & arg : arguments)
if (!found_null && arg->isNull())
{
const auto & elem = block.unsafeGetByPosition(arg);
if (elem.column && elem.column->isNullable())
return true;
found_null = true;
break;
}
return false;
}
/// Check if at least one column is nullable.
bool hasNullableColumns(const ColumnsWithTypeAndName & args)
{
for (const auto & arg : args)
{
if (arg.type.get()->isNullable())
return true;
else if (!found_nullable & arg->isNullable())
found_nullable = true;
}
return false;
if (found_null)
return Category::IS_NULL;
else if (found_nullable)
return Category::IS_NULLABLE;
else
return Category::IS_ORDINARY;
}
/// Check if at least one argument is nullable.
bool hasNullableArguments(const DataTypes & args)
{
for (const auto & arg : args)
{
if (arg.get()->isNullable())
return true;
}
return false;
}
/// Turn the specified set of columns into a set of non-nullable columns.
ColumnsWithTypeAndName toNonNullableColumns(const ColumnsWithTypeAndName & args)
/// Turn the specified set of columns into their respective nested columns.
ColumnsWithTypeAndName toNestedColumns(const ColumnsWithTypeAndName & args)
{
ColumnsWithTypeAndName new_args;
new_args.reserve(args.size());
for (const auto & arg : args)
{
if (arg.type.get()->isNullable())
if (arg.type->isNullable())
{
auto nullable_col = static_cast<const ColumnNullable *>(arg.column.get());
ColumnPtr nested_col = (nullable_col != nullptr) ? nullable_col->getNestedColumn() : nullptr;
@ -130,15 +145,15 @@ ColumnsWithTypeAndName toNonNullableColumns(const ColumnsWithTypeAndName & args)
return new_args;
}
/// Turn the specified set of data types into a set of non-nullable data types.
DataTypes toNonNullableArguments(const DataTypes & args)
/// Turn the specified set of data types into their respective nested data types.
DataTypes toNestedDataTypes(const DataTypes & args)
{
DataTypes new_args;
new_args.reserve(args.size());
for (const auto & arg : args)
{
if (arg.get()->isNullable())
if (arg->isNullable())
{
auto nullable_type = static_cast<const DataTypeNullable *>(arg.get());
DataTypePtr nested_type = nullable_type->getNestedType();
@ -155,15 +170,27 @@ DataTypes toNonNullableArguments(const DataTypes & args)
DataTypePtr IFunction::getReturnType(const DataTypes & arguments) const
{
if (!hasSpecialSupportForNulls() && hasNullArguments(arguments))
return std::make_shared<DataTypeNull>();
auto category = hasSpecialDataTypes(arguments);
if (!hasSpecialSupportForNulls() && hasNullableArguments(arguments))
if (category == Category::IS_ORDINARY)
{
const DataTypes new_args = toNonNullableArguments(arguments);
}
else if (category == Category::IS_NULL)
{
if (!hasSpecialSupportForNulls())
return std::make_shared<DataTypeNull>();
}
else if (category == Category::IS_NULLABLE)
{
if (!hasSpecialSupportForNulls())
{
const DataTypes new_args = toNestedDataTypes(arguments);
return getReturnTypeImpl(new_args);
}
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
return getReturnTypeImpl(arguments);
}
@ -172,50 +199,168 @@ void IFunction::getReturnTypeAndPrerequisites(
DataTypePtr & out_return_type,
std::vector<ExpressionAction> & out_prerequisites)
{
if (!hasSpecialSupportForNulls() && hasNullColumns(arguments))
{
out_return_type = std::make_shared<DataTypeNull>();
return;
}
auto category = hasSpecialColumns(arguments);
if (!hasSpecialSupportForNulls() && hasNullableColumns(arguments))
if (category == Category::IS_ORDINARY)
{
const ColumnsWithTypeAndName new_args = toNonNullableColumns(arguments);
}
else if (category == Category::IS_NULL)
{
if (!hasSpecialSupportForNulls())
out_return_type = std::make_shared<DataTypeNull>();
}
else if (category == Category::IS_NULLABLE)
{
if (!hasSpecialSupportForNulls())
{
const ColumnsWithTypeAndName new_args = toNestedColumns(arguments);
getReturnTypeAndPrerequisitesImpl(new_args, out_return_type, out_prerequisites);
out_return_type = std::make_shared<DataTypeNullable>(out_return_type);
}
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
getReturnTypeAndPrerequisitesImpl(arguments, out_return_type, out_prerequisites);
}
void IFunction::getLambdaArgumentTypes(DataTypes & arguments) const
{
if (!hasSpecialSupportForNulls() && hasNullArguments(arguments))
return;
auto category = hasSpecialDataTypes(arguments);
if (!hasSpecialSupportForNulls() && hasNullableArguments(arguments))
if (category == Category::IS_ORDINARY)
{
DataTypes new_args = toNonNullableArguments(arguments);
}
else if (category == Category::IS_NULL)
{
if (!hasSpecialSupportForNulls())
return;
}
else if (category == Category::IS_NULLABLE)
{
if (!hasSpecialSupportForNulls())
{
DataTypes new_args = toNestedDataTypes(arguments);
getLambdaArgumentTypesImpl(new_args);
arguments = std::move(new_args);
}
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
getLambdaArgumentTypesImpl(arguments);
}
void IFunction::execute(Block & block, const ColumnNumbers & args, size_t result)
{
auto strategy = chooseStrategy(block, args);
Block processed_block = preProcessBlock(strategy, block, args);
if (strategy != RETURN_NULL)
{
Block & src = processed_block ? processed_block : block;
executeImpl(src, args, result);
}
postProcessResult(strategy, block, processed_block, args, result);
}
void IFunction::execute(Block & block, const ColumnNumbers & args, const ColumnNumbers & prerequisites, size_t result)
{
auto strategy = chooseStrategy(block, args);
Block processed_block = preProcessBlock(strategy, block, args);
if (strategy != RETURN_NULL)
{
Block & src = processed_block ? processed_block : block;
executeImpl(src, args, prerequisites, result);
}
postProcessResult(strategy, block, processed_block, args, result);
}
IFunction::Strategy IFunction::chooseStrategy(const Block & block, const ColumnNumbers & args)
{
auto category = blockHasSpecialColumns(block, args);
if (category == Category::IS_ORDINARY)
{
}
else if (category == Category::IS_NULL)
{
if (!hasSpecialSupportForNulls())
return RETURN_NULL;
}
else if (category == Category::IS_NULLABLE)
{
if (!hasSpecialSupportForNulls())
return PROCESS_NULLABLE_COLUMNS;
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
return DIRECTLY_EXECUTE;
}
Block IFunction::preProcessBlock(Strategy strategy, const Block & block, const ColumnNumbers & args)
{
if (strategy == DIRECTLY_EXECUTE)
return {};
else if (strategy == RETURN_NULL)
return {};
else if (strategy == PROCESS_NULLABLE_COLUMNS)
{
/// Run the function on a block whose nullable columns have been replaced
/// with their respective nested columns.
return createBlockWithNestedColumns(block, args);
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
}
void IFunction::postProcessResult(Strategy strategy, Block & block, const Block & processed_block,
const ColumnNumbers & args, size_t result)
{
if (strategy == DIRECTLY_EXECUTE)
{
}
else if (strategy == RETURN_NULL)
{
/// We have found at least one NULL argument. Therefore we return NULL.
ColumnWithTypeAndName & dest_col = block.getByPosition(result);
dest_col.column = std::make_shared<ColumnNull>(block.rowsInFirstColumn(), Null());
}
else if (strategy == PROCESS_NULLABLE_COLUMNS)
{
/// Initialize the result column.
const ColumnWithTypeAndName & source_col = processed_block.getByPosition(result);
ColumnWithTypeAndName & dest_col = block.getByPosition(result);
dest_col.column = std::make_shared<ColumnNullable>(source_col.column);
/// Make a null map for the result.
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*dest_col.column);
nullable_col.getNullValuesByteMap() = std::make_shared<ColumnUInt8>(dest_col.column->size(), 0);
createNullValuesByteMap(block, args, result);
}
else
throw Exception{"IFunction: internal error", ErrorCodes::LOGICAL_ERROR};
}
/// Return a copy of a given block in which the specified columns are replaced by
/// their respective nested columns if they are nullable.
Block IFunction::extractNonNullableBlock(const Block & block, ColumnNumbers args)
Block IFunction::createBlockWithNestedColumns(const Block & block, ColumnNumbers args)
{
std::sort(args.begin(), args.end());
Block non_nullable_block;
Block res;
size_t j = 0;
for (size_t i = 0; i < block.columns(); ++i)
{
const auto & col = block.unsafeGetByPosition(i);
bool found = std::binary_search(args.begin(), args.end(), i) && col.column && col.type;
bool found = (i == args[j]);
//bool found = std::binary_search(args.begin(), args.end(), i);
if (found && col.column->isNullable())
{
@ -225,65 +370,13 @@ Block IFunction::extractNonNullableBlock(const Block & block, ColumnNumbers args
auto nullable_type = static_cast<const DataTypeNullable *>(col.type.get());
DataTypePtr nested_type = nullable_type->getNestedType();
non_nullable_block.insert(i, {nested_col, nested_type, col.name});
res.insert(i, {nested_col, nested_type, col.name});
}
else
non_nullable_block.insert(i, col);
res.insert(i, col);
}
return non_nullable_block;
}
template <typename Fun>
void IFunction::perform(Block & block, const ColumnNumbers & arguments, size_t result, const Fun & performer)
{
if (!hasSpecialSupportForNulls() && blockHasNullColumns(block, arguments))
{
/// We have found at least one NULL argument. Therefore we return NULL.
ColumnWithTypeAndName & dest_col = block.getByPosition(result);
dest_col.column = std::make_shared<ColumnNull>(block.rowsInFirstColumn(), Null());
return;
}
if (!hasSpecialSupportForNulls() && blockHasNullableColumns(block, arguments))
{
/// Run the function on a block whose nullable columns have been replaced
/// with their respective nested columns.
Block non_nullable_block = extractNonNullableBlock(block, arguments);
performer(non_nullable_block, arguments, result);
/// Initialize the result column.
const ColumnWithTypeAndName & source_col = non_nullable_block.getByPosition(result);
ColumnWithTypeAndName & dest_col = block.getByPosition(result);
dest_col.column = std::make_shared<ColumnNullable>(source_col.column);
/// Make a null map for the result.
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*dest_col.column);
nullable_col.getNullValuesByteMap() = std::make_shared<ColumnUInt8>(dest_col.column->size(), 0);
createNullValuesByteMap(block, arguments, result);
}
else
performer(block, arguments, result);
}
void IFunction::execute(Block & block, const ColumnNumbers & arguments, size_t result)
{
auto performer = [&](Block & block, const ColumnNumbers & arguments, size_t result)
{
executeImpl(block, arguments, result);
};
perform(block, arguments, result, performer);
}
void IFunction::execute(Block & block, const ColumnNumbers & arguments, const ColumnNumbers & prerequisites, size_t result)
{
auto performer = [&](Block & block, const ColumnNumbers & arguments, size_t result)
{
executeImpl(block, arguments, prerequisites, result);
};
perform(block, arguments, result, performer);
return res;
}
}

View File

@ -277,7 +277,7 @@ Block LogBlockInputStream::readImpl()
bool read_offsets = true;
const IDataType * observed_type;
if (column.type.get()->isNullable())
if (column.type->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*column.type);
observed_type = nullable_type.getNestedType().get();

View File

@ -3414,7 +3414,7 @@ void StorageReplicatedMergeTree::reshardPartitions(ASTPtr query, const String &
block_number = resharding_worker.subscribe(coordinator_id, queryToString(query));
NameAndTypePair column_desc = ITableDeclaration::getColumn(sharding_key_expr->getColumnName());
if (column_desc.type.get()->isNullable())
if (column_desc.type->isNullable())
throw Exception{"Sharding key must not be nullable", ErrorCodes::RESHARDING_NULLABLE_SHARDING_KEY};
for (const auto & weighted_path : weighted_zookeeper_paths)

View File

@ -202,7 +202,7 @@ Block TinyLogBlockInputStream::readImpl()
bool read_offsets = true;
const IDataType * observed_type;
if (column.type.get()->isNullable())
if (column.type->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*column.type);
observed_type = nullable_type.getNestedType().get();