mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 10:31:57 +00:00
ISSUES-4006 add factor with DateTime type
This commit is contained in:
parent
e032593005
commit
43839a97b6
@ -185,31 +185,4 @@ bool DataTypeDateTime::equals(const IDataType & rhs) const
|
|||||||
return typeid(rhs) == typeid(*this);
|
return typeid(rhs) == typeid(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ErrorCodes
|
|
||||||
{
|
|
||||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
|
||||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
|
||||||
{
|
|
||||||
if (!arguments)
|
|
||||||
return std::make_shared<DataTypeDateTime>();
|
|
||||||
|
|
||||||
if (arguments->children.size() != 1)
|
|
||||||
throw Exception("DateTime data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
||||||
|
|
||||||
const auto * arg = arguments->children[0]->as<ASTLiteral>();
|
|
||||||
if (!arg || arg->value.getType() != Field::Types::String)
|
|
||||||
throw Exception("Parameter for DateTime data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
||||||
|
|
||||||
return std::make_shared<DataTypeDateTime>(arg->value.get<String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerDataTypeDateTime(DataTypeFactory & factory)
|
|
||||||
{
|
|
||||||
factory.registerDataType("DateTime", create, DataTypeFactory::CaseInsensitive);
|
|
||||||
factory.registerAlias("TIMESTAMP", "DateTime", DataTypeFactory::CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -201,65 +201,4 @@ bool DataTypeDateTime64::equals(const IDataType & rhs) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ErrorCodes
|
|
||||||
{
|
|
||||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
|
||||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class ArgumentKind
|
|
||||||
{
|
|
||||||
Optional,
|
|
||||||
Mandatory
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, ArgumentKind Kind>
|
|
||||||
std::conditional_t<Kind == ArgumentKind::Optional, std::optional<T>, T>
|
|
||||||
getArgument(const ASTPtr & arguments, size_t argument_index, const char * argument_name, const std::string context_data_type_name)
|
|
||||||
{
|
|
||||||
using NearestResultType = NearestFieldType<T>;
|
|
||||||
const auto field_type = Field::TypeToEnum<NearestResultType>::value;
|
|
||||||
const ASTLiteral * argument = nullptr;
|
|
||||||
|
|
||||||
auto exception_message = [=](const String & message)
|
|
||||||
{
|
|
||||||
return std::string("Parameter #") + std::to_string(argument_index) + " '"
|
|
||||||
+ argument_name + "' for " + context_data_type_name
|
|
||||||
+ message
|
|
||||||
+ ", expected: " + Field::Types::toString(field_type) + " literal.";
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!arguments || arguments->children.size() <= argument_index
|
|
||||||
|| !(argument = arguments->children[argument_index]->as<ASTLiteral>()))
|
|
||||||
{
|
|
||||||
if constexpr (Kind == ArgumentKind::Optional)
|
|
||||||
return {};
|
|
||||||
else
|
|
||||||
throw Exception(exception_message(" is missing"),
|
|
||||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argument->value.getType() != field_type)
|
|
||||||
throw Exception(exception_message(String(" has wrong type: ") + argument->value.getTypeName()),
|
|
||||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
||||||
|
|
||||||
return argument->value.get<NearestResultType>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static DataTypePtr create64(const ASTPtr & arguments)
|
|
||||||
{
|
|
||||||
if (!arguments || arguments->size() == 0)
|
|
||||||
return std::make_shared<DataTypeDateTime64>(DataTypeDateTime64::default_scale);
|
|
||||||
|
|
||||||
const auto scale = getArgument<UInt64, ArgumentKind::Optional>(arguments, 0, "scale", "DateType64");
|
|
||||||
const auto timezone = getArgument<String, ArgumentKind::Optional>(arguments, !!scale, "timezone", "DateType64");
|
|
||||||
|
|
||||||
return std::make_shared<DataTypeDateTime64>(scale.value_or(DataTypeDateTime64::default_scale), timezone.value_or(String{}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerDataTypeDateTime64(DataTypeFactory & factory)
|
|
||||||
{
|
|
||||||
factory.registerDataType("DateTime64", create64, DataTypeFactory::CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
110
src/DataTypes/registerDataTypeDateTime.cpp
Normal file
110
src/DataTypes/registerDataTypeDateTime.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
#include <Core/Field.h>
|
||||||
|
#include <Parsers/IAST.h>
|
||||||
|
#include <Parsers/ASTLiteral.h>
|
||||||
|
#include <DataTypes/IDataType.h>
|
||||||
|
#include <DataTypes/DataTypeDateTime.h>
|
||||||
|
#include <DataTypes/DataTypeDateTime64.h>
|
||||||
|
#include <DataTypes/DataTypeFactory.h>
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ArgumentKind
|
||||||
|
{
|
||||||
|
Optional,
|
||||||
|
Mandatory
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, ArgumentKind Kind>
|
||||||
|
std::conditional_t<Kind == ArgumentKind::Optional, std::optional<T>, T>
|
||||||
|
getArgument(const ASTPtr & arguments, size_t argument_index, const char * argument_name, const std::string context_data_type_name)
|
||||||
|
{
|
||||||
|
using NearestResultType = NearestFieldType<T>;
|
||||||
|
const auto field_type = Field::TypeToEnum<NearestResultType>::value;
|
||||||
|
const ASTLiteral * argument = nullptr;
|
||||||
|
|
||||||
|
auto exception_message = [=](const String & message)
|
||||||
|
{
|
||||||
|
return std::string("Parameter #") + std::to_string(argument_index) + " '"
|
||||||
|
+ argument_name + "' for " + context_data_type_name
|
||||||
|
+ message
|
||||||
|
+ ", expected: " + Field::Types::toString(field_type) + " literal.";
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!arguments || arguments->children.size() <= argument_index
|
||||||
|
|| !(argument = arguments->children[argument_index]->as<ASTLiteral>())
|
||||||
|
|| argument->value.getType() != field_type)
|
||||||
|
{
|
||||||
|
if constexpr (Kind == ArgumentKind::Optional)
|
||||||
|
return {};
|
||||||
|
else
|
||||||
|
throw Exception(exception_message(" is missing"),
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return argument->value.get<NearestResultType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DataTypePtr create(const ASTPtr & arguments)
|
||||||
|
{
|
||||||
|
if (!arguments || arguments->size() == 0)
|
||||||
|
return std::make_shared<DataTypeDateTime>();
|
||||||
|
|
||||||
|
const auto scale = getArgument<UInt64, ArgumentKind::Optional>(arguments, 0, "scale", "DateTime");
|
||||||
|
const auto timezone = getArgument<String, ArgumentKind::Optional>(arguments, !!scale, "timezone", "DateTime");
|
||||||
|
|
||||||
|
if (scale)
|
||||||
|
return std::make_shared<DataTypeDateTime64>(scale.value_or(DataTypeDateTime64::default_scale), timezone.value_or(String{}));
|
||||||
|
|
||||||
|
return std::make_shared<DataTypeDateTime>(timezone.value_or(String{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DataTypePtr create32(const ASTPtr & arguments)
|
||||||
|
{
|
||||||
|
if (!arguments || arguments->size() == 0)
|
||||||
|
return std::make_shared<DataTypeDateTime>();
|
||||||
|
|
||||||
|
if (arguments->children.size() != 1)
|
||||||
|
throw Exception("DateTime32 data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
|
||||||
|
const auto timezone = getArgument<String, ArgumentKind::Mandatory>(arguments, 0, "timezone", "DateTime32");
|
||||||
|
|
||||||
|
return std::make_shared<DataTypeDateTime>(timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DataTypePtr create64(const ASTPtr & arguments)
|
||||||
|
{
|
||||||
|
if (!arguments || arguments->size() == 0)
|
||||||
|
return std::make_shared<DataTypeDateTime64>(DataTypeDateTime64::default_scale);
|
||||||
|
|
||||||
|
if (arguments->children.size() > 2)
|
||||||
|
throw Exception("DateTime64 data type can optionally have two argument - scale and time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
|
||||||
|
const auto scale = getArgument<UInt64, ArgumentKind::Optional>(arguments, 0, "scale", "DateTime64");
|
||||||
|
const auto timezone = getArgument<String, ArgumentKind::Optional>(arguments, !!scale, "timezone", "DateTime64");
|
||||||
|
|
||||||
|
return std::make_shared<DataTypeDateTime64>(scale.value_or(DataTypeDateTime64::default_scale), timezone.value_or(String{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerDataTypeDateTime(DataTypeFactory & factory)
|
||||||
|
{
|
||||||
|
factory.registerDataType("DateTime", create, DataTypeFactory::CaseInsensitive);
|
||||||
|
factory.registerDataType("DateTime32", create32, DataTypeFactory::CaseInsensitive);
|
||||||
|
factory.registerDataType("DateTime64", create64, DataTypeFactory::CaseInsensitive);
|
||||||
|
|
||||||
|
factory.registerAlias("TIMESTAMP", "DateTime", DataTypeFactory::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerDataTypeDateTime64(DataTypeFactory & /*factory*/)
|
||||||
|
{
|
||||||
|
// factory.registerDataType("DateTime64", create64, DataTypeFactory::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -38,6 +38,7 @@ SRCS(
|
|||||||
getMostSubtype.cpp
|
getMostSubtype.cpp
|
||||||
IDataType.cpp
|
IDataType.cpp
|
||||||
NestedUtils.cpp
|
NestedUtils.cpp
|
||||||
|
registerDataTypeDateTime.cpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ void registerFunctionsConversion(FunctionFactory & factory)
|
|||||||
|
|
||||||
factory.registerFunction<FunctionToDate>();
|
factory.registerFunction<FunctionToDate>();
|
||||||
factory.registerFunction<FunctionToDateTime>();
|
factory.registerFunction<FunctionToDateTime>();
|
||||||
|
factory.registerFunction<FunctionToDateTime32>();
|
||||||
factory.registerFunction<FunctionToDateTime64>();
|
factory.registerFunction<FunctionToDateTime64>();
|
||||||
factory.registerFunction<FunctionToUUID>();
|
factory.registerFunction<FunctionToUUID>();
|
||||||
factory.registerFunction<FunctionToString>();
|
factory.registerFunction<FunctionToString>();
|
||||||
|
@ -968,6 +968,7 @@ struct ConvertImpl<DataTypeFixedString, DataTypeString, Name>
|
|||||||
/// Declared early because used below.
|
/// Declared early because used below.
|
||||||
struct NameToDate { static constexpr auto name = "toDate"; };
|
struct NameToDate { static constexpr auto name = "toDate"; };
|
||||||
struct NameToDateTime { static constexpr auto name = "toDateTime"; };
|
struct NameToDateTime { static constexpr auto name = "toDateTime"; };
|
||||||
|
struct NameToDateTime32 { static constexpr auto name = "toDateTime32"; };
|
||||||
struct NameToDateTime64 { static constexpr auto name = "toDateTime64"; };
|
struct NameToDateTime64 { static constexpr auto name = "toDateTime64"; };
|
||||||
struct NameToString { static constexpr auto name = "toString"; };
|
struct NameToString { static constexpr auto name = "toString"; };
|
||||||
struct NameToDecimal32 { static constexpr auto name = "toDecimal32"; };
|
struct NameToDecimal32 { static constexpr auto name = "toDecimal32"; };
|
||||||
@ -1027,6 +1028,14 @@ public:
|
|||||||
{
|
{
|
||||||
mandatory_args.push_back({"scale", &isNativeInteger, &isColumnConst, "const Integer"});
|
mandatory_args.push_back({"scale", &isNativeInteger, &isColumnConst, "const Integer"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime> && std::is_same_v<Name, NameToDateTime>)
|
||||||
|
{
|
||||||
|
/// toDateTime(value, scale:Integer)
|
||||||
|
if ((arguments.size() == 2 && isUnsignedInteger(arguments[1].type)) || arguments.size() == 3)
|
||||||
|
mandatory_args.push_back({"scale", &isNativeInteger, &isColumnConst, "const Integer"});
|
||||||
|
}
|
||||||
|
|
||||||
// toString(DateTime or DateTime64, [timezone: String])
|
// toString(DateTime or DateTime64, [timezone: String])
|
||||||
if ((std::is_same_v<Name, NameToString> && arguments.size() > 0 && (isDateTime64(arguments[0].type) || isDateTime(arguments[0].type)))
|
if ((std::is_same_v<Name, NameToString> && arguments.size() > 0 && (isDateTime64(arguments[0].type) || isDateTime(arguments[0].type)))
|
||||||
// toUnixTimestamp(value[, timezone : String])
|
// toUnixTimestamp(value[, timezone : String])
|
||||||
@ -1076,6 +1085,17 @@ public:
|
|||||||
scale = static_cast<UInt32>(arguments[1].column->get64(0));
|
scale = static_cast<UInt32>(arguments[1].column->get64(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime> && std::is_same_v<Name, NameToDateTime>)
|
||||||
|
{
|
||||||
|
/// For toDateTime('xxxx-xx-xx xx:xx:xx.00', 2[, 'timezone']) we need to it convert to DateTime64
|
||||||
|
if ((arguments.size() == 2 && isUnsignedInteger(arguments[1].type)) || arguments.size() == 3)
|
||||||
|
{
|
||||||
|
timezone_arg_position += 1;
|
||||||
|
scale = static_cast<UInt32>(arguments[1].column->get64(0));
|
||||||
|
return std::make_shared<DataTypeDateTime64>(scale, extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
|
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime>)
|
||||||
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
||||||
else if constexpr (to_datetime64)
|
else if constexpr (to_datetime64)
|
||||||
@ -1179,6 +1199,18 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<ToDataType, DataTypeDateTime> && std::is_same_v<Name, NameToDateTime>)
|
||||||
|
{
|
||||||
|
/// For toDateTime('xxxx-xx-xx xx:xx:xx.00', 2[, 'timezone']) we need to it convert to DateTime64
|
||||||
|
if ((arguments.size() == 2 && isUnsignedInteger(block.getByPosition(arguments[1]).type)) || arguments.size() == 3)
|
||||||
|
{
|
||||||
|
if (!callOnIndexAndDataType<DataTypeDateTime64>(from_type->getTypeId(), call))
|
||||||
|
throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(),
|
||||||
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool done = callOnIndexAndDataType<ToDataType>(from_type->getTypeId(), call);
|
bool done = callOnIndexAndDataType<ToDataType>(from_type->getTypeId(), call);
|
||||||
if (!done)
|
if (!done)
|
||||||
{
|
{
|
||||||
@ -1607,6 +1639,7 @@ using FunctionToFloat32 = FunctionConvert<DataTypeFloat32, NameToFloat32, ToNumb
|
|||||||
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, ToNumberMonotonicity<Float64>>;
|
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, ToNumberMonotonicity<Float64>>;
|
||||||
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToDateMonotonicity>;
|
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToDateMonotonicity>;
|
||||||
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToDateTimeMonotonicity>;
|
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToDateTimeMonotonicity>;
|
||||||
|
using FunctionToDateTime32 = FunctionConvert<DataTypeDateTime, NameToDateTime32, ToDateTimeMonotonicity>;
|
||||||
using FunctionToDateTime64 = FunctionConvert<DataTypeDateTime64, NameToDateTime64, UnknownMonotonicity>;
|
using FunctionToDateTime64 = FunctionConvert<DataTypeDateTime64, NameToDateTime64, UnknownMonotonicity>;
|
||||||
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToNumberMonotonicity<UInt128>>;
|
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToNumberMonotonicity<UInt128>>;
|
||||||
using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>;
|
using FunctionToString = FunctionConvert<DataTypeString, NameToString, ToStringMonotonicity>;
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
2020-01-01 00:00:00 DateTime 2020-01-01 00:01:00 DateTime 2020-01-01 00:02:00.11 DateTime64(2) 2020-01-01 00:03:00 DateTime(\'Europe/Moscow\') 2020-01-01 00:04:00.220 DateTime64(3, \'Europe/Moscow\') 2020-01-01 00:05:00 DateTime 2020-01-01 00:06:00 DateTime(\'Europe/Moscow\')
|
||||||
|
2020-01-01 00:00:00 DateTime 2020-01-01 00:02:00.11 DateTime64(2) 2020-01-01 00:03:00 DateTime(\'Europe/Moscow\') 2020-01-01 00:04:00.220 DateTime64(3, \'Europe/Moscow\')
|
||||||
|
2020-01-01 00:00:00 DateTime 2020-01-01 00:02:00.11 DateTime64(2) 2020-01-01 00:03:00 DateTime(\'Europe/Moscow\') 2020-01-01 00:04:00.220 DateTime64(3, \'Europe/Moscow\')
|
||||||
|
2020-01-01 00:00:00 DateTime
|
15
tests/queries/0_stateless/01442_date_time_with_params.sql
Normal file
15
tests/queries/0_stateless/01442_date_time_with_params.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
DROP TABLE IF EXISTS test;
|
||||||
|
|
||||||
|
CREATE TABLE test (a DateTime, b DateTime(), c DateTime(2), d DateTime('Europe/Moscow'), e DateTime(3, 'Europe/Moscow'), f DateTime32, g DateTime32('Europe/Moscow')) ENGINE = MergeTree ORDER BY a;
|
||||||
|
|
||||||
|
INSERT INTO test VALUES('2020-01-01 00:00:00', '2020-01-01 00:01:00', '2020-01-01 00:02:00.11', '2020-01-01 00:03:00', '2020-01-01 00:04:00.22', '2020-01-01 00:05:00', '2020-01-01 00:06:00')
|
||||||
|
|
||||||
|
SELECT a, toTypeName(a), b, toTypeName(b), c, toTypeName(c), d, toTypeName(d), e, toTypeName(e), f, toTypeName(f), g, toTypeName(g) FROM test;
|
||||||
|
|
||||||
|
SELECT toDateTime('2020-01-01 00:00:00') AS a, toTypeName(a), toDateTime('2020-01-01 00:02:00.11', 2) AS b, toTypeName(b), toDateTime('2020-01-01 00:03:00', 'Europe/Moscow') AS c, toTypeName(c), toDateTime('2020-01-01 00:04:00.22', 3, 'Europe/Moscow') AS d, toTypeName(d);
|
||||||
|
|
||||||
|
SELECT CAST('2020-01-01 00:00:00', 'DateTime') AS a, toTypeName(a), CAST('2020-01-01 00:02:00.11', 'DateTime(2)') AS b, toTypeName(b), CAST('2020-01-01 00:03:00', 'DateTime(\'Europe/Moscow\')') AS c, toTypeName(c), CAST('2020-01-01 00:04:00.22', 'DateTime(3, \'Europe/Moscow\')') AS d, toTypeName(d);
|
||||||
|
|
||||||
|
SELECT toDateTime32('2020-01-01 00:00:00') AS a, toTypeName(a);
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS test;
|
Loading…
Reference in New Issue
Block a user