This is an automated email from the ASF dual-hosted git repository. ravindra pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push: new 3e56a949c7 ARROW-15940: [Gandiva][C++] Add NEGATIVE function for decimal data type 3e56a949c7 is described below commit 3e56a949c73168d789612a9022cdceae6088e2b7 Author: Johnnathan <johnnathanalme...@gmail.com> AuthorDate: Tue Apr 26 16:32:01 2022 +0530 ARROW-15940: [Gandiva][C++] Add NEGATIVE function for decimal data type This PR implements the NEGATIVE function for decimal data type. The function receive a decimal128() and return a negative decimal128(). Closes #12581 from Johnnathanalmeida/feature/negative-function-for-decimal Authored-by: Johnnathan <johnnathanalme...@gmail.com> Signed-off-by: Pindikura Ravindra <ravin...@dremio.com> --- cpp/src/gandiva/function_registry_arithmetic.cc | 4 ++ cpp/src/gandiva/precompiled/arithmetic_ops.cc | 11 ++++ cpp/src/gandiva/precompiled/arithmetic_ops_test.cc | 60 ++++++++++++++++++++++ cpp/src/gandiva/precompiled/types.h | 4 ++ cpp/src/gandiva/tests/decimal_test.cc | 45 ++++++++++++++++ 5 files changed, 124 insertions(+) diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc b/cpp/src/gandiva/function_registry_arithmetic.cc index 5baf84bfd8..6d10fd920d 100644 --- a/cpp/src/gandiva/function_registry_arithmetic.cc +++ b/cpp/src/gandiva/function_registry_arithmetic.cc @@ -176,6 +176,10 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() { "negative_int64", NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors), + NativeFunction("negative", {}, DataTypeVector{decimal128()}, decimal128(), + kResultNullIfNull, "negative_decimal", + NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors), + // compare functions BINARY_RELATIONAL_BOOL_FN(equal, ({"eq", "same"})), BINARY_RELATIONAL_BOOL_FN(not_equal, {}), diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops.cc b/cpp/src/gandiva/precompiled/arithmetic_ops.cc index ccc09ab873..3fdc4d0b6a 100644 --- a/cpp/src/gandiva/precompiled/arithmetic_ops.cc +++ b/cpp/src/gandiva/precompiled/arithmetic_ops.cc @@ -17,6 +17,7 @@ #include <cmath> #include <cstdint> +#include "arrow/util/basic_decimal.h" extern "C" { @@ -389,6 +390,16 @@ NEGATIVE_INTEGER(int64, 64) #undef NEGATIVE #undef NEGATIVE_INTEGER +void negative_decimal(gdv_int64 context, int64_t high_bits, uint64_t low_bits, + int32_t /*precision*/, int32_t /*scale*/, int32_t /*out_precision*/, + int32_t /*out_scale*/, int64_t* out_high_bits, + uint64_t* out_low_bits) { + arrow::BasicDecimal128 res = arrow::BasicDecimal128(high_bits, low_bits).Negate(); + + *out_high_bits = res.high_bits(); + *out_low_bits = res.low_bits(); +} + #define DIV(TYPE) \ FORCE_INLINE \ gdv_##TYPE div_##TYPE##_##TYPE(gdv_int64 context, gdv_##TYPE in1, gdv_##TYPE in2) { \ diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc index 91a1ae7f70..1cca0cb9c4 100644 --- a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc +++ b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc @@ -21,6 +21,9 @@ #include <cstdint> #include "../execution_context.h" +#include "arrow/testing/gtest_util.h" +#include "arrow/util/decimal.h" +#include "gandiva/decimal_scalar.h" #include "gandiva/precompiled/types.h" namespace gandiva { @@ -80,6 +83,63 @@ TEST(TestArithmeticOps, TestMod) { EXPECT_FALSE(context.has_error()); } +TEST(TestArithmeticOps, TestNegativeDecimal) { + gandiva::ExecutionContext ctx; + int64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx); + + int64_t out_high_bits = 0; + uint64_t out_low_bits = 0; + + arrow::Decimal128 input_decimal("-10.5"); + negative_decimal(ctx_ptr, input_decimal.high_bits(), input_decimal.low_bits(), 3, 1, 3, + 1, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal("10.5"); + EXPECT_EQ(output_decimal.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal2("10.5"); + negative_decimal(ctx_ptr, input_decimal2.high_bits(), input_decimal2.low_bits(), 3, 1, + 3, 1, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal2("-10.5"); + EXPECT_EQ(output_decimal2.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal2.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal3("-23049223942343.532412"); + negative_decimal(ctx_ptr, input_decimal3.high_bits(), input_decimal3.low_bits(), 20, 6, + 20, 6, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal3("23049223942343.532412"); + EXPECT_EQ(output_decimal3.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal3.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal4("15.001"); + negative_decimal(ctx_ptr, input_decimal4.high_bits(), input_decimal4.low_bits(), 2, 3, + 2, 3, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal4("-15.001"); + EXPECT_EQ(output_decimal4.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal4.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal5("17"); + negative_decimal(ctx_ptr, input_decimal5.high_bits(), input_decimal5.low_bits(), 2, 0, + 2, 0, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal5("-17"); + EXPECT_EQ(output_decimal5.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal5.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal6("-99917"); + negative_decimal(ctx_ptr, input_decimal6.high_bits(), input_decimal6.low_bits(), 5, 0, + 5, 0, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal6("99917"); + EXPECT_EQ(output_decimal6.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal6.low_bits(), out_low_bits); + + arrow::Decimal128 input_decimal7("0.99917"); + negative_decimal(ctx_ptr, input_decimal7.high_bits(), input_decimal7.low_bits(), 0, 5, + 0, 5, &out_high_bits, &out_low_bits); + arrow::Decimal128 output_decimal7("-0.99917"); + EXPECT_EQ(output_decimal7.high_bits(), out_high_bits); + EXPECT_EQ(output_decimal7.low_bits(), out_low_bits); +} + TEST(TestArithmeticOps, TestPositiveNegative) { EXPECT_EQ(positive_int32(10), 10); EXPECT_EQ(positive_int64(1000), 1000); diff --git a/cpp/src/gandiva/precompiled/types.h b/cpp/src/gandiva/precompiled/types.h index 1f1e42deb6..f3bd51ae80 100644 --- a/cpp/src/gandiva/precompiled/types.h +++ b/cpp/src/gandiva/precompiled/types.h @@ -207,6 +207,10 @@ gdv_float32 positive_float32(gdv_float32 in); gdv_float64 positive_float64(gdv_float64 in); gdv_float32 negative_float32(gdv_float32 in); gdv_float64 negative_float64(gdv_float64 in); +void negative_decimal(gdv_int64 context, int64_t high_bits, uint64_t low_bits, + int32_t /*precision*/, int32_t /*scale*/, int32_t /*out_precision*/, + int32_t /*out_scale*/, int64_t* out_high_bits, + uint64_t* out_low_bits); gdv_int64 divide_int64_int64(gdv_int64 context, gdv_int64 in1, gdv_int64 in2); diff --git a/cpp/src/gandiva/tests/decimal_test.cc b/cpp/src/gandiva/tests/decimal_test.cc index 31f2dedf5c..1924f5b408 100644 --- a/cpp/src/gandiva/tests/decimal_test.cc +++ b/cpp/src/gandiva/tests/decimal_test.cc @@ -301,6 +301,51 @@ TEST_F(TestDecimal, TestCompare) { outputs[5]); // greater_than_or_equal_to } +TEST_F(TestDecimal, TestNegative) { + // schema for input fields + constexpr int32_t precision = 3; + constexpr int32_t scale = 1; + + auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale); + + auto field_a = field("a", decimal_type); + auto schema = arrow::schema({field_a}); + + // build expressions + auto exprs = std::vector<ExpressionPtr>{ + TreeExprBuilder::MakeExpression("negative", {field_a}, + field("res_negative", decimal_type)), + }; + + // Build a projector for the expression. + std::shared_ptr<Projector> projector; + auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector); + DCHECK_OK(status); + + // Create a row-batch with some sample data + int num_records = 4; + auto validity = {true, true, true, true}; + auto array_a = MakeArrowArrayDecimal( + decimal_type, MakeDecimalVector({"10.5", "-10.5", "-50.2", "50.2"}, scale), + validity); + + // prepare input record batch + auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a}); + + // Evaluate expression + arrow::ArrayVector outputs; + status = projector->Evaluate(*in_batch, pool_, &outputs); + DCHECK_OK(status); + + // Validate results + // negative(x) + EXPECT_ARROW_ARRAY_EQUALS( + MakeArrowArrayDecimal(decimal_type, + MakeDecimalVector({"-10.5", "10.5", "50.2", "-50.2"}, scale), + validity), + outputs[0]); +} + // ARROW-9092: This test is conditionally disabled when building with LLVM 9 // because it hangs. #if GANDIVA_LLVM_VERSION != 9