mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 02:21:59 +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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
IDataType.cpp
|
||||
NestedUtils.cpp
|
||||
registerDataTypeDateTime.cpp
|
||||
|
||||
)
|
||||
|
||||
|
@ -32,6 +32,7 @@ void registerFunctionsConversion(FunctionFactory & factory)
|
||||
|
||||
factory.registerFunction<FunctionToDate>();
|
||||
factory.registerFunction<FunctionToDateTime>();
|
||||
factory.registerFunction<FunctionToDateTime32>();
|
||||
factory.registerFunction<FunctionToDateTime64>();
|
||||
factory.registerFunction<FunctionToUUID>();
|
||||
factory.registerFunction<FunctionToString>();
|
||||
|
@ -968,6 +968,7 @@ struct ConvertImpl<DataTypeFixedString, DataTypeString, Name>
|
||||
/// Declared early because used below.
|
||||
struct NameToDate { static constexpr auto name = "toDate"; };
|
||||
struct NameToDateTime { static constexpr auto name = "toDateTime"; };
|
||||
struct NameToDateTime32 { static constexpr auto name = "toDateTime32"; };
|
||||
struct NameToDateTime64 { static constexpr auto name = "toDateTime64"; };
|
||||
struct NameToString { static constexpr auto name = "toString"; };
|
||||
struct NameToDecimal32 { static constexpr auto name = "toDecimal32"; };
|
||||
@ -1027,6 +1028,14 @@ public:
|
||||
{
|
||||
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])
|
||||
if ((std::is_same_v<Name, NameToString> && arguments.size() > 0 && (isDateTime64(arguments[0].type) || isDateTime(arguments[0].type)))
|
||||
// toUnixTimestamp(value[, timezone : String])
|
||||
@ -1076,6 +1085,17 @@ public:
|
||||
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>)
|
||||
return std::make_shared<DataTypeDateTime>(extractTimeZoneNameFromFunctionArguments(arguments, timezone_arg_position, 0));
|
||||
else if constexpr (to_datetime64)
|
||||
@ -1179,6 +1199,18 @@ private:
|
||||
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);
|
||||
if (!done)
|
||||
{
|
||||
@ -1607,6 +1639,7 @@ using FunctionToFloat32 = FunctionConvert<DataTypeFloat32, NameToFloat32, ToNumb
|
||||
using FunctionToFloat64 = FunctionConvert<DataTypeFloat64, NameToFloat64, ToNumberMonotonicity<Float64>>;
|
||||
using FunctionToDate = FunctionConvert<DataTypeDate, NameToDate, ToDateMonotonicity>;
|
||||
using FunctionToDateTime = FunctionConvert<DataTypeDateTime, NameToDateTime, ToDateTimeMonotonicity>;
|
||||
using FunctionToDateTime32 = FunctionConvert<DataTypeDateTime, NameToDateTime32, ToDateTimeMonotonicity>;
|
||||
using FunctionToDateTime64 = FunctionConvert<DataTypeDateTime64, NameToDateTime64, UnknownMonotonicity>;
|
||||
using FunctionToUUID = FunctionConvert<DataTypeUUID, NameToUUID, ToNumberMonotonicity<UInt128>>;
|
||||
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