#include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_COLUMN; } /** arrayDifference() - returns an array with the difference between all pairs of neighboring elements. */ struct ArrayDifferenceImpl { 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.isUInt8() || which.isInt8()) return std::make_shared(std::make_shared()); if (which.isUInt16() || which.isInt16()) return std::make_shared(std::make_shared()); if (which.isUInt32() || which.isUInt64() || which.isInt32() || which.isInt64()) return std::make_shared(std::make_shared()); if (which.isFloat32() || which.isFloat64()) return std::make_shared(std::make_shared()); throw Exception("arrayDifference cannot process values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { const ColumnVector * column = checkAndGetColumn>(&*mapped); if (!column) return false; const IColumn::Offsets & offsets = array.getOffsets(); const typename ColumnVector::Container & data = column->getData(); auto res_nested = ColumnVector::create(); typename ColumnVector::Container & res_values = res_nested->getData(); res_values.resize(data.size()); size_t pos = 0; for (size_t i = 0; i < offsets.size(); ++i) { // skip empty arrays if (pos < offsets[i]) { res_values[pos] = 0; for (++pos; pos < offsets[i]; ++pos) { res_values[pos] = static_cast(data[pos]) - static_cast(data[pos - 1]); } } } 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 , Int16>(mapped, array, res) || executeType< UInt16, Int32>(mapped, array, res) || executeType< UInt32, Int64>(mapped, array, res) || executeType< UInt64, Int64>(mapped, array, res) || executeType< Int8 , Int16>(mapped, array, res) || executeType< Int16, Int32>(mapped, array, res) || executeType< Int32, Int64>(mapped, array, res) || executeType< Int64, Int64>(mapped, array, res) || executeType(mapped, array, res) || executeType(mapped, array, res)) return res; else throw Exception("Unexpected column for arrayDifference: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); } }; struct NameArrayDifference { static constexpr auto name = "arrayDifference"; }; using FunctionArrayDifference = FunctionArrayMapped; void registerFunctionArrayDifference(FunctionFactory & factory) { factory.registerFunction(); } }