#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int CANNOT_FORMAT_DATETIME; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } template class ExecutableFunctionFromModifiedJulianDay : public IExecutableFunction { public: String getName() const override { return Name::name; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { using ColVecType = typename FromDataType::ColumnType; const ColVecType * col_from = checkAndGetColumn(arguments[0].column.get()); const typename ColVecType::Container & vec_from = col_from->getData(); auto col_to = ColumnString::create(); ColumnString::Chars & data_to = col_to->getChars(); ColumnString::Offsets & offsets_to = col_to->getOffsets(); data_to.resize(input_rows_count * strlen("YYYY-MM-DD") + 1); offsets_to.resize(input_rows_count); ColumnUInt8::MutablePtr col_null_map_to; ColumnUInt8::Container * vec_null_map_to [[maybe_unused]] = nullptr; if constexpr (nullOnErrors) { col_null_map_to = ColumnUInt8::create(input_rows_count); vec_null_map_to = &col_null_map_to->getData(); } WriteBufferFromVector write_buffer(data_to); for (size_t i = 0; i < input_rows_count; ++i) { if constexpr (nullOnErrors) { try { const GregorianDate<> gd(vec_from[i]); gd.write(write_buffer); (*vec_null_map_to)[i] = false; } catch (const Exception & e) { if (e.code() == ErrorCodes::CANNOT_FORMAT_DATETIME) (*vec_null_map_to)[i] = true; else throw; } writeChar(0, write_buffer); offsets_to[i] = write_buffer.count(); } else { const GregorianDate<> gd(vec_from[i]); gd.write(write_buffer); writeChar(0, write_buffer); offsets_to[i] = write_buffer.count(); } } write_buffer.finalize(); if constexpr (nullOnErrors) return ColumnNullable::create(std::move(col_to), std::move(col_null_map_to)); else return col_to; } bool useDefaultImplementationForConstants() const override { return true; } }; template class FunctionBaseFromModifiedJulianDay : public IFunctionBase { public: explicit FunctionBaseFromModifiedJulianDay(DataTypes argument_types_, DataTypePtr return_type_) : argument_types(std::move(argument_types_)) , return_type(std::move(return_type_)) {} String getName() const override { return Name::name; } const DataTypes & getArgumentTypes() const override { return argument_types; } const DataTypePtr & getResultType() const override { return return_type; } ExecutableFunctionPtr prepare(const ColumnsWithTypeAndName &) const override { return std::make_unique>(); } bool isInjective(const ColumnsWithTypeAndName &) const override { return true; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } bool hasInformationAboutMonotonicity() const override { return true; } Monotonicity getMonotonicityForRange(const IDataType &, const Field &, const Field &) const override { return { .is_monotonic = true, .is_always_monotonic = true, .is_strict = true, }; } private: DataTypes argument_types; DataTypePtr return_type; }; template class FromModifiedJulianDayOverloadResolver : public IFunctionOverloadResolver { public: static constexpr auto name = Name::name; static FunctionOverloadResolverPtr create(ContextPtr) { return std::make_unique>(); } String getName() const override { return Name::name; } FunctionBasePtr buildImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override { DataTypes argument_types = { arguments[0].type }; const DataTypePtr & from_type_not_null = removeNullable(arguments[0].type); FunctionBasePtr base; auto call = [&](const auto & types) -> bool { using Types = std::decay_t; using FromIntType = typename Types::RightType; using FromDataType = DataTypeNumber; base = std::make_unique>(argument_types, return_type); return true; }; bool built = callOnBasicType(from_type_not_null->getTypeId(), call); if (built) return base; /* When the argument is a NULL constant, the resulting * function base will not be actually called but it * will still be inspected. Returning a NULL pointer * here causes a SEGV. So we must somehow create a * dummy implementation and return it. */ if (WhichDataType(from_type_not_null).isNothing()) // Nullable(Nothing) return std::make_unique>(argument_types, return_type); else // Should not happen. throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The argument of function {} must be integral", getName()); } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!isInteger(arguments[0])) { throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "The argument of function {} must be integral", getName()); } DataTypePtr base_type = std::make_shared(); if constexpr (nullOnErrors) return std::make_shared(base_type); else return base_type; } size_t getNumberOfArguments() const override { return 1; } bool isInjective(const ColumnsWithTypeAndName &) const override { return true; } }; struct NameFromModifiedJulianDay { static constexpr auto name = "fromModifiedJulianDay"; }; struct NameFromModifiedJulianDayOrNull { static constexpr auto name = "fromModifiedJulianDayOrNull"; }; REGISTER_FUNCTION(FromModifiedJulianDay) { factory.registerFunction>(); factory.registerFunction>(); } }