ClickHouse/src/Functions/array/arrayCumSumNonNegative.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

136 lines
4.9 KiB
C++
Raw Normal View History

#include <Columns/ColumnDecimal.h>
2022-02-17 14:56:29 +00:00
#include <Columns/ColumnsNumber.h>
#include <DataTypes/DataTypesDecimal.h>
#include <DataTypes/DataTypesNumber.h>
#include <Functions/FunctionFactory.h>
2022-02-17 14:56:29 +00:00
#include "FunctionArrayMapped.h"
namespace DB
{
namespace ErrorCodes
{
2020-02-25 18:02:41 +00:00
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
{
2022-02-17 14:56:29 +00:00
using column_type = ColumnArray;
using data_type = DataTypeArray;
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);
2018-09-13 02:55:32 +00:00
if (which.isNativeUInt())
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
if (which.isNativeInt())
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt64>());
if (which.isFloat())
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeFloat64>());
if (which.isDecimal())
{
UInt32 scale = getDecimalScale(*expression_return);
2021-02-20 18:13:36 +00:00
DataTypePtr nested = std::make_shared<DataTypeDecimal<Decimal128>>(DecimalUtils::max_precision<Decimal128>, scale);
return std::make_shared<DataTypeArray>(nested);
}
throw Exception("arrayCumSumNonNegativeImpl cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
2021-02-06 19:22:21 +00:00
template <typename Src, typename Dst>
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];
2021-04-25 09:30:43 +00:00
if (accumulated < Dst{})
accumulated = {};
2021-02-06 19:22:21 +00:00
res_values[pos] = accumulated;
}
}
}
template <typename Element, typename Result>
static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr)
{
2021-09-10 11:49:22 +00:00
using ColVecType = ColumnVectorOrDecimal<Element>;
using ColVecResult = ColumnVectorOrDecimal<Result>;
const ColVecType * column = checkAndGetColumn<ColVecType>(&*mapped);
if (!column)
return false;
const IColumn::Offsets & offsets = array.getOffsets();
const typename ColVecType::Container & data = column->getData();
typename ColVecResult::MutablePtr res_nested;
2021-09-10 11:49:22 +00:00
if constexpr (is_decimal<Element>)
2022-01-27 10:07:53 +00:00
res_nested = ColVecResult::create(0, column->getScale());
else
res_nested = ColVecResult::create();
typename ColVecResult::Container & res_values = res_nested->getData();
res_values.resize(data.size());
2021-02-06 19:22:21 +00:00
implVector(offsets.size(), offsets.data(), res_values.data(), data.data());
res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr());
return true;
}
2020-03-09 03:44:48 +00:00
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
{
ColumnPtr res;
mapped = mapped->convertToFullColumnIfConst();
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<Float32,Float64>(mapped, array, res) ||
executeType<Float64,Float64>(mapped, array, res) ||
executeType<Decimal32, Decimal128>(mapped, array, res) ||
executeType<Decimal64, Decimal128>(mapped, array, res) ||
executeType<Decimal128, Decimal128>(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<ArrayCumSumNonNegativeImpl, NameArrayCumSumNonNegative>;
REGISTER_FUNCTION(ArrayCumSumNonNegative)
{
factory.registerFunction<FunctionArrayCumSumNonNegative>();
}
}