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 dc2f678 ARROW-13375: [C++][Gandiva] Implement POSITIVE and NEGATIVE Hive functions on Gandiva dc2f678 is described below commit dc2f678797d70ce990d4d73551ee573965dd38aa Author: João Pedro <jo...@simbioseventures.com> AuthorDate: Sun Feb 6 11:38:34 2022 +0530 ARROW-13375: [C++][Gandiva] Implement POSITIVE and NEGATIVE Hive functions on Gandiva Implement POSITIVE and NEGATIVE Hive functions on Gandiva Closes #10742 from jpedroantunes/feature/positive-negative Authored-by: João Pedro <jo...@simbioseventures.com> Signed-off-by: Pindikura Ravindra <ravin...@dremio.com> --- cpp/src/gandiva/function_registry_arithmetic.cc | 17 ++++++ cpp/src/gandiva/gdv_function_stubs_test.cc | 2 +- cpp/src/gandiva/precompiled/arithmetic_ops.cc | 41 +++++++++++++-- cpp/src/gandiva/precompiled/arithmetic_ops_test.cc | 42 +++++++++++++++ cpp/src/gandiva/precompiled/types.h | 9 ++++ cpp/src/gandiva/tests/projector_test.cc | 60 ++++++++++++++++++++++ 6 files changed, 167 insertions(+), 4 deletions(-) diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc b/cpp/src/gandiva/function_registry_arithmetic.cc index 4dc478f..983f7fe 100644 --- a/cpp/src/gandiva/function_registry_arithmetic.cc +++ b/cpp/src/gandiva/function_registry_arithmetic.cc @@ -16,6 +16,7 @@ // under the License. #include "gandiva/function_registry_arithmetic.h" + #include "gandiva/function_registry_common.h" namespace gandiva { @@ -159,6 +160,22 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() { NativeFunction("bround", {}, DataTypeVector{float64()}, float64(), kResultNullIfNull, "bround_float64"), + // positive and negative functions + UNARY_SAFE_NULL_IF_NULL(positive, {}, int32, int32), + UNARY_SAFE_NULL_IF_NULL(positive, {}, int64, int64), + UNARY_SAFE_NULL_IF_NULL(positive, {}, float32, float32), + UNARY_SAFE_NULL_IF_NULL(positive, {}, float64, float64), + UNARY_SAFE_NULL_IF_NULL(negative, {}, float32, float32), + UNARY_SAFE_NULL_IF_NULL(negative, {}, float64, float64), + + NativeFunction("negative", {}, DataTypeVector{int32()}, int32(), kResultNullIfNull, + "negative_int32", + NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors), + + NativeFunction("negative", {}, DataTypeVector{int64()}, int64(), kResultNullIfNull, + "negative_int64", + 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/gdv_function_stubs_test.cc b/cpp/src/gandiva/gdv_function_stubs_test.cc index 2288867..c0b938c 100644 --- a/cpp/src/gandiva/gdv_function_stubs_test.cc +++ b/cpp/src/gandiva/gdv_function_stubs_test.cc @@ -20,8 +20,8 @@ #include <gandiva/precompiled/testing.h> #include <gmock/gmock.h> #include <gtest/gtest.h> -#include "arrow/util/logging.h" +#include "arrow/util/logging.h" #include "gandiva/execution_context.h" namespace gandiva { diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops.cc b/cpp/src/gandiva/precompiled/arithmetic_ops.cc index b272cfc..3bae866 100644 --- a/cpp/src/gandiva/precompiled/arithmetic_ops.cc +++ b/cpp/src/gandiva/precompiled/arithmetic_ops.cc @@ -15,9 +15,11 @@ // specific language governing permissions and limitations // under the License. +#include <cmath> +#include <cstdint> + extern "C" { -#include <math.h> #include "./types.h" // Expand inner macro for all numeric types. @@ -246,6 +248,10 @@ IS_TRUE_OR_FALSE_BOOL(isfalse, boolean, !) NUMERIC_TYPES(IS_TRUE_OR_FALSE_NUMERIC, istrue, +) NUMERIC_TYPES(IS_TRUE_OR_FALSE_NUMERIC, isfalse, !) +#define NUMERIC_FUNCTION_FOR_REAL(INNER) \ + INNER(float32) \ + INNER(float64) + #define NUMERIC_FUNCTION(INNER) \ INNER(int8) \ INNER(int16) \ @@ -255,8 +261,7 @@ NUMERIC_TYPES(IS_TRUE_OR_FALSE_NUMERIC, isfalse, !) INNER(uint16) \ INNER(uint32) \ INNER(uint64) \ - INNER(float32) \ - INNER(float64) + NUMERIC_FUNCTION_FOR_REAL(INNER) #define DATE_FUNCTION(INNER) \ INNER(date32) \ @@ -332,6 +337,36 @@ NUMERIC_FUNCTION(DIVIDE) #undef DIVIDE +#define POSITIVE(TYPE) \ + FORCE_INLINE \ + gdv_##TYPE positive_##TYPE(gdv_##TYPE in) { return in; } + +NUMERIC_FUNCTION(POSITIVE) + +#undef POSITIVE + +#define NEGATIVE(TYPE) \ + FORCE_INLINE \ + gdv_##TYPE negative_##TYPE(gdv_##TYPE in) { return static_cast<gdv_##TYPE>(-1 * in); } + +NUMERIC_FUNCTION_FOR_REAL(NEGATIVE) + +#define NEGATIVE_INTEGER(TYPE, SIZE) \ + FORCE_INLINE \ + gdv_##TYPE negative_##TYPE(gdv_int64 context, gdv_##TYPE in) { \ + if (in <= INT##SIZE##_MIN) { \ + gdv_fn_context_set_error_msg(context, "Overflow in negative execution"); \ + return 0; \ + } \ + return -1 * in; \ + } + +NEGATIVE_INTEGER(int32, 32) +NEGATIVE_INTEGER(int64, 64) + +#undef NEGATIVE +#undef NEGATIVE_INTEGER + #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 f8448d8..4f40f2f 100644 --- a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc +++ b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc @@ -17,6 +17,9 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> + +#include <cstdint> + #include "../execution_context.h" #include "gandiva/precompiled/types.h" @@ -77,6 +80,45 @@ TEST(TestArithmeticOps, TestMod) { EXPECT_FALSE(context.has_error()); } +TEST(TestArithmeticOps, TestPositiveNegative) { + EXPECT_EQ(positive_int32(10), 10); + EXPECT_EQ(positive_int64(1000), 1000); + EXPECT_EQ(positive_float32(1.500f), 1.500f); + EXPECT_EQ(positive_float64(10.500f), 10.500f); + + EXPECT_EQ(negative_float32(1.500f), -1.500f); + EXPECT_EQ(negative_float64(10.500f), -10.500f); + + EXPECT_EQ(positive_int32(-10), -10); + EXPECT_EQ(positive_int64(-1000), -1000); + EXPECT_EQ(positive_float32(-1.500f), -1.500f); + EXPECT_EQ(positive_float64(-10.500f), -10.500f); + + EXPECT_EQ(negative_float32(-1.500f), 1.500f); + EXPECT_EQ(negative_float64(-10.500f), 10.500f); + + gandiva::ExecutionContext ctx; + + int64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx); + + EXPECT_EQ(negative_int32(ctx_ptr, 100), -100); + EXPECT_EQ(negative_int32(ctx_ptr, -100), 100); + + EXPECT_EQ(negative_int64(ctx_ptr, 100L), -100L); + EXPECT_EQ(negative_int64(ctx_ptr, -100L), 100L); + + EXPECT_EQ(negative_int32(ctx_ptr, (INT32_MIN + 1)), (INT32_MAX)); + EXPECT_EQ(negative_int64(ctx_ptr, (INT64_MIN + 1)), (INT64_MAX)); + + negative_int32(ctx_ptr, INT32_MIN); + EXPECT_THAT(ctx.get_error(), ::testing::HasSubstr("Overflow in negative execution")); + ctx.Reset(); + + negative_int64(ctx_ptr, INT64_MIN); + EXPECT_THAT(ctx.get_error(), ::testing::HasSubstr("Overflow in negative execution")); + ctx.Reset(); +} + TEST(TestArithmeticOps, TestDivide) { gandiva::ExecutionContext context; EXPECT_EQ(divide_int64_int64(reinterpret_cast<gdv_int64>(&context), 10, 0), 0); diff --git a/cpp/src/gandiva/precompiled/types.h b/cpp/src/gandiva/precompiled/types.h index e29e782..e08dacd 100644 --- a/cpp/src/gandiva/precompiled/types.h +++ b/cpp/src/gandiva/precompiled/types.h @@ -185,6 +185,15 @@ gdv_float64 mod_float64_float64(gdv_int64 context, gdv_float64 left, gdv_float64 gdv_int64 pmod_int64_int64(int64_t context, gdv_int64 left, gdv_int64 right); +gdv_int32 positive_int32(gdv_int32 in); +gdv_int64 positive_int64(gdv_int64 in); +gdv_int32 negative_int32(gdv_int64 context, gdv_int32 in); +gdv_int64 negative_int64(gdv_int64 context, gdv_int64 in); +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); + gdv_int64 divide_int64_int64(gdv_int64 context, gdv_int64 in1, gdv_int64 in2); gdv_int64 div_int64_int64(gdv_int64 context, gdv_int64 in1, gdv_int64 in2); diff --git a/cpp/src/gandiva/tests/projector_test.cc b/cpp/src/gandiva/tests/projector_test.cc index b3584ec..d12d4f8 100644 --- a/cpp/src/gandiva/tests/projector_test.cc +++ b/cpp/src/gandiva/tests/projector_test.cc @@ -943,6 +943,66 @@ TEST_F(TestProjector, TestGreatestLeast) { EXPECT_ARROW_ARRAY_EQUALS(exp_least, outputs_lst.at(0)); } +TEST_F(TestProjector, TestPositiveNegative) { + // schema for input fields + auto field0 = field("f0", int32()); + auto field1 = field("f1", int64()); + auto schema = arrow::schema({field0, field1}); + + // output fields + auto field_pos = field("positive", int32()); + auto field_pos2 = field("positive2", int64()); + + // Build expression for POSITIVE function + auto pos_expr = TreeExprBuilder::MakeExpression("positive", {field0}, field_pos); + auto pos_expr2 = TreeExprBuilder::MakeExpression("positive", {field1}, field_pos2); + + std::shared_ptr<Projector> projector; + auto status = + Projector::Make(schema, {pos_expr, pos_expr2}, TestConfiguration(), &projector); + EXPECT_TRUE(status.ok()) << status.message(); + + // Create a row-batch with some sample data + int num_records = 4; + auto array0 = MakeArrowArrayInt32({2, 3, 4, 5}, {true, true, true, true}); + auto array1 = MakeArrowArrayInt64({100, 200, 300, 400}, {true, true, true, true}); + // expected output + auto exp_pos = MakeArrowArrayInt32({2, 3, 4, 5}, {true, true, true, true}); + auto exp_pos2 = MakeArrowArrayInt64({100, 200, 300, 400}, {true, true, true, true}); + + // prepare input record batch + auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1}); + + // Evaluate expression + arrow::ArrayVector outputs; + status = projector->Evaluate(*in_batch, pool_, &outputs); + EXPECT_TRUE(status.ok()) << status.message(); + + // Validate results + EXPECT_ARROW_ARRAY_EQUALS(exp_pos, outputs.at(0)); + EXPECT_ARROW_ARRAY_EQUALS(exp_pos2, outputs.at(1)); + + // Build expression for NEG function + auto neg_expr = TreeExprBuilder::MakeExpression("negative", {field0}, field_pos); + auto neg_expr2 = TreeExprBuilder::MakeExpression("negative", {field1}, field_pos2); + + status = + Projector::Make(schema, {neg_expr, neg_expr2}, TestConfiguration(), &projector); + EXPECT_TRUE(status.ok()) << status.message(); + + // expected output + auto exp_neg = MakeArrowArrayInt32({-2, -3, -4, -5}, {true, true, true, true}); + auto exp_neg2 = MakeArrowArrayInt64({-100, -200, -300, -400}, {true, true, true, true}); + + // Evaluate expression + status = projector->Evaluate(*in_batch, pool_, &outputs); + EXPECT_TRUE(status.ok()) << status.message(); + + // Validate results + EXPECT_ARROW_ARRAY_EQUALS(exp_neg, outputs.at(0)); + EXPECT_ARROW_ARRAY_EQUALS(exp_neg2, outputs.at(1)); +} + TEST_F(TestProjector, TestConcat) { // schema for input fields auto field0 = field("f0", arrow::utf8());