You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ra...@apache.org on 2022/04/27 11:51:45 UTC

[arrow] branch master updated: ARROW-15744: [Gandiva][C++] Add NEGATIVE function for interval types

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 e9481532e9 ARROW-15744: [Gandiva][C++] Add NEGATIVE function for interval types
e9481532e9 is described below

commit e9481532e93e4f29a1c2c322e00f268d6cd9f534
Author: Johnnathan <jo...@gmail.com>
AuthorDate: Wed Apr 27 17:21:33 2022 +0530

    ARROW-15744: [Gandiva][C++] Add NEGATIVE function for interval types
    
    There are two interval types:
    
    YEAR_MONTH
    DAY_TIME
    
    This implementation is based on java implementation.
    
    Closes #12480 from Johnnathanalmeida/feature/add-negative-function-interval-types
    
    Authored-by: Johnnathan <jo...@gmail.com>
    Signed-off-by: Pindikura Ravindra <ra...@dremio.com>
---
 cpp/src/gandiva/function_registry_arithmetic.cc    |  8 ++
 cpp/src/gandiva/precompiled/arithmetic_ops.cc      | 24 ++++++
 cpp/src/gandiva/precompiled/arithmetic_ops_test.cc | 60 ++++++++++++++
 cpp/src/gandiva/precompiled/types.h                |  5 ++
 cpp/src/gandiva/tests/projector_test.cc            | 96 ++++++++++++++++++++++
 5 files changed, 193 insertions(+)

diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc b/cpp/src/gandiva/function_registry_arithmetic.cc
index 6d10fd920d..4c16fc2a84 100644
--- a/cpp/src/gandiva/function_registry_arithmetic.cc
+++ b/cpp/src/gandiva/function_registry_arithmetic.cc
@@ -180,6 +180,14 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() {
                      kResultNullIfNull, "negative_decimal",
                      NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),
 
