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)) for (size_t i = firstThen(); i < else_arg; i = nextThen(i))
{ {
if (args[i]->isNull())
continue;
const IDataType * observed_type; const IDataType * observed_type;
if (!args[i]->isNullable()) if (args[i]->isNullable())
{ {
const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]); const DataTypeNullable & nullable_type = static_cast<const DataTypeNullable &>(*args[i]);
observed_type = nullable_type.getNestedType().get(); observed_type = nullable_type.getNestedType().get();
@ -374,7 +377,9 @@ bool hasFixedStringsOfIdenticalLength(const DataTypes & args)
else else
observed_type = args[else_arg].get(); 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); size_t length = get_length(observed_type, else_arg);
if (length != first_length) 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; return true;
} }

View File

@ -66,6 +66,34 @@ bool hasNullDataTypes(const DataTypes & args)
return args[else_arg]->isNull(); 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) void registerFunctionsConditional(FunctionFactory & factory)
@ -378,16 +406,14 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
} }
const IDataType * data = args[Conditional::firstThen()].get(); auto type = getReturnTypeFromFirstNonNullBranch(args, has_nullable_types, has_null_types);
const auto * fixed_str = typeid_cast<const DataTypeFixedString *>(data); if (type)
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);
return 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)) else if (Conditional::hasStrings(args))
{ {
@ -410,29 +436,9 @@ DataTypePtr FunctionMultiIf::getReturnTypeInternal(const DataTypes & args) const
} }
else else
{ {
/// Return the type of the first non-null branch. auto type = getReturnTypeFromFirstNonNullBranch(args, has_nullable_types, has_null_types);
/// Make it nullable if there is at least one nullable branch if (type)
/// or one null branch. return type;
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]);
/// All the branches are null. /// All the branches are null.
return std::make_shared<DataTypeNull>(); return std::make_shared<DataTypeNull>();