This commit is contained in:
Robert Schulze 2023-10-24 15:14:20 +00:00
parent 2346f30095
commit f94c33586c
No known key found for this signature in database
GPG Key ID: 26703B55FB13728A
6 changed files with 97 additions and 49 deletions

View File

@ -1987,7 +1987,7 @@ Extracts time from [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID) as
**Syntax**
``` sql
snowflakeToDateTime(value [, time_zone])
snowflakeToDateTime(value[, time_zone])
```
**Parameters**
@ -2023,7 +2023,7 @@ Extracts time from [Snowflake ID](https://en.wikipedia.org/wiki/Snowflake_ID) as
**Syntax**
``` sql
snowflakeToDateTime64(value [, time_zone])
snowflakeToDateTime64(value[, time_zone])
```
**Parameters**
@ -2033,7 +2033,7 @@ snowflakeToDateTime64(value [, time_zone])
**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**

View File

@ -452,10 +452,23 @@ inline bool isObject(const T & data_type) { return WhichDataType(data_type).isOb
template <typename T>
inline bool isUInt8(const T & data_type) { return WhichDataType(data_type).isUInt8(); }
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(); }
template <typename T>
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>
inline bool isInteger(const T & data_type)
{

View File

@ -4,10 +4,12 @@
#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>
#include <DataTypes/DataTypeDateTime64.h>
#include <DataTypes/DataTypesDecimal.h>
#include <DataTypes/DataTypesNumber.h>
#include <Columns/ColumnConst.h>
#include <Columns/ColumnsDateTime.h>
#include <Columns/ColumnsNumber.h>
#include <Core/DecimalFunctions.h>
#include <Interpreters/Context.h>
#include <base/arithmeticOverflow.h>
@ -40,14 +42,15 @@ public:
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
bool isVariadic() const override { return false; }
bool useDefaultImplementationForConstants() const override { return true; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
if (!isDateTime(arguments[0].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The only argument for function {} must be DateTime", name);
FunctionArgumentDescriptors args{
{"value", &isDateTime<IDataType>, nullptr, "DateTime"}
};
validateFunctionArgumentTypes(*this, arguments, args);
return std::make_shared<DataTypeInt64>();
}
@ -88,13 +91,15 @@ public:
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
if (arguments.empty() || arguments.size() > 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {} takes one or two arguments", name);
FunctionArgumentDescriptors mandatory_args{
{"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()))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The first argument for function {} must be Int64", name);
std::string timezone;
String timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);
@ -141,14 +146,15 @@ public:
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
bool isVariadic() const override { return false; }
bool useDefaultImplementationForConstants() const override { return true; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
if (!isDateTime64(arguments[0].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The only argument for function {} must be DateTime64", name);
FunctionArgumentDescriptors args{
{"value", &isDateTime64<IDataType>, nullptr, "DateTime64"}
};
validateFunctionArgumentTypes(*this, arguments, args);
return std::make_shared<DataTypeInt64>();
}
@ -156,14 +162,21 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
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_data = res_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)
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;
}
@ -190,13 +203,15 @@ public:
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
if (arguments.empty() || arguments.size() > 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {} takes one or two arguments", name);
FunctionArgumentDescriptors mandatory_args{
{"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()))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The first argument for function {} must be Int64", name);
std::string timezone;
String timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0, allow_nonconst_timezone_arguments);

View File

@ -1,6 +1,6 @@
const column
2021-08-15 18:57:56 1426860702823350272
2021-08-15 18:57:56.492 1426860704886947840
non-const column
2021-08-15 18:57:56 1426860702823350272
2021-08-15 18:57:56.492 1426860704886947840
-- const / non-const inputs
2021-08-15 18:57:56 1426860702823350272 1426860702823350272
2021-08-15 18:57:56.492 1426860704886947840 1426860704886947840
-- different DateTime64 scales
1426981498778550272 1426981500456271872 1426981500833759232 1426981500842147840 1426981500842147840
1 1 1 1 0

View File

@ -1,23 +1,43 @@
-- Error cases
SELECT dateTimeToSnowflake(); -- {serverError 42}
SELECT dateTime64ToSnowflake(); -- {serverError 42}
SELECT dateTimeToSnowflake(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
SELECT dateTime64ToSnowflake(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
SELECT dateTimeToSnowflake('abc'); -- {serverError 43}
SELECT dateTime64ToSnowflake('abc'); -- {serverError 43}
SELECT dateTimeToSnowflake('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT dateTime64ToSnowflake('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT dateTimeToSnowflake('abc', 123); -- {serverError 42}
SELECT dateTime64ToSnowflake('abc', 123); -- {serverError 42}
SELECT dateTimeToSnowflake('abc', 123); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
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
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
SELECT dt64, dateTime64ToSnowflake(dt64);
SELECT dt64, dateTime64ToSnowflake(dt64), materialize(dateTime64ToSnowflake(dt64));
SELECT 'non-const column';
WITH toDateTime('2021-08-15 18:57:56', 'Asia/Shanghai') AS x
SELECT materialize(x) as dt, dateTimeToSnowflake(dt);;
SELECT '-- different DateTime64 scales';
WITH toDateTime64('2021-08-15 18:57:56.492', 3, 'Asia/Shanghai') AS x
SELECT materialize(x) as dt64, dateTime64ToSnowflake(dt64);
WITH toDateTime64('2021-08-15 18:57:56.492', 0, 'UTC') AS dt64_0,
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;

View File

@ -1,12 +1,12 @@
-- -- Error cases
SELECT snowflakeToDateTime(); -- {serverError 42}
SELECT snowflakeToDateTime64(); -- {serverError 42}
SELECT snowflakeToDateTime(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
SELECT snowflakeToDateTime64(); -- {serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH}
SELECT snowflakeToDateTime('abc'); -- {serverError 43}
SELECT snowflakeToDateTime64('abc'); -- {serverError 43}
SELECT snowflakeToDateTime('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT snowflakeToDateTime64('abc'); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT snowflakeToDateTime('abc', 123); -- {serverError 43}
SELECT snowflakeToDateTime64('abc', 123); -- {serverError 43}
SELECT snowflakeToDateTime('abc', 123); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT snowflakeToDateTime64('abc', 123); -- {serverError ILLEGAL_TYPE_OF_ARGUMENT}
SELECT 'const column';
WITH