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