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