mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-30 03:22:14 +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 isDate(const DataTypePtr & data_type) { return WhichDataType(data_type).isDate(); }
|
||||||
inline bool isDateOrDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateOrDateTime(); }
|
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 isDateTime64(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime64(); }
|
||||||
inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_type).isEnum(); }
|
inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_type).isEnum(); }
|
||||||
inline bool isDecimal(const DataTypePtr & data_type) { return WhichDataType(data_type).isDecimal(); }
|
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 ILLEGAL_COLUMN;
|
||||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
||||||
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
||||||
@ -124,9 +125,9 @@ namespace
|
|||||||
void validateArgumentsImpl(const IFunction & func,
|
void validateArgumentsImpl(const IFunction & func,
|
||||||
const ColumnsWithTypeAndName & arguments,
|
const ColumnsWithTypeAndName & arguments,
|
||||||
size_t argument_offset,
|
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;
|
const auto argument_index = i + argument_offset;
|
||||||
if (argument_index >= arguments.size())
|
if (argument_index >= arguments.size())
|
||||||
@ -135,24 +136,36 @@ void validateArgumentsImpl(const IFunction & func,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto & arg = arguments[i + argument_offset];
|
const auto & arg = arguments[i + argument_offset];
|
||||||
const auto validator = validators[i];
|
const auto validator = decriptors[i];
|
||||||
if (!validator.validator_func(*arg.type))
|
if (!validator.isValid(arg.type, arg.column))
|
||||||
throw Exception("Illegal type " + arg.type->getName() +
|
throw Exception("Illegal type of argument #" + std::to_string(i)
|
||||||
" of " + std::to_string(i) +
|
+ (validator.argument_name ? " '" + std::string(validator.argument_name) + "'": std::string{})
|
||||||
" argument of function " + func.getName() +
|
+ " of function " + func.getName()
|
||||||
" expected " + validator.expected_type_description,
|
+ ", expected " + validator.expected_type_description
|
||||||
|
+ (arg.type ? ", got " + arg.type->getName() : std::string{}),
|
||||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
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,
|
void validateFunctionArgumentTypes(const IFunction & func,
|
||||||
const ColumnsWithTypeAndName & arguments,
|
const ColumnsWithTypeAndName & arguments,
|
||||||
const FunctionArgumentTypeValidators & mandatory_args,
|
const FunctionArgumentDescriptors & mandatory_args,
|
||||||
const FunctionArgumentTypeValidators & optional_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
|
auto joinArgumentTypes = [](const auto & args, const String sep = ", ") -> String
|
||||||
{
|
{
|
||||||
@ -160,8 +173,12 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
|||||||
for (const auto & a : args)
|
for (const auto & a : args)
|
||||||
{
|
{
|
||||||
using A = std::decay_t<decltype(a)>;
|
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;
|
result += a.expected_type_description;
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<A, ColumnWithTypeAndName>)
|
else if constexpr (std::is_same_v<A, ColumnWithTypeAndName>)
|
||||||
result += a.type->getName();
|
result += a.type->getName();
|
||||||
|
|
||||||
@ -174,10 +191,14 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
throw Exception("Incorrect number of arguments of function " + func.getName()
|
throw Exception("Incorrect number of arguments for function " + func.getName()
|
||||||
+ " provided " + std::to_string(arguments.size()) + " (" + joinArgumentTypes(arguments) + ")"
|
+ " 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()) : "")
|
+ (arguments.size() ? " (" + joinArgumentTypes(arguments) + ")" : String{} )
|
||||||
+ " (" + joinArgumentTypes(mandatory_args) + (optional_args.size() ? ", [" + joinArgumentTypes(mandatory_args) + "]" : "") + ")",
|
+ ", 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);
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,13 +91,19 @@ void validateArgumentType(const IFunction & func, const DataTypes & arguments,
|
|||||||
const char * expected_type_description);
|
const char * expected_type_description);
|
||||||
|
|
||||||
// Simple validator that is used in conjunction with validateFunctionArgumentTypes() to check if function arguments are as expected.
|
// 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;
|
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.
|
/** 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.
|
* 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.
|
/// 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 *>
|
std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *>
|
||||||
|
@ -898,16 +898,19 @@ public:
|
|||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
FunctionArgumentTypeValidators mandatory_args = {{[](const auto &) {return true;}, "ANY TYPE"}};
|
FunctionArgumentDescriptors mandatory_args = {{"Value", nullptr, nullptr, "ANY TYPE"}};
|
||||||
FunctionArgumentTypeValidators optional_args;
|
FunctionArgumentDescriptors optional_args;
|
||||||
|
|
||||||
if constexpr (to_decimal || to_datetime64)
|
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);
|
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||||
@ -918,8 +921,8 @@ public:
|
|||||||
}
|
}
|
||||||
else if constexpr (to_decimal)
|
else if constexpr (to_decimal)
|
||||||
{
|
{
|
||||||
if (!arguments[1].column)
|
// if (!arguments[1].column)
|
||||||
throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
// throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
||||||
|
|
||||||
UInt64 scale = extractToDecimalScale(arguments[1]);
|
UInt64 scale = extractToDecimalScale(arguments[1]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user