| 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 | |