dbms: fix [#METR-19266]

This commit is contained in:
Alexey Arno 2016-08-15 17:07:23 +03:00
parent a9310a5568
commit 04c9975c84
2 changed files with 48 additions and 34 deletions

View File

@ -340,8 +340,11 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
for (size_t i = firstThen(); i < else_arg; i = nextThen(i))
{
if (args[i]->isNull())
continue;
const IDataType * observed_type;
if (!args[i]->isNullable())
if (args[i]->isNullable())
{
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get();
@ -374,7 +377,9 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
else
observed_type = args[else_arg].get();
if (has_length)
if (!has_length)
has_length = true;
else
{
size_t length = get_length(observed_type, else_arg);
if (length != first_length)
@ -382,6 +387,9 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
}
}
if (!has_length)
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
return true;
}

View File

@ -66,6 +66,34 @@ bool hasNullDataTypes(const DataTypes & args)
return args[else_arg]->isNull();
}
/// Return the type of the first non-null branch. Make it nullable
/// if there is at least one nullable branch or one null branch.
/// This function is used in a very few number of cases in getReturnTypeImpl().
DataTypePtr getReturnTypeFromFirstNonNullBranch(const DataTypes & args, bool has_nullable_types, bool has_null_types)
{
auto get_type_to_return = [has_nullable_types, has_null_types](const DataTypePtr & arg) -> DataTypePtr
{
if (arg->isNullable())
return arg;
else if (has_nullable_types || has_null_types)
return std::make_shared<DataTypeNullable>(arg);
else
return arg;
};
for (size_t i = Conditional::firstThen(); i < Conditional::elseArg(args); i = Conditional::nextThen(i))
{
if (!args[i]->isNull())
return get_type_to_return(args[i]);
}
size_t i = Conditional::elseArg(args);
if (!args[i]->isNull())
return get_type_to_return(args[i]);
return {};
}
}
void registerFunctionsConditional(FunctionFactory & factory)
@ -378,16 +406,14 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
}
const IDataType * data = args[Conditional::firstThen()].get();
const auto * fixed_str = typeid_cast<const DataTypeFixedString *>(data);
if (fixed_str == nullptr)
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
DataTypePtr type = std::make_shared<DataTypeFixedString>(fixed_str->getN());
if (has_nullable_types || has_null_types)
type = std::make_shared<DataTypeNullable>(type);
auto type = getReturnTypeFromFirstNonNullBranch(args, has_nullable_types, has_null_types);
if (type)
return type;
else
{
/// This cannot happen: at least one fixed string is not null.
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR};
}
}
else if (Conditional::hasStrings(args))
{
@ -410,29 +436,9 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
}
else
{
/// Return the type of the first non-null branch.
/// Make it nullable if there is at least one nullable branch
/// or one null branch.
auto get_type_to_return = [has_nullable_types, has_null_types](const DataTypePtr & arg) -> DataTypePtr
{
if (arg->isNullable())
return arg;
else if (has_nullable_types || has_null_types)
return std::make_shared<DataTypeNullable>(arg);
else
return arg;
};
for (size_t i = Conditional::firstThen(); i < Conditional::elseArg(args); i = Conditional::nextThen(i))
{
if (!args[i]->isNull())
return get_type_to_return(args[i]);
}
size_t i = Conditional::elseArg(args);
if (!args[i]->isNull())
return get_type_to_return(args[i]);
auto type = getReturnTypeFromFirstNonNullBranch(args, has_nullable_types, has_null_types);
if (type)
return type;
/// All the branches are null.
return std::make_shared<DataTypeNull>();