1#include <DataTypes/DataTypesNumber.h>
2#include <DataTypes/DataTypesDecimal.h>
3#include <Columns/ColumnsNumber.h>
4#include <Columns/ColumnDecimal.h>
5#include "FunctionArrayMapped.h"
6#include <Functions/FunctionFactory.h>
7
8
9namespace DB
10{
11
12namespace ErrorCodes
13{
14 extern const int ILLEGAL_COLUMN;
15}
16
17/** arrayDifference() - returns an array with the difference between all pairs of neighboring elements.
18 */
19struct ArrayDifferenceImpl
20{
21 static bool useDefaultImplementationForConstants() { return true; }
22 static bool needBoolean() { return false; }
23 static bool needExpression() { return false; }
24 static bool needOneArray() { return false; }
25
26 static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & /*array_element*/)
27 {
28 WhichDataType which(expression_return);
29
30 if (which.isUInt8() || which.isInt8())
31 return std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt16>());
32
33 if (which.isUInt16() || which.isInt16())
34 return std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt32>());
35
36 if (which.isUInt32() || which.isUInt64() || which.isInt32() || which.isInt64())
37 return std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt64>());
38
39 if (which.isFloat32() || which.isFloat64())
40 return std::make_shared<DataTypeArray>(std::make_shared<DataTypeFloat64>());
41
42 if (which.isDecimal())
43 return std::make_shared<DataTypeArray>(expression_return);
44
45 throw Exception("arrayDifference cannot process values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
46 }
47
48
49 template <typename Element, typename Result>
50 static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr)
51 {
52 using ColVecType = std::conditional_t<IsDecimalNumber<Element>, ColumnDecimal<Element>, ColumnVector<Element>>;
53 using ColVecResult = std::conditional_t<IsDecimalNumber<Result>, ColumnDecimal<Result>, ColumnVector<Result>>;
54
55 const ColVecType * column = checkAndGetColumn<ColVecType>(&*mapped);
56
57 if (!column)
58 return false;
59
60 const IColumn::Offsets & offsets = array.getOffsets();
61 const typename ColVecType::Container & data = column->getData();
62
63 typename ColVecResult::MutablePtr res_nested;
64 if constexpr (IsDecimalNumber<Element>)
65 res_nested = ColVecResult::create(0, data.getScale());
66 else
67 res_nested = ColVecResult::create();
68
69 typename ColVecResult::Container & res_values = res_nested->getData();
70 res_values.resize(data.size());
71
72 size_t pos = 0;
73 for (size_t i = 0; i < offsets.size(); ++i)
74 {
75 // skip empty arrays
76 if (pos < offsets[i])
77 {
78 res_values[pos] = 0;
79 for (++pos; pos < offsets[i]; ++pos)
80 {
81 res_values[pos] = static_cast<Result>(data[pos]) - static_cast<Result>(data[pos - 1]);
82 }
83 }
84 }
85 res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr());
86 return true;
87
88 }
89
90 static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
91 {
92 ColumnPtr res;
93
94 if (executeType< UInt8 , Int16>(mapped, array, res) ||
95 executeType< UInt16, Int32>(mapped, array, res) ||
96 executeType< UInt32, Int64>(mapped, array, res) ||
97 executeType< UInt64, Int64>(mapped, array, res) ||
98 executeType< Int8 , Int16>(mapped, array, res) ||
99 executeType< Int16, Int32>(mapped, array, res) ||
100 executeType< Int32, Int64>(mapped, array, res) ||
101 executeType< Int64, Int64>(mapped, array, res) ||
102 executeType<Float32,Float64>(mapped, array, res) ||
103 executeType<Float64,Float64>(mapped, array, res) ||
104 executeType<Decimal32, Decimal32>(mapped, array, res) ||
105 executeType<Decimal64, Decimal64>(mapped, array, res) ||
106 executeType<Decimal128, Decimal128>(mapped, array, res))
107 return res;
108 else
109 throw Exception("Unexpected column for arrayDifference: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN);
110 }
111
112};
113
114struct NameArrayDifference { static constexpr auto name = "arrayDifference"; };
115using FunctionArrayDifference = FunctionArrayMapped<ArrayDifferenceImpl, NameArrayDifference>;
116
117void registerFunctionArrayDifference(FunctionFactory & factory)
118{
119 factory.registerFunction<FunctionArrayDifference>();
120}
121
122}
123
124