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
12namespace DB
13{
14
15namespace 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
22static 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
46class FunctionNow64 : public IFunction
47{
48public:
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
93void registerFunctionNow64(FunctionFactory & factory)
94{
95 factory.registerFunction<FunctionNow64>(FunctionFactory::CaseInsensitive);
96}
97
98}
99