#pragma once #include #include #include #include #include #include #include namespace DB { template struct AggregateFunctionSumData { T sum{}; void add(T value) { sum += value; } void merge(const AggregateFunctionSumData & rhs) { sum += rhs.sum; } void write(WriteBuffer & buf) const { writeBinary(sum, buf); } void read(ReadBuffer & buf) { readBinary(sum, buf); } T get() const { return sum; } }; template struct AggregateFunctionSumKahanData { static_assert(std::is_floating_point_v, "It doesn't make sense to use Kahan Summation algorithm for non floating point types"); T sum{}; T compensation{}; void add(T value) { auto compensated_value = value - compensation; auto new_sum = sum + compensated_value; compensation = (new_sum - sum) - compensated_value; sum = new_sum; } void merge(const AggregateFunctionSumKahanData & rhs) { auto raw_sum = sum + rhs.sum; auto rhs_compensated = raw_sum - sum; auto compensations = ((rhs.sum - rhs_compensated) + (sum - (raw_sum - rhs_compensated))) + compensation + rhs.compensation; sum = raw_sum + compensations; compensation = compensations - (sum - raw_sum); } void write(WriteBuffer & buf) const { writeBinary(sum, buf); writeBinary(compensation, buf); } void read(ReadBuffer & buf) { readBinary(sum, buf); readBinary(compensation, buf); } T get() const { return sum; } }; enum AggregateFunctionSumType { AggregateFunctionTypeSum, AggregateFunctionTypeSumWithOverflow, AggregateFunctionTypeSumKahan, }; /// Counts the sum of the numbers. template class AggregateFunctionSum final : public IAggregateFunctionDataHelper> { public: using ResultDataType = std::conditional_t, DataTypeDecimal, DataTypeNumber>; using ColVecType = std::conditional_t, ColumnDecimal, ColumnVector>; using ColVecResult = std::conditional_t, ColumnDecimal, ColumnVector>; String getName() const override { if constexpr (Type == AggregateFunctionTypeSum) return "sum"; else if constexpr (Type == AggregateFunctionTypeSumWithOverflow) return "sumWithOverflow"; else if constexpr (Type == AggregateFunctionTypeSumKahan) return "sumKahan"; __builtin_unreachable(); } AggregateFunctionSum(const DataTypes & argument_types_) : IAggregateFunctionDataHelper>(argument_types_, {}) , scale(0) {} AggregateFunctionSum(const IDataType & data_type, const DataTypes & argument_types_) : IAggregateFunctionDataHelper>(argument_types_, {}) , scale(getDecimalScale(data_type)) {} DataTypePtr getReturnType() const override { if constexpr (IsDecimalNumber) return std::make_shared(ResultDataType::maxPrecision(), scale); else return std::make_shared(); } void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override { const auto & column = static_cast(*columns[0]); this->data(place).add(column.getData()[row_num]); } void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override { this->data(place).merge(this->data(rhs)); } void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override { this->data(place).write(buf); } void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override { this->data(place).read(buf); } void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override { auto & column = static_cast(to); column.getData().push_back(this->data(place).get()); } private: UInt32 scale; }; }