mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
Fix issue #42966
This commit is contained in:
parent
2346f30095
commit
f94c33586c
@ -1987,7 +1987,7 @@ Extracts time from [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID) as
|
|||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
snowflakeToDateTime(value [, time_zone])
|
snowflakeToDateTime(value[, time_zone])
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@ -2023,7 +2023,7 @@ Extracts time from [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID) as
|
|||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
snowflakeToDateTime64(value [, time_zone])
|
snowflakeToDateTime64(value[, time_zone])
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
@ -2033,7 +2033,7 @@ snowflakeToDateTime64(value [, time_zone])
|
|||||||
|
|
||||||
**Returned value**
|
**Returned value**
|
||||||
|
|
||||||
- Input value converted to the [DateTime64](/docs/en/sql-reference/data-types/datetime64.md) data type.
|
- Input value converted to the [DateTime64](/docs/en/sql-reference/data-types/datetime64.md) data type with millisecond precision (scale = 3).
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
|
@ -452,10 +452,23 @@ inline bool isObject(const T & data_type) { return WhichDataType(data_type).isOb
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool isUInt8(const T & data_type) { return WhichDataType(data_type).isUInt8(); }
|
inline bool isUInt8(const T & data_type) { return WhichDataType(data_type).isUInt8(); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
inline bool isUInt16(const T & data_type) { return WhichDataType(data_type).isUInt16(); }
|
||||||
|
template <typename T>
|
||||||
|
inline bool isUInt32(const T & data_type) { return WhichDataType(data_type).isUInt32(); }
|
||||||
|
template <typename T>
|
||||||
inline bool isUInt64(const T & data_type) { return WhichDataType(data_type).isUInt64(); }
|
inline bool isUInt64(const T & data_type) { return WhichDataType(data_type).isUInt64(); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool isUnsignedInteger(const T & data_type) { return WhichDataType(data_type).isUInt(); }
|
inline bool isUnsignedInteger(const T & data_type) { return WhichDataType(data_type).isUInt(); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool isInt8(const T & data_type) { return WhichDataType(data_type).isInt8(); }
|
||||||
|
template <typename T>
|
||||||
|
inline bool isInt16(const T & data_type) { return WhichDataType(data_type).isInt16(); }
|
||||||
|
template <typename T>
|
||||||
|
inline bool isInt32(const T & data_type) { return WhichDataType(data_type).isInt32(); }
|
||||||
|
template <typename T>
|
||||||
|
inline bool isInt64(const T & data_type) { return WhichDataType(data_type).isInt64(); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool isInteger(const T & data_type)
|
inline bool isInteger(const T & data_type)
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
#include <Functions/IFunction.h>
|
#include <Functions/IFunction.h>
|
||||||
#include <Functions/FunctionHelpers.h>
|
#include <Functions/FunctionHelpers.h>
|
||||||
#include <DataTypes/DataTypeDateTime64.h>
|
#include <DataTypes/DataTypeDateTime64.h>
|
||||||
|
#include <DataTypes/DataTypesDecimal.h>
|
||||||
#include <DataTypes/DataTypesNumber.h>
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
#include <Columns/ColumnConst.h>
|
#include <Columns/ColumnConst.h>
|
||||||
#include <Columns/ColumnsDateTime.h>
|
#include <Columns/ColumnsDateTime.h>
|
||||||
#include <Columns/ColumnsNumber.h>
|
#include <Columns/ColumnsNumber.h>
|
||||||
|
#include <Core/DecimalFunctions.h>
|
||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
|
|
||||||
#include <base/arithmeticOverflow.h>
|
#include <base/arithmeticOverflow.h>
|
||||||
@ -40,14 +42,15 @@ public:
|
|||||||
|
|
||||||
String getName() const override { return name; }
|
String getName() const override { return name; }
|
||||||
size_t getNumberOfArguments() const override { return 1; }
|
size_t getNumberOfArguments() const override { return 1; }
|
||||||
bool isVariadic() const override { return false; }
|
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
if (!isDateTime(arguments[0].type))
|
FunctionArgumentDescriptors args{
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The only argument for function {} must be DateTime", name);
|
{"value", &isDateTime<IDataType>, nullptr, "DateTime"}
|
||||||
|
};
|
||||||
|
validateFunctionArgumentTypes(*this, arguments, args);
|
||||||
|
|
||||||
return std::make_shared<DataTypeInt64>();
|
return std::make_shared<DataTypeInt64>();
|
||||||
}
|
}
|
||||||
@ -88,13 +91,15 @@ public:
|
|||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
if (arguments.empty() || arguments.size() > 2)
|
FunctionArgumentDescriptors mandatory_args{
|
||||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {} takes one or two arguments", name);
|
{"value", &isInt64<IDataType>, nullptr, "Int64"}
|
||||||
|
};
|
||||||
|
FunctionArgumentDescriptors optional_args{
|
||||||
|
{"time_zone", &isString<IDataType>, nullptr, "String"}
|
||||||
|
};
|
||||||
|
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||||
|
|
||||||
if (!typeid_cast<const DataTypeInt64 *>(arguments[0].type.get()))
|
String timezone;
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The first argument for function {} must be Int64", name);
|
|
||||||
|
|
||||||
std::string timezone;
|
|
||||||
if (arguments.size() == 2)
|
if (arguments.size() == 2)
|
||||||
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
|
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
|
||||||
|
|
||||||
@ -141,14 +146,15 @@ public:
|
|||||||
|
|
||||||
String getName() const override { return name; }
|
String getName() const override { return name; }
|
||||||
size_t getNumberOfArguments() const override { return 1; }
|
size_t getNumberOfArguments() const override { return 1; }
|
||||||
bool isVariadic() const override { return false; }
|
|
||||||
bool useDefaultImplementationForConstants() const override { return true; }
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
if (!isDateTime64(arguments[0].type))
|
FunctionArgumentDescriptors args{
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The only argument for function {} must be DateTime64", name);
|
{"value", &isDateTime64<IDataType>, nullptr, "DateTime64"}
|
||||||
|
};
|
||||||
|
validateFunctionArgumentTypes(*this, arguments, args);
|
||||||
|
|
||||||
return std::make_shared<DataTypeInt64>();
|
return std::make_shared<DataTypeInt64>();
|
||||||
}
|
}
|
||||||
@ -156,14 +162,21 @@ public:
|
|||||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
|
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
|
||||||
{
|
{
|
||||||
const auto & src = arguments[0];
|
const auto & src = arguments[0];
|
||||||
const auto & src_column = *src.column;
|
|
||||||
|
|
||||||
|
const auto & src_column = *src.column;
|
||||||
auto res_column = ColumnInt64::create(input_rows_count);
|
auto res_column = ColumnInt64::create(input_rows_count);
|
||||||
auto & res_data = res_column->getData();
|
auto & res_data = res_column->getData();
|
||||||
|
|
||||||
const auto & src_data = typeid_cast<const ColumnDecimal<DateTime64> &>(src_column).getData();
|
const auto & src_data = typeid_cast<const ColumnDecimal<DateTime64> &>(src_column).getData();
|
||||||
|
|
||||||
|
/// timestamps in snowflake-ids are millisecond-based, convert input to milliseconds
|
||||||
|
UInt32 src_scale = getDecimalScale(*arguments[0].type);
|
||||||
|
Int64 multiplier_msec = DecimalUtils::scaleMultiplier<DateTime64>(3);
|
||||||
|
Int64 multiplier_src = DecimalUtils::scaleMultiplier<DateTime64>(src_scale);
|
||||||
|
auto factor = multiplier_msec / static_cast<double>(multiplier_src);
|
||||||
|
|
||||||
for (size_t i = 0; i < input_rows_count; ++i)
|
for (size_t i = 0; i < input_rows_count; ++i)
|
||||||
res_data[i] = (src_data[i] - snowflake_epoch) << time_shift;
|
res_data[i] = static_cast<Int64>(src_data[i] * factor - snowflake_epoch) << time_shift;
|
||||||
|
|
||||||
return res_column;
|
return res_column;
|
||||||
}
|
}
|
||||||
@ -190,13 +203,15 @@ public:
|
|||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
if (arguments.empty() || arguments.size() > 2)
|
FunctionArgumentDescriptors mandatory_args{
|
||||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {} takes one or two arguments", name);
|
{"value", &isInt64<IDataType>, nullptr, "Int64"}
|
||||||
|
};
|
||||||
|
FunctionArgumentDescriptors optional_args{
|
||||||
|
{"time_zone", &isString<IDataType>, nullptr, "String"}
|
||||||
|
};
|
||||||
|
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||||
|
|
||||||
if (!typeid_cast<const DataTypeInt64 *>(arguments[0].type.get()))
|
String timezone;
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The first argument for function {} must be Int64", name);
|
|
||||||
|
|
||||||
std::string timezone;
|
|
||||||
if (arguments.size() == 2)
|
if (arguments.size() == 2)
|
||||||
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
|
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const column
|
-- const / non-const inputs
|
||||||
2021-08-15 18:57:56 1426860702823350272
|
2021-08-15 18:57:56 1426860702823350272 1426860702823350272
|
||||||
2021-08-15 18:57:56.492 1426860704886947840
|
2021-08-15 18:57:56.492 1426860704886947840 1426860704886947840
|
||||||
non-const column
|
-- different DateTime64 scales
|
||||||
2021-08-15 18:57:56 1426860702823350272
|
1426981498778550272 1426981500456271872 1426981500833759232 1426981500842147840 1426981500842147840
|
||||||
2021-08-15 18:57:56.492 1426860704886947840
|
1 1 1 1 0
|
||||||
|
@ -1,23 +1,43 @@
|
|||||||
-- Error cases
|
-- Error cases
|
||||||
SELECT dateTimeToSnowflake(); -- {serverError 42}
|
SELECT dateTimeToSnowflake(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
SELECT dateTime64ToSnowflake(); -- {serverError 42}
|
SELECT dateTime64ToSnowflake(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
|
|
||||||
SELECT dateTimeToSnowflake('abc'); -- {serverError 43}
|
SELECT dateTimeToSnowflake('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
SELECT dateTime64ToSnowflake('abc'); -- {serverError 43}
|
SELECT dateTime64ToSnowflake('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
|
|
||||||
SELECT dateTimeToSnowflake('abc', 123); -- {serverError 42}
|
SELECT dateTimeToSnowflake('abc', 123); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
SELECT dateTime64ToSnowflake('abc', 123); -- {serverError 42}
|
SELECT dateTime64ToSnowflake('abc', 123); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
|
|
||||||
|
SELECT '-- const / non-const inputs';
|
||||||
|
|
||||||
SELECT 'const column';
|
|
||||||
WITH toDateTime('2021-08-15 18:57:56', 'Asia/Shanghai') AS dt
|
WITH toDateTime('2021-08-15 18:57:56', 'Asia/Shanghai') AS dt
|
||||||
SELECT dt, dateTimeToSnowflake(dt);
|
SELECT dt, dateTimeToSnowflake(dt), materialize(dateTimeToSnowflake(dt));
|
||||||
|
|
||||||
WITH toDateTime64('2021-08-15 18:57:56.492', 3, 'Asia/Shanghai') AS dt64
|
WITH toDateTime64('2021-08-15 18:57:56.492', 3, 'Asia/Shanghai') AS dt64
|
||||||
SELECT dt64, dateTime64ToSnowflake(dt64);
|
SELECT dt64, dateTime64ToSnowflake(dt64), materialize(dateTime64ToSnowflake(dt64));
|
||||||
|
|
||||||
SELECT 'non-const column';
|
SELECT '-- different DateTime64 scales';
|
||||||
WITH toDateTime('2021-08-15 18:57:56', 'Asia/Shanghai') AS x
|
|
||||||
SELECT materialize(x) as dt, dateTimeToSnowflake(dt);;
|
|
||||||
|
|
||||||
WITH toDateTime64('2021-08-15 18:57:56.492', 3, 'Asia/Shanghai') AS x
|
WITH toDateTime64('2021-08-15 18:57:56.492', 0, 'UTC') AS dt64_0,
|
||||||
SELECT materialize(x) as dt64, dateTime64ToSnowflake(dt64);
|
toDateTime64('2021-08-15 18:57:56.492', 1, 'UTC') AS dt64_1,
|
||||||
|
toDateTime64('2021-08-15 18:57:56.492', 2, 'UTC') AS dt64_2,
|
||||||
|
toDateTime64('2021-08-15 18:57:56.492', 3, 'UTC') AS dt64_3,
|
||||||
|
toDateTime64('2021-08-15 18:57:56.492', 4, 'UTC') AS dt64_4
|
||||||
|
SELECT dateTime64ToSnowflake(dt64_0),
|
||||||
|
dateTime64ToSnowflake(dt64_1),
|
||||||
|
dateTime64ToSnowflake(dt64_2),
|
||||||
|
dateTime64ToSnowflake(dt64_3),
|
||||||
|
dateTime64ToSnowflake(dt64_4);
|
||||||
|
|
||||||
|
-- DateTime64-to-Snowflake-to-DateTime64 is idempotent *if* the scale is <=3 (millisecond
|
||||||
|
-- precision)
|
||||||
|
WITH now64(0) AS dt64_0,
|
||||||
|
now64(1) AS dt64_1,
|
||||||
|
now64(2) AS dt64_2,
|
||||||
|
now64(3) AS dt64_3,
|
||||||
|
now64(4) AS dt64_4
|
||||||
|
SELECT snowflakeToDateTime64(dateTime64ToSnowflake(dt64_0)) == dt64_0,
|
||||||
|
snowflakeToDateTime64(dateTime64ToSnowflake(dt64_1)) == dt64_1,
|
||||||
|
snowflakeToDateTime64(dateTime64ToSnowflake(dt64_2)) == dt64_2,
|
||||||
|
snowflakeToDateTime64(dateTime64ToSnowflake(dt64_3)) == dt64_3,
|
||||||
|
snowflakeToDateTime64(dateTime64ToSnowflake(dt64_4)) == dt64_4;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
-- -- Error cases
|
-- -- Error cases
|
||||||
SELECT snowflakeToDateTime(); -- {serverError 42}
|
SELECT snowflakeToDateTime(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
SELECT snowflakeToDateTime64(); -- {serverError 42}
|
SELECT snowflakeToDateTime64(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
|
||||||
|
|
||||||
SELECT snowflakeToDateTime('abc'); -- {serverError 43}
|
SELECT snowflakeToDateTime('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
SELECT snowflakeToDateTime64('abc'); -- {serverError 43}
|
SELECT snowflakeToDateTime64('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
|
|
||||||
SELECT snowflakeToDateTime('abc', 123); -- {serverError 43}
|
SELECT snowflakeToDateTime('abc', 123); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
SELECT snowflakeToDateTime64('abc', 123); -- {serverError 43}
|
SELECT snowflakeToDateTime64('abc', 123); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
|
||||||
|
|
||||||
SELECT 'const column';
|
SELECT 'const column';
|
||||||
WITH
|
WITH
|
||||||
|
Loading…
Reference in New Issue
Block a user