ClickHouse/src/Functions/FunctionUnixTimestamp64.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

167 lines
6.2 KiB
C++
Raw Normal View History

#pragma once
#include <Functions/extractTimeZoneFromFunctionArguments.h>
2021-05-17 07:30:42 +00:00
#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>
#include <DataTypes/DataTypeDateTime64.h>
#include <DataTypes/DataTypesNumber.h>
#include <Columns/ColumnsNumber.h>
2021-10-02 07:13:14 +00:00
#include <base/arithmeticOverflow.h>
namespace DB
{
namespace ErrorCodes
{
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int DECIMAL_OVERFLOW;
2022-01-10 19:41:05 +00:00
extern const int ILLEGAL_COLUMN;
}
/// Cast DateTime64 to Int64 representation narrowed down (or scaled up) to any scale value defined in Impl.
class FunctionToUnixTimestamp64 : public IFunction
{
private:
size_t target_scale;
const char * name;
public:
FunctionToUnixTimestamp64(size_t target_scale_, const char * name_)
: target_scale(target_scale_), name(name_)
{
}
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 1; }
bool isVariadic() const override { return false; }
2021-06-22 16:21:23 +00:00
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
bool useDefaultImplementationForConstants() 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);
return std::make_shared<DataTypeInt64>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
2020-10-17 21:41:50 +00:00
const auto & src = arguments[0];
const auto & col = *src.column;
2021-05-07 01:45:29 +00:00
auto res_column = ColumnInt64::create(input_rows_count);
auto & result_data = res_column->getData();
2021-05-06 23:17:39 +00:00
const auto & source_data = typeid_cast<const ColumnDecimal<DateTime64> &>(col).getData();
const Int32 scale_diff = static_cast<Int32>(typeid_cast<const DataTypeDateTime64 &>(*src.type).getScale() - target_scale);
if (scale_diff == 0)
{
2021-05-06 23:17:39 +00:00
for (size_t i = 0; i < input_rows_count; ++i)
result_data[i] = source_data[i];
}
else if (scale_diff < 0)
{
const Int64 scale_multiplier = DecimalUtils::scaleMultiplier<Int64>(-scale_diff);
2021-05-06 23:17:39 +00:00
for (size_t i = 0; i < input_rows_count; ++i)
{
2021-05-06 23:17:39 +00:00
Int64 result_value = source_data[i];
if (common::mulOverflow(result_value, scale_multiplier, result_value))
throw Exception("Decimal overflow in " + getName(), ErrorCodes::DECIMAL_OVERFLOW);
2021-05-06 23:17:39 +00:00
result_data[i] = result_value;
}
}
else
{
const Int64 scale_multiplier = DecimalUtils::scaleMultiplier<Int64>(scale_diff);
2021-05-06 23:17:39 +00:00
for (size_t i = 0; i < input_rows_count; ++i)
result_data[i] = Int64(source_data[i]) / scale_multiplier;
}
2020-10-17 21:41:50 +00:00
return res_column;
}
};
class FunctionFromUnixTimestamp64 : public IFunction
{
private:
size_t target_scale;
const char * name;
public:
FunctionFromUnixTimestamp64(size_t target_scale_, const char * name_)
: target_scale(target_scale_), name(name_)
{
}
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 0; }
bool isVariadic() const override { return true; }
2021-06-22 16:21:23 +00:00
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
bool useDefaultImplementationForConstants() const override { return true; }
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
{
if (arguments.size() < 1 || arguments.size() > 2)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function {} takes one or two arguments", name);
if (!isInteger(arguments[0].type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The first argument for function {} must be integer", name);
std::string timezone;
if (arguments.size() == 2)
timezone = extractTimeZoneNameFromFunctionArguments(arguments, 1, 0);
return std::make_shared<DataTypeDateTime64>(target_scale, timezone);
}
2022-01-10 19:41:05 +00:00
template <typename T>
2022-01-26 17:15:34 +00:00
bool executeType(auto & result_column, const ColumnsWithTypeAndName & arguments, size_t input_rows_count) const
{
const auto & src = arguments[0];
const auto & col = *src.column;
2022-01-10 19:41:05 +00:00
if (!checkAndGetColumn<ColumnVector<T>>(col))
2022-01-26 17:15:34 +00:00
return 0;
2022-01-10 19:41:05 +00:00
auto & result_data = result_column->getData();
2022-01-10 19:41:05 +00:00
const auto & source_data = typeid_cast<const ColumnVector<T> &>(col).getData();
2021-05-06 23:17:39 +00:00
for (size_t i = 0; i < input_rows_count; ++i)
result_data[i] = source_data[i];
2022-01-26 17:15:34 +00:00
return 1;
2022-01-10 19:41:05 +00:00
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
auto result_column = ColumnDecimal<DateTime64>::create(input_rows_count, static_cast<UInt32>(target_scale));
2022-01-23 20:06:32 +00:00
2022-01-26 17:15:34 +00:00
if (!((executeType<UInt8>(result_column, arguments, input_rows_count))
|| (executeType<UInt16>(result_column, arguments, input_rows_count))
|| (executeType<UInt32>(result_column, arguments, input_rows_count))
|| (executeType<UInt32>(result_column, arguments, input_rows_count))
|| (executeType<UInt64>(result_column, arguments, input_rows_count))
|| (executeType<Int8>(result_column, arguments, input_rows_count))
|| (executeType<Int16>(result_column, arguments, input_rows_count))
|| (executeType<Int32>(result_column, arguments, input_rows_count))
|| (executeType<Int64>(result_column, arguments, input_rows_count))))
2022-01-10 19:41:05 +00:00
{
throw Exception(ErrorCodes::ILLEGAL_COLUMN,
"Illegal column {} of first argument of function {}",
arguments[0].column->getName(),
getName());
}
return result_column;
}
2022-01-10 19:41:05 +00:00
};
}