#include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ARGUMENT_OUT_OF_BOUND; } namespace { struct DateTraits { static constexpr auto name = "fromDaysSinceYearZero"; using ReturnDataType = DataTypeDate; }; struct DateTraits32 { static constexpr auto name = "fromDaysSinceYearZero32"; using ReturnDataType = DataTypeDate32; }; template class FunctionFromDaysSinceYearZero : public IFunction { public: static constexpr auto name = Traits::name; using RawReturnType = typename Traits::ReturnDataType::FieldType; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } bool useDefaultImplementationForConstants() const override { return true; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { FunctionArgumentDescriptors args{{"days", &isNativeInteger, nullptr, "Integer"}}; validateFunctionArgumentTypes(*this, arguments, args); return std::make_shared(); } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { auto res_column = Traits::ReturnDataType::ColumnType::create(input_rows_count); const auto & src_column = arguments[0]; auto try_type = [&](T) { using ColVecType = ColumnVector; if (const ColVecType * col_vec = checkAndGetColumn(src_column.column.get())) { execute(*col_vec, *res_column, input_rows_count); return true; } return false; }; const bool success = try_type(UInt8{}) || try_type(UInt16{}) || try_type(UInt32{}) || try_type(UInt64{}) || try_type(Int8{}) || try_type(Int16{}) || try_type(Int32{}) || try_type(Int64{}); if (!success) throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal column while execute function {}", getName()); return res_column; } template void execute(const ColVecType & col, ResCol & result_column, size_t rows_count) const { const auto & src_data = col.getData(); auto & dst_data = result_column.getData(); dst_data.resize(rows_count); for (size_t i = 0; i < rows_count; ++i) { auto value = src_data[i]; if (value < 0) throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "Expected a non-negative integer, got: {}", std::to_string(value)); /// prevent potential signed integer overflows (aka. undefined behavior) with Date32 results auto value_uint64 = static_cast(value); /// NOLINT(bugprone-signed-char-misuse,cert-str34-c) dst_data[i] = static_cast(value_uint64 - ToDaysSinceYearZeroImpl::DAYS_BETWEEN_YEARS_0_AND_1970); } } }; } REGISTER_FUNCTION(FromDaysSinceYearZero) { factory.registerFunction>(FunctionDocumentation{ .description = R"( Given the number of days passed since 1 January 0000 in the proleptic Gregorian calendar defined by ISO 8601 return a corresponding date. The calculation is the same as in MySQL's FROM_DAYS() function. )", .examples{{"typical", "SELECT fromDaysSinceYearZero(713569)", "2023-09-08"}}, .categories{"Dates and Times"}}); factory.registerFunction>(FunctionDocumentation{ .description = R"( Given the number of days passed since 1 January 0000 in the proleptic Gregorian calendar defined by ISO 8601 return a corresponding date. The calculation is the same as in MySQL's FROM_DAYS() function. )", .examples{{"typical", "SELECT fromDaysSinceYearZero32(713569)", "2023-09-08"}}, .categories{"Dates and Times"}}); factory.registerAlias("FROM_DAYS", FunctionFromDaysSinceYearZero::name, FunctionFactory::CaseInsensitive); } }