+      NativeFunction("negative", {}, DataTypeVector{month_interval()}, month_interval(),
+                     kResultNullIfNull, "negative_month_interval",
+                     NativeFunction::kNeedsContext | NativeFunction::kCanReturnErrors),
+
+      NativeFunction("negative", {}, DataTypeVector{day_time_interval()},
+                     day_time_interval(), kResultNullIfNull, "negative_daytimeinterval",
+                     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 3fdc4d0b6a..55994ce733 100644
--- a/cpp/src/gandiva/precompiled/arithmetic_ops.cc
+++ b/cpp/src/gandiva/precompiled/arithmetic_ops.cc
@@ -386,6 +386,30 @@ NUMERIC_FUNCTION_FOR_REAL(NEGATIVE)
 
 NEGATIVE_INTEGER(int32, 32)
 NEGATIVE_INTEGER(int64, 64)
+NEGATIVE_INTEGER(month_interval, 32)
+
+const int64_t INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME = 9223372034707292159;
+const int64_t INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME = -9223372030412324863;
+
+gdv_int64 negative_daytimeinterval(gdv_int64 context, gdv_day_time_interval interval) {
+  if (interval > INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME ||
+      interval < INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME) {
+    gdv_fn_context_set_error_msg(
+        context, "Interval day time is out of boundaries for the negative function");
+    return 0;
+  }
+
+  int64_t left = interval >> 32;
+  int64_t right = interval & 0x00000000FFFFFFFF;
+
+  left = -1 * left;
+  right = -1 * right;
+
+  gdv_int64 out = (left & 0x00000000FFFFFFFF) << 32;
+  out |= (right & 0x00000000FFFFFFFF);
+
+  return out;
+}
 
 #undef NEGATIVE
 #undef NEGATIVE_INTEGER
diff --git a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
index 1cca0cb9c4..532a9a9fc3 100644
--- a/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
+++ b/cpp/src/gandiva/precompiled/arithmetic_ops_test.cc
@@ -179,6 +179,66 @@ TEST(TestArithmeticOps, TestPositiveNegative) {
   ctx.Reset();
 }
 
+TEST(TestArithmeticOps, TestNegativeIntervalTypes) {
+  gandiva::ExecutionContext ctx;
+  int64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
+
+  // Input: 8589934594;         Mean:  2 time &  2 days
+  // Response: -4294967298;     Mean: -2 time & -2 days
+  gdv_int64 result = negative_daytimeinterval(ctx_ptr, 8589934594);
+  EXPECT_EQ(result, -4294967298);
+
+  // Input: -4294967298;      Mean: -2 time & -2 days
+  // Response: 8589934594;    Mean:  2 time &  2 days
+  result = negative_daytimeinterval(ctx_ptr, -4294967298);
+  EXPECT_EQ(result, 8589934594);
+
+  // Input: -12884903388;      Mean: -4 time & -1500 days
+  // Response: 17179870684;    Mean:  4 time &  1500 days
+  result = negative_daytimeinterval(ctx_ptr, -12884903388);
+  EXPECT_EQ(result, 17179870684);
+
+  // Input: 44023418384000;      Mean:  10250 time &  3600000 days
+  // Response: -44019123416704;  Mean: -10250 time & -3600000 days
+  result = negative_daytimeinterval(ctx_ptr, 44023418384000);
+  EXPECT_EQ(result, -44019123416704);
+
+  // Input: 9223372034707292159;      Mean:  2147483647 time &  2147483647 days
+  // Response: -9223372030412324863;  Mean: -2147483647 time & -2147483647 days
+  const int64_t INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME = 9223372034707292159;
+  result = negative_daytimeinterval(ctx_ptr, INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME);
+  EXPECT_EQ(result, -9223372030412324863);
+
+  result = negative_daytimeinterval(ctx_ptr, INT64_MAX);
+  EXPECT_EQ(ctx.has_error(), true);
+  EXPECT_EQ(ctx.get_error(),
+            "Interval day time is out of boundaries for the negative function");
+  ctx.Reset();
+
+  const int64_t INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME = -9223372030412324863;
+  result = negative_daytimeinterval(ctx_ptr, INT_MIN_TO_NEGATIVE_INTERVAL_DAY_TIME);
+  EXPECT_EQ(result, INT_MAX_TO_NEGATIVE_INTERVAL_DAY_TIME);
+
+  result = negative_daytimeinterval(ctx_ptr, INT64_MIN);
+  EXPECT_EQ(ctx.has_error(), true);
+  EXPECT_EQ(ctx.get_error(),
+            "Interval day time is out of boundaries for the negative function");
+  ctx.Reset();
+
+  // Month interval
+  gdv_month_interval result2 = negative_month_interval(ctx_ptr, 2);
+  EXPECT_EQ(result2, -2);
+
+  result2 = negative_month_interval(ctx_ptr, -2);
+  EXPECT_EQ(result2, 2);
+
+  result2 = negative_month_interval(ctx_ptr, 510);
+  EXPECT_EQ(result2, -510);
+
+  result2 = negative_month_interval(ctx_ptr, INT32_MAX);
+  EXPECT_EQ(result2, -INT32_MAX);
+}
+
 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 fde23cdd02..1b492fcfdf 100644
--- a/cpp/src/gandiva/precompiled/types.h
+++ b/cpp/src/gandiva/precompiled/types.h
@@ -207,11 +207,16 @@ 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_month_interval negative_month_interval(gdv_int64 context,
+                                           gdv_month_interval interval);
+gdv_int64 negative_daytimeinterval(gdv_int64 context, gdv_day_time_interval interval);
+
 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 86c35af4bf..06c1dbdf08 100644
--- a/cpp/src/gandiva/tests/projector_test.cc
+++ b/cpp/src/gandiva/tests/projector_test.cc
@@ -1042,6 +1042,102 @@ TEST_F(TestProjector, TestPositiveNegative) {
   EXPECT_ARROW_ARRAY_EQUALS(exp_neg2, outputs.at(1));
 }
 
+TEST_F(TestProjector, TestNegativeMonthInterval) {
+  // schema for input fields
+  auto field0 = field("f0", arrow::month_interval());
+  auto schema = arrow::schema({field0});
+
+  // output fields
+  auto field_pos = field("result", arrow::month_interval());
+
+  // Build expression for NEGATIVE function
+  auto pos_expr = TreeExprBuilder::MakeExpression("negative", {field0}, field_pos);
+
+  std::shared_ptr<Projector> projector;
+  auto status = Projector::Make(schema, {pos_expr}, TestConfiguration(), &projector);
+  EXPECT_TRUE(status.ok()) << status.message();
+
+  // Create a row-batch with some sample data
+  int num_records = 6;
+
+  std::shared_ptr<arrow::Array> array0, exp_pos;
+  arrow::ArrayFromVector<arrow::MonthIntervalType>(
+      arrow::month_interval(), {true, true, true, true, true, true},
+      {2, -2, 10250, 2147483647, 4, -4}, &array0);
+
+  // expected output
+  arrow::ArrayFromVector<arrow::MonthIntervalType>(
+      arrow::month_interval(), {true, true, true, true, true, true},
+      {-2, 2, -10250, -2147483647, -4, 4}, &exp_pos);
+
+  // prepare input record batch
+  auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
+
+  // 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));
+}
+
+TEST_F(TestProjector, TestNegativeIntervalTypeDayTime) {
+  // schema for input fields
+  auto field0 = field("f1", arrow::day_time_interval());
+  auto schema = arrow::schema({field0});
+
+  // output fields
+  auto output_negative = field("result", arrow::day_time_interval());
+
+  // Build expression for POSITIVE function
+  auto pos_expr = TreeExprBuilder::MakeExpression("negative", {field0}, output_negative);
+
+  std::shared_ptr<Projector> projector;
+  auto status = Projector::Make(schema, {pos_expr}, TestConfiguration(), &projector);
+  EXPECT_TRUE(status.ok()) << status.message();
+
+  // Create a row-batch with some sample data
+  int num_records = 7;
+
+  std::shared_ptr<arrow::Array> array_day_interval, array_day_interval_output;
+  arrow::ArrayFromVector<arrow::DayTimeIntervalType,
+                         arrow::DayTimeIntervalType::DayMilliseconds>(
+      arrow::day_time_interval(), {true, true, true, true, true, true, true},
+      {{2, 2},
+       {-2, -2},
+       {10250, 3600000},
+       {2147483647, 2147483647},
+       {4, 1500},
+       {-4, -1500},
+       {-2147483647, -2147483647}},
+      &array_day_interval);
+
+  // expected output
+  arrow::ArrayFromVector<arrow::DayTimeIntervalType,
+                         arrow::DayTimeIntervalType::DayMilliseconds>(
+      arrow::day_time_interval(), {true, true, true, true, true, true, true},
+      {{-2, -2},
+       {2, 2},
+       {-10250, -3600000},
+       {-2147483647, -2147483647},
+       {-4, -1500},
+       {4, 1500},
+       {2147483647, 2147483647}},
+      &array_day_interval_output);
+
+  // prepare input record batch
+  auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_day_interval});
+
+  // Evaluate expression
+  arrow::ArrayVector outputs;
+  status = projector->Evaluate(*in_batch, pool_, &outputs);
+  EXPECT_TRUE(status.ok()) << status.message();
+
+  // Validate results
+  EXPECT_ARROW_ARRAY_EQUALS(array_day_interval_output, outputs.at(0));
+}
+
 TEST_F(TestProjector, TestConcat) {
   // schema for input fields
   auto field0 = field("f0", arrow::utf8());