From a8a283ffdcaa30212daa0d266cc2dea572c13971 Mon Sep 17 00:00:00 2001 From: chertus Date: Mon, 11 Nov 2019 23:46:36 +0300 Subject: [PATCH] add missing array functions for Decimals --- dbms/src/Functions/array/arrayCompact.cpp | 22 +++++++--- dbms/src/Functions/array/arrayCumSum.cpp | 41 +++++++++++++++---- .../array/arrayCumSumNonNegative.cpp | 32 ++++++++++++--- dbms/src/Functions/array/arrayDifference.cpp | 26 +++++++++--- dbms/src/Functions/array/arraySum.cpp | 40 ++++++++++++++---- .../00700_decimal_array_functions.reference | 20 +++++++++ .../00700_decimal_array_functions.sql | 20 +++++++++ 7 files changed, 169 insertions(+), 32 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00700_decimal_array_functions.reference create mode 100644 dbms/tests/queries/0_stateless/00700_decimal_array_functions.sql diff --git a/dbms/src/Functions/array/arrayCompact.cpp b/dbms/src/Functions/array/arrayCompact.cpp index b4e11a42f1a..489d18440e0 100644 --- a/dbms/src/Functions/array/arrayCompact.cpp +++ b/dbms/src/Functions/array/arrayCompact.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -27,16 +29,23 @@ struct ArrayCompactImpl template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { - const ColumnVector * src_values_column = checkAndGetColumn>(mapped.get()); + using ColVecType = std::conditional_t, ColumnDecimal, ColumnVector>; + + const ColVecType * src_values_column = checkAndGetColumn(mapped.get()); if (!src_values_column) return false; const IColumn::Offsets & src_offsets = array.getOffsets(); - const typename ColumnVector::Container & src_values = src_values_column->getData(); + const typename ColVecType::Container & src_values = src_values_column->getData(); - auto res_values_column = ColumnVector::create(src_values.size()); - typename ColumnVector::Container & res_values = res_values_column->getData(); + typename ColVecType::MutablePtr res_values_column; + if constexpr (IsDecimalNumber) + res_values_column = ColVecType::create(src_values.size(), src_values.getScale()); + else + res_values_column = ColVecType::create(src_values.size()); + + typename ColVecType::Container & res_values = res_values_column->getData(); size_t src_offsets_size = src_offsets.size(); auto res_offsets_column = ColumnArray::ColumnOffsets::create(src_offsets_size); IColumn::Offsets & res_offsets = res_offsets_column->getData(); @@ -129,7 +138,10 @@ struct ArrayCompactImpl executeType< Int32 >(mapped, array, res) || executeType< Int64 >(mapped, array, res) || executeType(mapped, array, res) || - executeType(mapped, array, res))) + executeType(mapped, array, res)) || + executeType(mapped, array, res) || + executeType(mapped, array, res) || + executeType(mapped, array, res)) { executeGeneric(mapped, array, res); } diff --git a/dbms/src/Functions/array/arrayCumSum.cpp b/dbms/src/Functions/array/arrayCumSum.cpp index 0649558c650..a32d165ee19 100644 --- a/dbms/src/Functions/array/arrayCumSum.cpp +++ b/dbms/src/Functions/array/arrayCumSum.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "FunctionArrayMapped.h" #include @@ -31,6 +33,13 @@ struct ArrayCumSumImpl if (which.isFloat()) return std::make_shared(std::make_shared()); + if (which.isDecimal()) + { + UInt32 scale = getDecimalScale(*expression_return); + DataTypePtr nested = std::make_shared>(maxDecimalPrecision(), scale); + return std::make_shared(nested); + } + throw Exception("arrayCumSum cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } @@ -38,11 +47,15 @@ struct ArrayCumSumImpl template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { - const ColumnVector * column = checkAndGetColumn>(&*mapped); + using ColVecType = std::conditional_t, ColumnDecimal, ColumnVector>; + using ColVecResult = std::conditional_t, ColumnDecimal, ColumnVector>; + + const ColVecType * column = checkAndGetColumn(&*mapped); + const typename ColVecType::Container & data = column->getData(); if (!column) { - const ColumnConst * column_const = checkAndGetColumnConst>(&*mapped); + const ColumnConst * column_const = checkAndGetColumnConst(&*mapped); if (!column_const) return false; @@ -50,8 +63,13 @@ struct ArrayCumSumImpl const Element x = column_const->template getValue(); const IColumn::Offsets & offsets = array.getOffsets(); - auto res_nested = ColumnVector::create(); - typename ColumnVector::Container & res_values = res_nested->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(column_const->size()); size_t pos = 0; @@ -73,10 +91,14 @@ struct ArrayCumSumImpl } 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(); + 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()); size_t pos = 0; @@ -110,7 +132,10 @@ struct ArrayCumSumImpl 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) || + executeType(mapped, array, res)) return res; else throw Exception("Unexpected column for arrayCumSum: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Functions/array/arrayCumSumNonNegative.cpp b/dbms/src/Functions/array/arrayCumSumNonNegative.cpp index d27310a6b6a..4ccafaadf43 100644 --- a/dbms/src/Functions/array/arrayCumSumNonNegative.cpp +++ b/dbms/src/Functions/array/arrayCumSumNonNegative.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "FunctionArrayMapped.h" #include @@ -34,6 +36,13 @@ struct ArrayCumSumNonNegativeImpl if (which.isFloat()) return std::make_shared(std::make_shared()); + if (which.isDecimal()) + { + UInt32 scale = getDecimalScale(*expression_return); + DataTypePtr nested = std::make_shared>(maxDecimalPrecision(), scale); + return std::make_shared(nested); + } + throw Exception("arrayCumSumNonNegativeImpl cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } @@ -41,16 +50,24 @@ struct ArrayCumSumNonNegativeImpl template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { - const ColumnVector * column = checkAndGetColumn>(&*mapped); + 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 ColumnVector::Container & data = column->getData(); + const typename ColVecType::Container & data = column->getData(); - auto res_nested = ColumnVector::create(); - typename ColumnVector::Container & res_values = res_nested->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()); size_t pos = 0; @@ -60,7 +77,7 @@ struct ArrayCumSumNonNegativeImpl // skip empty arrays if (pos < offsets[i]) { - accum_sum = data[pos] > 0 ? data[pos] : 0; + accum_sum = data[pos] > 0 ? data[pos] : Element(0); res_values[pos] = accum_sum; for (++pos; pos < offsets[i]; ++pos) { @@ -90,7 +107,10 @@ struct ArrayCumSumNonNegativeImpl 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) || + executeType(mapped, array, res)) return res; else throw Exception("Unexpected column for arrayCumSumNonNegativeImpl: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Functions/array/arrayDifference.cpp b/dbms/src/Functions/array/arrayDifference.cpp index 4d3acb5b927..545749e5ec0 100644 --- a/dbms/src/Functions/array/arrayDifference.cpp +++ b/dbms/src/Functions/array/arrayDifference.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "FunctionArrayMapped.h" #include @@ -37,6 +39,9 @@ struct ArrayDifferenceImpl if (which.isFloat32() || which.isFloat64()) return std::make_shared(std::make_shared()); + if (which.isDecimal()) + return std::make_shared(expression_return); + throw Exception("arrayDifference cannot process values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } @@ -44,16 +49,24 @@ struct ArrayDifferenceImpl template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { - const ColumnVector * column = checkAndGetColumn>(&*mapped); + 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 ColumnVector::Container & data = column->getData(); + const typename ColVecType::Container & data = column->getData(); - auto res_nested = ColumnVector::create(); - typename ColumnVector::Container & res_values = res_nested->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()); size_t pos = 0; @@ -87,7 +100,10 @@ struct ArrayDifferenceImpl 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) || + executeType(mapped, array, res)) return res; else throw Exception("Unexpected column for arrayDifference: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/src/Functions/array/arraySum.cpp b/dbms/src/Functions/array/arraySum.cpp index 403f7625f1d..f6fa2cbba95 100644 --- a/dbms/src/Functions/array/arraySum.cpp +++ b/dbms/src/Functions/array/arraySum.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include "FunctionArrayMapped.h" #include @@ -31,25 +33,40 @@ struct ArraySumImpl if (which.isFloat()) return std::make_shared(); + if (which.isDecimal()) + { + UInt32 scale = getDecimalScale(*expression_return); + return std::make_shared>(maxDecimalPrecision(), scale); + } + throw Exception("arraySum cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } template static bool executeType(const ColumnPtr & mapped, const ColumnArray::Offsets & offsets, ColumnPtr & res_ptr) { - const ColumnVector * column = checkAndGetColumn>(&*mapped); + using ColVecType = std::conditional_t, ColumnDecimal, ColumnVector>; + using ColVecResult = std::conditional_t, ColumnDecimal, ColumnVector>; + + const ColVecType * column = checkAndGetColumn(&*mapped); + const typename ColVecType::Container & data = column->getData(); if (!column) { - const ColumnConst * column_const = checkAndGetColumnConst>(&*mapped); + const ColumnConst * column_const = checkAndGetColumnConst(&*mapped); if (!column_const) return false; const Element x = column_const->template getValue(); - auto res_column = ColumnVector::create(offsets.size()); - typename ColumnVector::Container & res = res_column->getData(); + typename ColVecResult::MutablePtr res_column; + if constexpr (IsDecimalNumber) + res_column = ColVecResult::create(offsets.size(), data.getScale()); + else + res_column = ColVecResult::create(offsets.size()); + + typename ColVecResult::Container & res = res_column->getData(); size_t pos = 0; for (size_t i = 0; i < offsets.size(); ++i) @@ -62,9 +79,13 @@ struct ArraySumImpl return true; } - const typename ColumnVector::Container & data = column->getData(); - auto res_column = ColumnVector::create(offsets.size()); - typename ColumnVector::Container & res = res_column->getData(); + typename ColVecResult::MutablePtr res_column; + if constexpr (IsDecimalNumber) + res_column = ColVecResult::create(offsets.size(), data.getScale()); + else + res_column = ColVecResult::create(offsets.size()); + + typename ColVecResult::Container & res = res_column->getData(); size_t pos = 0; for (size_t i = 0; i < offsets.size(); ++i) @@ -95,7 +116,10 @@ struct ArraySumImpl executeType< Int32, Int64>(mapped, offsets, res) || executeType< Int64, Int64>(mapped, offsets, res) || executeType(mapped, offsets, res) || - executeType(mapped, offsets, res)) + executeType(mapped, offsets, res) || + executeType(mapped, offsets, res) || + executeType(mapped, offsets, res) || + executeType(mapped, offsets, res)) return res; else throw Exception("Unexpected column for arraySum: " + mapped->getName(), ErrorCodes::ILLEGAL_COLUMN); diff --git a/dbms/tests/queries/0_stateless/00700_decimal_array_functions.reference b/dbms/tests/queries/0_stateless/00700_decimal_array_functions.reference new file mode 100644 index 00000000000..969a8dd2f18 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_array_functions.reference @@ -0,0 +1,20 @@ +[0.0000,1.0000] Array(Decimal(9, 4)) +[0.00000000,1.00000000] Array(Decimal(18, 8)) +[0.00000000,1.00000000] Array(Decimal(38, 8)) +- +1.0000 Decimal(38, 4) +1.00000000 Decimal(38, 8) +1.00000000 Decimal(38, 8) +- +[1.0000,2.0000] Array(Decimal(38, 4)) +[1.00000000,2.00000000] Array(Decimal(38, 8)) +[1.00000000,2.00000000] Array(Decimal(38, 8)) +- +[1.0000,2.0000] Array(Decimal(38, 4)) +[1.00000000,2.00000000] Array(Decimal(38, 8)) +[1.00000000,2.00000000] Array(Decimal(38, 8)) +- +[1.0000] Array(Decimal(9, 4)) +[1.00000000] Array(Decimal(18, 8)) +[1.00000000] Array(Decimal(38, 8)) +- diff --git a/dbms/tests/queries/0_stateless/00700_decimal_array_functions.sql b/dbms/tests/queries/0_stateless/00700_decimal_array_functions.sql new file mode 100644 index 00000000000..c76c8728e15 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00700_decimal_array_functions.sql @@ -0,0 +1,20 @@ +SELECT arrayDifference([toDecimal32(0.0,4), toDecimal32(1.0,4)]) x, toTypeName(x); +SELECT arrayDifference([toDecimal64(0.0,8), toDecimal64(1.0,8)]) x, toTypeName(x); +SELECT arrayDifference([toDecimal128(0.0,8), toDecimal128(1.0,8)]) x, toTypeName(x); +SELECT '-'; +SELECT arraySum([toDecimal32(0.0,4), toDecimal32(1.0,4)]) x, toTypeName(x); +SELECT arraySum([toDecimal64(0.0,8), toDecimal64(1.0,8)]) x, toTypeName(x); +SELECT arraySum([toDecimal128(0.0,8), toDecimal128(1.0,8)]) x, toTypeName(x); +SELECT '-'; +SELECT arrayCumSum([toDecimal32(1.0,4), toDecimal32(1.0,4)]) x, toTypeName(x); +SELECT arrayCumSum([toDecimal64(1.0,8), toDecimal64(1.0,8)]) x, toTypeName(x); +SELECT arrayCumSum([toDecimal128(1.0,8), toDecimal128(1.0,8)]) x, toTypeName(x); +SELECT '-'; +SELECT arrayCumSumNonNegative([toDecimal32(1.0,4), toDecimal32(1.0,4)]) x, toTypeName(x); +SELECT arrayCumSumNonNegative([toDecimal64(1.0,8), toDecimal64(1.0,8)]) x, toTypeName(x); +SELECT arrayCumSumNonNegative([toDecimal128(1.0,8), toDecimal128(1.0,8)]) x, toTypeName(x); +SELECT '-'; +SELECT arrayCompact([toDecimal32(1.0,4), toDecimal32(1.0,4)]) x, toTypeName(x); +SELECT arrayCompact([toDecimal64(1.0,8), toDecimal64(1.0,8)]) x, toTypeName(x); +SELECT arrayCompact([toDecimal128(1.0,8), toDecimal128(1.0,8)]) x, toTypeName(x); +SELECT '-';