mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 17:41:59 +00:00
Fixed type check in toDateTime64
This commit is contained in:
parent
94318c50a1
commit
87f58864d3
@ -534,6 +534,7 @@ struct WhichDataType
|
||||
|
||||
inline bool isDate(const DataTypePtr & data_type) { return WhichDataType(data_type).isDate(); }
|
||||
inline bool isDateOrDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateOrDateTime(); }
|
||||
inline bool isDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime(); }
|
||||
inline bool isDateTime64(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime64(); }
|
||||
inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_type).isEnum(); }
|
||||
inline bool isDecimal(const DataTypePtr & data_type) { return WhichDataType(data_type).isDecimal(); }
|
||||
|
@ -19,6 +19,7 @@ namespace ErrorCodes
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
}
|
||||
|
||||
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
||||
@ -124,9 +125,9 @@ namespace
|
||||
void validateArgumentsImpl(const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
size_t argument_offset,
|
||||
const FunctionArgumentTypeValidators & validators)
|
||||
const FunctionArgumentDescriptors & decriptors)
|
||||
{
|
||||
for (size_t i = 0; i < validators.size(); ++i)
|
||||
for (size_t i = 0; i < decriptors.size(); ++i)
|
||||
{
|
||||
const auto argument_index = i + argument_offset;
|
||||
if (argument_index >= arguments.size())
|
||||
@ -135,24 +136,36 @@ void validateArgumentsImpl(const IFunction & func,
|
||||
}
|
||||
|
||||
const auto & arg = arguments[i + argument_offset];
|
||||
const auto validator = validators[i];
|
||||
if (!validator.validator_func(*arg.type))
|
||||
throw Exception("Illegal type " + arg.type->getName() +
|
||||
" of " + std::to_string(i) +
|
||||
" argument of function " + func.getName() +
|
||||
" expected " + validator.expected_type_description,
|
||||
const auto validator = decriptors[i];
|
||||
if (!validator.isValid(arg.type, arg.column))
|
||||
throw Exception("Illegal type of argument #" + std::to_string(i)
|
||||
+ (validator.argument_name ? " '" + std::string(validator.argument_name) + "'": std::string{})
|
||||
+ " of function " + func.getName()
|
||||
+ ", expected " + validator.expected_type_description
|
||||
+ (arg.type ? ", got " + arg.type->getName() : std::string{}),
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool FunctionArgumentDescriptor::isValid(const DataTypePtr & data_type, const ColumnPtr & column) const
|
||||
{
|
||||
if (type_validator_func && !(data_type && type_validator_func(*data_type)))
|
||||
return false;
|
||||
|
||||
if (column_validator_func && !(column && column_validator_func(*column)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void validateFunctionArgumentTypes(const IFunction & func,
|
||||
const ColumnsWithTypeAndName & arguments,
|
||||
const FunctionArgumentTypeValidators & mandatory_args,
|
||||
const FunctionArgumentTypeValidators & optional_args)
|
||||
const FunctionArgumentDescriptors & mandatory_args,
|
||||
const FunctionArgumentDescriptors & optional_args)
|
||||
{
|
||||
if (arguments.size() < mandatory_args.size())
|
||||
if (arguments.size() < mandatory_args.size() || arguments.size() > mandatory_args.size() + optional_args.size())
|
||||
{
|
||||
auto joinArgumentTypes = [](const auto & args, const String sep = ", ") -> String
|
||||
{
|
||||
@ -160,8 +173,12 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
||||
for (const auto & a : args)
|
||||
{
|
||||
using A = std::decay_t<decltype(a)>;
|
||||
if constexpr (std::is_same_v<A, FunctionArgumentTypeValidator>)
|
||||
if constexpr (std::is_same_v<A, FunctionArgumentDescriptor>)
|
||||
{
|
||||
if (a.argument_name)
|
||||
result += "'" + std::string(a.argument_name) + "' : ";
|
||||
result += a.expected_type_description;
|
||||
}
|
||||
else if constexpr (std::is_same_v<A, ColumnWithTypeAndName>)
|
||||
result += a.type->getName();
|
||||
|
||||
@ -174,10 +191,14 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
||||
return result;
|
||||
};
|
||||
|
||||
throw Exception("Incorrect number of arguments of function " + func.getName()
|
||||
+ " provided " + std::to_string(arguments.size()) + " (" + joinArgumentTypes(arguments) + ")"
|
||||
+ " expected " + std::to_string(mandatory_args.size()) + (optional_args.size() ? " or " + std::to_string(mandatory_args.size() + optional_args.size()) : "")
|
||||
+ " (" + joinArgumentTypes(mandatory_args) + (optional_args.size() ? ", [" + joinArgumentTypes(mandatory_args) + "]" : "") + ")",
|
||||
throw Exception("Incorrect number of arguments for function " + func.getName()
|
||||
+ " provided " + std::to_string(arguments.size())
|
||||
+ (arguments.size() ? " (" + joinArgumentTypes(arguments) + ")" : String{} )
|
||||
+ ", expected " + std::to_string(mandatory_args.size())
|
||||
+ (optional_args.size() ? " to " + std::to_string(mandatory_args.size() + optional_args.size()) : "")
|
||||
+ " (" + joinArgumentTypes(mandatory_args)
|
||||
+ (optional_args.size() ? ", [" + joinArgumentTypes(optional_args) + "]" : "")
|
||||
+ ")",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
}
|
||||
|
||||
|
@ -91,13 +91,19 @@ void validateArgumentType(const IFunction & func, const DataTypes & arguments,
|
||||
const char * expected_type_description);
|
||||
|
||||
// Simple validator that is used in conjunction with validateFunctionArgumentTypes() to check if function arguments are as expected.
|
||||
struct FunctionArgumentTypeValidator
|
||||
struct FunctionArgumentDescriptor
|
||||
{
|
||||
bool (* validator_func)(const IDataType &);
|
||||
const char * argument_name;
|
||||
|
||||
bool (* type_validator_func)(const IDataType &);
|
||||
bool (* column_validator_func)(const IColumn &);
|
||||
|
||||
const char * expected_type_description;
|
||||
|
||||
bool isValid(const DataTypePtr & data_type, const ColumnPtr & column) const;
|
||||
};
|
||||
|
||||
using FunctionArgumentTypeValidators = std::vector<FunctionArgumentTypeValidator>;
|
||||
using FunctionArgumentDescriptors = std::vector<FunctionArgumentDescriptor>;
|
||||
|
||||
/** Validate that function arguments match specification.
|
||||
*
|
||||
@ -117,7 +123,9 @@ using FunctionArgumentTypeValidators = std::vector<FunctionArgumentTypeValidator
|
||||
*
|
||||
* If any mandatory arg is missing, throw an exception, with explicit description of expected arguments.
|
||||
*/
|
||||
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments, const FunctionArgumentTypeValidators & mandatory_args, const FunctionArgumentTypeValidators & optional_args = {});
|
||||
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments,
|
||||
const FunctionArgumentDescriptors & mandatory_args,
|
||||
const FunctionArgumentDescriptors & optional_args = {});
|
||||
|
||||
/// Checks if a list of array columns have equal offsets. Return a pair of nested columns and offsets if true, otherwise throw.
|
||||
std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *>
|
||||
|
@ -898,16 +898,19 @@ public:
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
FunctionArgumentTypeValidators mandatory_args = {{[](const auto &) {return true;}, "ANY TYPE"}};
|
||||
FunctionArgumentTypeValidators optional_args;
|
||||
FunctionArgumentDescriptors mandatory_args = {{"Value", nullptr, nullptr, "ANY TYPE"}};
|
||||
FunctionArgumentDescriptors optional_args;
|
||||
|
||||
if constexpr (to_decimal || to_datetime64)
|
||||
{
|
||||
mandatory_args.push_back(FunctionArgumentTypeValidator{&isNativeInteger, "Integer"}); // scale
|
||||
mandatory_args.push_back({"scale", &isNativeInteger, &isColumnConst, "const Integer"});
|
||||
}
|
||||
else
|
||||
// toString(DateTime or DateTime64, [timezone: String])
|
||||
if ((std::is_same_v<Name, NameToString> && arguments.size() > 0 && (isDateTime64(arguments[0].type) || isDateTime(arguments[0].type)))
|
||||
// toDateTime(value, [timezone: String]) or toDateTime64(value, scale : Integer, [timezone: string])
|
||||
|| std::is_same_v<ToDataType, DataTypeDateTime> || std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||
{
|
||||
optional_args.push_back(FunctionArgumentTypeValidator{&isString, "String"}); // timezone
|
||||
optional_args.push_back({"timezone", &isString, &isColumnConst, "const String"});
|
||||
}
|
||||
|
||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||
@ -918,8 +921,8 @@ public:
|
||||
}
|
||||
else if constexpr (to_decimal)
|
||||
{
|
||||
if (!arguments[1].column)
|
||||
throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
||||
// if (!arguments[1].column)
|
||||
// throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
||||
|
||||
UInt64 scale = extractToDecimalScale(arguments[1]);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user