mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-17 21:24:28 +00:00
Simplified argument type validation for conversion functions.
This commit is contained in:
parent
db166af95a
commit
9f9fcb1add
@ -116,4 +116,45 @@ void validateArgumentType(const IFunction & func, const DataTypes & arguments,
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void validateArgumentsImpl(const IFunction & func, const ColumnsWithTypeAndName & arguments, size_t argument_offset, const FunctionArgumentTypeValidators & validators)
|
||||
{
|
||||
for (size_t i = 0; i < validators.size(); ++i)
|
||||
{
|
||||
const auto argument_index = i + argument_offset;
|
||||
if (argument_index >= arguments.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto & arg = arguments[i + argument_offset];
|
||||
const auto validator = validators[i];
|
||||
if (validator.validator_func(*arg.type) == false)
|
||||
throw Exception("Illegal type " + arg.type->getName() +
|
||||
" of " + std::to_string(i) +
|
||||
" argument of function " + func.getName() +
|
||||
" expected " + validator.expected_type_description,
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments, const FunctionArgumentTypeValidators & mandatory_args, const FunctionArgumentTypeValidators & optional_args)
|
||||
{
|
||||
if (arguments.size() < mandatory_args.size())
|
||||
throw Exception("Incorrect number of arguments of function " + func.getName()
|
||||
+ " provided: " + std::to_string(arguments.size())
|
||||
+ " expected: " + std::to_string(mandatory_args.size())
|
||||
+ (optional_args.size() ? " or " + std::to_string(mandatory_args.size() + optional_args.size()) : ""),
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
validateArgumentsImpl(func, arguments, 0, mandatory_args);
|
||||
if (optional_args.size())
|
||||
{
|
||||
validateArgumentsImpl(func, arguments, mandatory_args.size(), optional_args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -89,4 +89,14 @@ void validateArgumentType(const IFunction & func, const DataTypes & arguments,
|
||||
size_t argument_index, bool (* validator_func)(const IDataType &),
|
||||
const char * expected_type_description);
|
||||
|
||||
struct FunctionArgumentTypeValidator
|
||||
{
|
||||
bool (* validator_func)(const IDataType &);
|
||||
const char * expected_type_description;
|
||||
};
|
||||
|
||||
using FunctionArgumentTypeValidators = std::vector<FunctionArgumentTypeValidator>;
|
||||
|
||||
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments, const FunctionArgumentTypeValidators & mandatory_args, const FunctionArgumentTypeValidators & optional_args = {});
|
||||
|
||||
}
|
||||
|
@ -832,16 +832,19 @@ public:
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
if (to_decimal && arguments.size() != 2)
|
||||
FunctionArgumentTypeValidators mandatory_args = {{[](const auto &) {return true;}, "ANY TYPE"}};
|
||||
FunctionArgumentTypeValidators optional_args;
|
||||
|
||||
if constexpr (to_decimal || std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||
{
|
||||
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
|
||||
+ toString(arguments.size()) + ", should be 2.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
mandatory_args.push_back(FunctionArgumentTypeValidator{&isNativeInteger, "Integer"}); // scale
|
||||
}
|
||||
else if (arguments.size() != 1 && arguments.size() != 2)
|
||||
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
|
||||
+ toString(arguments.size()) + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
else
|
||||
{
|
||||
optional_args.push_back(FunctionArgumentTypeValidator{&isString, "String"}); // timezone
|
||||
}
|
||||
|
||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||
|
||||
if constexpr (std::is_same_v<ToDataType, DataTypeInterval>)
|
||||
{
|
||||
@ -865,45 +868,20 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt8 max_args = 2;
|
||||
UInt8 timezone_arg_position = 1;
|
||||
UInt32 scale = DataTypeDateTime64::default_scale;
|
||||
|
||||
// DateTime64 requires more arguments: scale and timezone. Since timezone is optional, scale should be first.
|
||||
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||
{
|
||||
max_args += 1;
|
||||
if (isNativeInteger(*arguments[max_args - 1].type))
|
||||
{
|
||||
scale = static_cast<UInt32>(arguments[max_args - 1].column->get64(0));
|
||||
}
|
||||
timezone_arg_position += 1;
|
||||
scale = static_cast<UInt32>(arguments[1].column->get64(0));
|
||||
}
|
||||
|
||||
/** Optional (could be first or second) argument with time zone is supported:
|
||||
* - for functions toDateTime, toUnixTimestamp, toDate;
|
||||
* - for function toString of DateTime argument.
|
||||
*/
|
||||
if (arguments.size() == max_args)
|
||||
{
|
||||
if (!checkAndGetDataType<DataTypeString>(arguments[max_args - 1].type.get()))
|
||||
throw Exception("Illegal type " + arguments[max_args - 1].type->getName() + " of 2nd argument of function " + getName(),
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
|
||||
static constexpr bool to_date_or_time = std::is_same_v<Name, NameToDateTime>
|
||||
|| std::is_same_v<Name, NameToDate>
|
||||
|| std::is_same_v<Name, NameToUnixTimestamp>;
|
||||
|
||||
if (!(to_date_or_time
|
||||
|| (std::is_same_v<Name, NameToString> && (WhichDataType(arguments[0].type).isDateTime() || WhichDataType(arguments[0].type).isDateTime64()))))
|
||||
{
|
||||
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
|
||||
+ toString(arguments.size()) + ", should be " + std::to_string(max_args) + ".",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
if (std::is_same_v<ToDataType, DataTypeDateTime>)
|
||||
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, max_args - 1, 0));
|
||||
else if (std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||
return std::make_shared<DataTypeDateTime64>(scale, extractTimeZoneNameFromFunctionArguments(arguments, max_args - 1, 0));
|
||||
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
|
||||
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
||||
else if constexpr (std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||
return std::make_shared<DataTypeDateTime64>(scale, extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
||||
else
|
||||
return std::make_shared<ToDataType>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user