#include #include #include #include #include "FunctionArrayMapped.h" #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_COLUMN; } /** arrayCumSumNonNegative() - returns an array with cumulative sums of the original. (If value < 0 -> 0). */ struct ArrayCumSumNonNegativeImpl { static bool useDefaultImplementationForConstants() { return true; } static bool needBoolean() { return false; } static bool needExpression() { return false; } static bool needOneArray() { return false; } static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & /*array_element*/) { WhichDataType which(expression_return); if (which.isNativeUInt()) return std::make_shared(std::make_shared()); if (which.isNativeInt()) return std::make_shared(std::make_shared()); if (which.isFloat()) return std::make_shared(std::make_shared()); if (which.isDecimal()) { UInt32 scale = getDecimalScale(*expression_return); DataTypePtr nested = std::make_shared>(DecimalUtils::max_precision, scale); return std::make_shared(nested); } throw Exception("arrayCumSumNonNegativeImpl cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } template static void NO_SANITIZE_UNDEFINED implVector( size_t size, const IColumn::Offset * __restrict offsets, Dst * __restrict res_values, const Src * __restrict src_values) { size_t pos = 0; for (const auto * end = offsets + size; offsets < end; ++offsets) { auto offset = *offsets; Dst accumulated{}; for (; pos < offset; ++pos) { accumulated += src_values[pos]; if (accumulated < Dst{}) accumulated = {}; res_values[pos] = accumulated; } } } template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { using ColVecType = std::conditional_t, ColumnDecimal, ColumnVector>; using ColVecResult = std::conditional_t, ColumnDecimal, ColumnVector>; const ColVecType * column = checkAndGetColumn(&*mapped); if (!column) return false; const IColumn::Offsets & offsets = array.getOffsets(); const typename ColVecType::Container & data = column->getData(); typename ColVecResult::MutablePtr res_nested; if constexpr (IsDecimalNumber) res_nested = ColVecResult::create(0, data.getScale()); else res_nested = ColVecResult::create(); typename ColVecResult::Container & res_values = res_nested->getData(); res_values.resize(data.size()); implVector(offsets.size(), offsets.data(), res_values.data(), data.data()); res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr()); return true; } static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped) { ColumnPtr res; if (executeType< UInt8 , UInt64>(mapped, array, res) || executeType< UInt16, UInt64>(mapped, array, res) || executeType< UInt32, UInt64>(mapped, array, res) || executeType< UInt64, UInt64>(mapped, array, res) || executeType< Int8 , Int64>(mapped, array, res) || executeType< Int16, Int64>(mapped, array, res) || executeType< Int32, Int64>(mapped, array, res) || executeType< Int64, Int64>(mapped, array, res) || executeType(mapped, array, res) || executeType(mapped, array, res) || executeType(mapped, array, res) || executeType(mapped, array, res) || executeType(mapped, array, res)) return res; else throw Exception("Unexpected column for arrayCumSumNonNegativeImpl: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); } }; struct NameArrayCumSumNonNegative { static constexpr auto name = "arrayCumSumNonNegative"; }; using FunctionArrayCumSumNonNegative = FunctionArrayMapped; void registerFunctionArrayCumSumNonNegative(FunctionFactory & factory) { factory.registerFunction(); } }