| 1 | #include <DataTypes/DataTypeDateTime64.h> | 
|---|
| 2 |  | 
|---|
| 3 | #include <Core/DecimalFunctions.h> | 
|---|
| 4 | #include <Functions/IFunction.h> | 
|---|
| 5 | #include <Functions/FunctionFactory.h> | 
|---|
| 6 |  | 
|---|
| 7 | #include <Common/assert_cast.h> | 
|---|
| 8 |  | 
|---|
| 9 | #include <time.h> | 
|---|
| 10 |  | 
|---|
| 11 |  | 
|---|
| 12 | namespace DB | 
|---|
| 13 | { | 
|---|
| 14 |  | 
|---|
| 15 | namespace ErrorCodes | 
|---|
| 16 | { | 
|---|
| 17 | extern const int ILLEGAL_COLUMN; | 
|---|
| 18 | extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; | 
|---|
| 19 | extern const int CANNOT_CLOCK_GETTIME; | 
|---|
| 20 | } | 
|---|
| 21 |  | 
|---|
| 22 | static Field nowSubsecond(UInt32 scale) | 
|---|
| 23 | { | 
|---|
| 24 | static constexpr Int32 fractional_scale = 9; | 
|---|
| 25 |  | 
|---|
| 26 | timespec spec{}; | 
|---|
| 27 | if (clock_gettime(CLOCK_REALTIME, &spec)) | 
|---|
| 28 | throwFromErrno( "Cannot clock_gettime.", ErrorCodes::CANNOT_CLOCK_GETTIME); | 
|---|
| 29 |  | 
|---|
| 30 | DecimalUtils::DecimalComponents<DateTime64::NativeType> components{spec.tv_sec, spec.tv_nsec}; | 
|---|
| 31 |  | 
|---|
| 32 | // clock_gettime produces subsecond part in nanoseconds, but decimalFromComponents fractional is scale-dependent. | 
|---|
| 33 | // Andjust fractional to scale, e.g. for 123456789 nanoseconds: | 
|---|
| 34 | //   if scale is  6 (miscoseconds) => divide by 9 - 6 = 3 to get 123456 microseconds | 
|---|
| 35 | //   if scale is 12 (picoseconds)  => multiply by abs(9 - 12) = 3 to get 123456789000 picoseconds | 
|---|
| 36 | const auto adjust_scale = fractional_scale - static_cast<Int32>(scale); | 
|---|
| 37 | if (adjust_scale < 0) | 
|---|
| 38 | components.fractional *= intExp10(std::abs(adjust_scale)); | 
|---|
| 39 | else if (adjust_scale > 0) | 
|---|
| 40 | components.fractional /= intExp10(adjust_scale); | 
|---|
| 41 |  | 
|---|
| 42 | return DecimalField(DecimalUtils::decimalFromComponents<DateTime64>(components, scale), | 
|---|
| 43 | scale); | 
|---|
| 44 | } | 
|---|
| 45 |  | 
|---|
| 46 | class FunctionNow64 : public IFunction | 
|---|
| 47 | { | 
|---|
| 48 | public: | 
|---|
| 49 | static constexpr auto name = "now64"; | 
|---|
| 50 | static FunctionPtr create(const Context &) { return std::make_shared<FunctionNow64>(); } | 
|---|
| 51 |  | 
|---|
| 52 | String getName() const override | 
|---|
| 53 | { | 
|---|
| 54 | return name; | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | bool isVariadic() const override { return true; } | 
|---|
| 58 | size_t getNumberOfArguments() const override { return 0; } | 
|---|
| 59 | ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return ColumnNumbers{0}; } | 
|---|
| 60 | bool isDeterministic() const override { return false; } | 
|---|
| 61 |  | 
|---|
| 62 | // Return type depends on argument value. | 
|---|
| 63 | DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override | 
|---|
| 64 | { | 
|---|
| 65 | UInt32 scale = DataTypeDateTime64::default_scale; | 
|---|
| 66 |  | 
|---|
| 67 | // Type check is similar to the validateArgumentType, trying to keep error codes and messages as close to the said function as possible. | 
|---|
| 68 | if (arguments.size() >= 1) | 
|---|
| 69 | { | 
|---|
| 70 | const auto & argument = arguments[0]; | 
|---|
| 71 | if (!isInteger(argument.type) || !argument.column || !isColumnConst(*argument.column)) | 
|---|
| 72 | throw Exception( "Illegal type "+ argument.type->getName() + | 
|---|
| 73 | " of 0"+ | 
|---|
| 74 | " argument of function "+ getName() + | 
|---|
| 75 | ". Expected const integer.", | 
|---|
| 76 | ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); | 
|---|
| 77 |  | 
|---|
| 78 | scale = argument.column->get64(0); | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | return std::make_shared<DataTypeDateTime64>(scale); | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | void executeImpl(Block & block, const ColumnNumbers & /*arguments*/, size_t result, size_t input_rows_count) override | 
|---|
| 85 | { | 
|---|
| 86 | auto & result_col = block.getByPosition(result); | 
|---|
| 87 | const UInt32 scale = assert_cast<const DataTypeDateTime64 *>(result_col.type.get())->getScale(); | 
|---|
| 88 |  | 
|---|
| 89 | result_col.column = result_col.type->createColumnConst(input_rows_count, nowSubsecond(scale)); | 
|---|
| 90 | } | 
|---|
| 91 | }; | 
|---|
| 92 |  | 
|---|
| 93 | void registerFunctionNow64(FunctionFactory & factory) | 
|---|
| 94 | { | 
|---|
| 95 | factory.registerFunction<FunctionNow64>(FunctionFactory::CaseInsensitive); | 
|---|
| 96 | } | 
|---|
| 97 |  | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|