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 31aa19d  ARROW-4206: [Gandiva] support decimal divide and mod
31aa19d is described below

commit 31aa19da25352d5f6abdf3264d57306c3b52bb05
Author: Pindikura Ravindra <ravin...@dremio.com>
AuthorDate: Thu Mar 14 11:29:42 2019 +0530

    ARROW-4206: [Gandiva] support decimal divide and mod
    
    Author: Pindikura Ravindra <ravin...@dremio.com>
    
    Closes #3813 from pravindra/gdivmod and squashes the following commits:
    
    96ef4054 <Pindikura Ravindra> ARROW-4206:  add global symbol for new fns
    a9ad13fe <Pindikura Ravindra> ARROW-4206:  Add more tests/comments
    697c2343 <Pindikura Ravindra> ARROW-4206:  Fix build errors
    267f117e <Pindikura Ravindra> ARROW-4206:  support decimal divide and mod
---
 cpp/src/arrow/util/basic_decimal.h              |   3 +
 cpp/src/arrow/util/decimal-test.cc              | 115 +++++++++-
 cpp/src/arrow/util/decimal.h                    |   5 +
 cpp/src/gandiva/decimal_ir.cc                   |  58 +++++
 cpp/src/gandiva/decimal_ir.h                    |   4 +
 cpp/src/gandiva/decimal_xlarge.cc               | 121 ++++++++--
 cpp/src/gandiva/decimal_xlarge.h                |   8 +
 cpp/src/gandiva/function_registry_arithmetic.cc |   2 +
 cpp/src/gandiva/precompiled/CMakeLists.txt      |   7 +-
 cpp/src/gandiva/precompiled/decimal_ops.cc      |  84 +++++++
 cpp/src/gandiva/precompiled/decimal_ops.h       |  10 +
 cpp/src/gandiva/precompiled/decimal_ops_test.cc | 281 ++++++++++++++++++++----
 cpp/src/gandiva/precompiled/decimal_wrapper.cc  |  34 +++
 cpp/src/gandiva/tests/decimal_single_test.cc    |  33 ++-
 14 files changed, 698 insertions(+), 67 deletions(-)

diff --git a/cpp/src/arrow/util/basic_decimal.h 
b/cpp/src/arrow/util/basic_decimal.h
index 7929b11..2e5857c 100644
--- a/cpp/src/arrow/util/basic_decimal.h
+++ b/cpp/src/arrow/util/basic_decimal.h
@@ -138,6 +138,9 @@ class ARROW_EXPORT BasicDecimal128 {
   /// - If 'round' is false, the right-most digits are simply dropped.
   BasicDecimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const;
 
+  // returns 1 for positive and zero decimal values, -1 for negative decimal 
values.
+  inline int64_t Sign() const { return 1 | (high_bits_ >> 63); }
+
   /// \brief count the number of leading binary zeroes.
   int32_t CountLeadingBinaryZeros() const;
 
diff --git a/cpp/src/arrow/util/decimal-test.cc 
b/cpp/src/arrow/util/decimal-test.cc
index db4d35f..4ba7d7f 100644
--- a/cpp/src/arrow/util/decimal-test.cc
+++ b/cpp/src/arrow/util/decimal-test.cc
@@ -23,12 +23,16 @@
 #include <tuple>
 
 #include <gtest/gtest.h>
+#include <boost/multiprecision/cpp_int.hpp>
 
 #include "arrow/status.h"
 #include "arrow/testing/gtest_util.h"
+#include "arrow/testing/random.h"
 #include "arrow/util/decimal.h"
 #include "arrow/util/macros.h"
 
+using boost::multiprecision::int128_t;
+
 namespace arrow {
 
 class DecimalTestFixture : public ::testing::Test {
@@ -466,20 +470,113 @@ TEST(Decimal128Test, TestToInteger) {
   ASSERT_RAISES(Invalid, invalid_int64.ToInteger(&out2));
 }
 
+template <typename ArrowType, typename CType = typename ArrowType::c_type>
+std::vector<CType> GetRandomNumbers(int32_t size) {
+  auto rand = random::RandomArrayGenerator(0x5487655);
+  auto x_array = rand.Numeric<ArrowType>(size, 0, 
std::numeric_limits<CType>::max(), 0);
+
+  auto x_ptr = x_array->data()->template GetValues<CType>(1);
+  std::vector<CType> ret;
+  for (int i = 0; i < size; ++i) {
+    ret.push_back(x_ptr[i]);
+  }
+  return ret;
+}
+
 TEST(Decimal128Test, Multiply) {
-  Decimal128 result;
+  ASSERT_EQ(Decimal128(60501), Decimal128(301) * Decimal128(201));
+
+  ASSERT_EQ(Decimal128(-60501), Decimal128(-301) * Decimal128(201));
+
+  ASSERT_EQ(Decimal128(-60501), Decimal128(301) * Decimal128(-201));
+
+  ASSERT_EQ(Decimal128(60501), Decimal128(-301) * Decimal128(-201));
+
+  // Test some random numbers.
+  for (auto x : GetRandomNumbers<Int32Type>(16)) {
+    for (auto y : GetRandomNumbers<Int32Type>(16)) {
+      Decimal128 result = Decimal128(x) * Decimal128(y);
+      ASSERT_EQ(Decimal128(static_cast<int64_t>(x) * y), result)
+          << " x: " << x << " y: " << y;
+    }
+  }
+
+  // Test some edge cases
+  for (auto x : std::vector<int128_t>{-INT64_MAX, -INT32_MAX, 0, INT32_MAX, 
INT64_MAX}) {
+    for (auto y :
+         std::vector<int128_t>{-INT32_MAX, -32, -2, -1, 0, 1, 2, 32, 
INT32_MAX}) {
+      Decimal128 result = Decimal128(x.str()) * Decimal128(y.str());
+      ASSERT_EQ(Decimal128((x * y).str()), result) << " x: " << x << " y: " << 
y;
+    }
+  }
+}
+
+TEST(Decimal128Test, Divide) {
+  ASSERT_EQ(Decimal128(66), Decimal128(20100) / Decimal128(301));
+
+  ASSERT_EQ(Decimal128(-66), Decimal128(-20100) / Decimal128(301));
+
+  ASSERT_EQ(Decimal128(-66), Decimal128(20100) / Decimal128(-301));
 
-  result = Decimal128("301") * Decimal128("201");
-  ASSERT_EQ(result.ToIntegerString(), "60501");
+  ASSERT_EQ(Decimal128(66), Decimal128(-20100) / Decimal128(-301));
 
-  result = Decimal128("-301") * Decimal128("201");
-  ASSERT_EQ(result.ToIntegerString(), "-60501");
+  // Test some random numbers.
+  for (auto x : GetRandomNumbers<Int32Type>(16)) {
+    for (auto y : GetRandomNumbers<Int32Type>(16)) {
+      if (y == 0) {
+        continue;
+      }
 
-  result = Decimal128("301") * Decimal128("-201");
-  ASSERT_EQ(result.ToIntegerString(), "-60501");
+      Decimal128 result = Decimal128(x) / Decimal128(y);
+      ASSERT_EQ(Decimal128(static_cast<int64_t>(x) / y), result)
+          << " x: " << x << " y: " << y;
+    }
+  }
+
+  // Test some edge cases
+  for (auto x : std::vector<int128_t>{-INT64_MAX, -INT32_MAX, 0, INT32_MAX, 
INT64_MAX}) {
+    for (auto y : std::vector<int128_t>{-INT32_MAX, -32, -2, -1, 1, 2, 32, 
INT32_MAX}) {
+      Decimal128 result = Decimal128(x.str()) * Decimal128(y.str());
+      ASSERT_EQ(Decimal128((x * y).str()), result) << " x: " << x << " y: " << 
y;
+    }
+  }
+}
+
+TEST(Decimal128Test, Mod) {
+  ASSERT_EQ(Decimal128(234), Decimal128(20100) % Decimal128(301));
+
+  ASSERT_EQ(Decimal128(-234), Decimal128(-20100) % Decimal128(301));
+
+  ASSERT_EQ(Decimal128(234), Decimal128(20100) % Decimal128(-301));
+
+  ASSERT_EQ(Decimal128(-234), Decimal128(-20100) % Decimal128(-301));
+
+  // Test some random numbers.
+  for (auto x : GetRandomNumbers<Int32Type>(16)) {
+    for (auto y : GetRandomNumbers<Int32Type>(16)) {
+      if (y == 0) {
+        continue;
+      }
+
+      Decimal128 result = Decimal128(x) % Decimal128(y);
+      ASSERT_EQ(Decimal128(static_cast<int64_t>(x) % y), result)
+          << " x: " << x << " y: " << y;
+    }
+  }
+
+  // Test some edge cases
+  for (auto x : std::vector<int128_t>{-INT64_MAX, -INT32_MAX, 0, INT32_MAX, 
INT64_MAX}) {
+    for (auto y : std::vector<int128_t>{-INT32_MAX, -32, -2, -1, 1, 2, 32, 
INT32_MAX}) {
+      Decimal128 result = Decimal128(x.str()) * Decimal128(y.str());
+      ASSERT_EQ(Decimal128((x * y).str()), result) << " x: " << x << " y: " << 
y;
+    }
+  }
+}
 
-  result = Decimal128("-301") * Decimal128("-201");
-  ASSERT_EQ(result.ToIntegerString(), "60501");
+TEST(Decimal128Test, Sign) {
+  ASSERT_EQ(1, Decimal128(999999).Sign());
+  ASSERT_EQ(-1, Decimal128(-999999).Sign());
+  ASSERT_EQ(1, Decimal128(0).Sign());
 }
 
 TEST(Decimal128Test, GetWholeAndFraction) {
diff --git a/cpp/src/arrow/util/decimal.h b/cpp/src/arrow/util/decimal.h
index 4c61a17..3cb86d1 100644
--- a/cpp/src/arrow/util/decimal.h
+++ b/cpp/src/arrow/util/decimal.h
@@ -123,6 +123,11 @@ class ARROW_EXPORT Decimal128 : public BasicDecimal128 {
     return Status::OK();
   }
 
+  friend std::ostream& operator<<(std::ostream& os, const Decimal128& decimal) 
{
+    os << decimal.ToIntegerString();
+    return os;
+  }
+
  private:
   /// Converts internal error code to Status
   Status ToArrowStatus(DecimalStatus dstatus) const;
diff --git a/cpp/src/gandiva/decimal_ir.cc b/cpp/src/gandiva/decimal_ir.cc
index 53727bb..47e60cf 100644
--- a/cpp/src/gandiva/decimal_ir.cc
+++ b/cpp/src/gandiva/decimal_ir.cc
@@ -406,6 +406,60 @@ Status DecimalIR::BuildMultiply() {
   return Status::OK();
 }
 
+Status DecimalIR::BuildDivideOrMod(const std::string& function_name,
+                                   const std::string& internal_fname) {
+  // Create fn prototype :
+  // int128_t
+  // divide_decimal128_decimal128(int64_t execution_context,
+  //                              int128_t x_value, int32_t x_precision, 
int32_t x_scale,
+  //                              int128_t y_value, int32_t y_precision, 
int32_t y_scale
+  //                              int32_t out_precision, int32_t out_scale)
+  auto i32 = types()->i32_type();
+  auto i128 = types()->i128_type();
+  auto function = BuildFunction(function_name, i128,
+                                {
+                                    {"execution_context", types()->i64_type()},
+                                    {"x_value", i128},
+                                    {"x_precision", i32},
+                                    {"x_scale", i32},
+                                    {"y_value", i128},
+                                    {"y_precision", i32},
+                                    {"y_scale", i32},
+                                    {"out_precision", i32},
+                                    {"out_scale", i32},
+                                });
+
+  auto arg_iter = function->arg_begin();
+  auto execution_context = &arg_iter[0];
+  ValueFull x(&arg_iter[1], &arg_iter[2], &arg_iter[3]);
+  ValueFull y(&arg_iter[4], &arg_iter[5], &arg_iter[6]);
+  ValueFull out(nullptr, &arg_iter[7], &arg_iter[8]);
+
+  auto entry = llvm::BasicBlock::Create(*context(), "entry", function);
+  ir_builder()->SetInsertPoint(entry);
+
+  // Make call to pre-compiled IR function.
+  auto block = ir_builder()->GetInsertBlock();
+  auto out_high_ptr = new llvm::AllocaInst(types()->i64_type(), 0, "out_hi", 
block);
+  auto out_low_ptr = new llvm::AllocaInst(types()->i64_type(), 0, "out_low", 
block);
+  auto x_split = ValueSplit::MakeFromInt128(this, x.value());
+  auto y_split = ValueSplit::MakeFromInt128(this, y.value());
+
+  std::vector<llvm::Value*> args = {
+      execution_context, x_split.high(), x_split.low(), x.precision(), 
x.scale(),
+      y_split.high(),    y_split.low(),  y.precision(), y.scale(),     
out.precision(),
+      out.scale(),       out_high_ptr,   out_low_ptr,
+  };
+  ir_builder()->CreateCall(module()->getFunction(internal_fname), args);
+
+  auto out_high = ir_builder()->CreateLoad(out_high_ptr);
+  auto out_low = ir_builder()->CreateLoad(out_low_ptr);
+  auto result = ValueSplit(out_high, out_low).AsInt128(this);
+
+  ir_builder()->CreateRet(result);
+  return Status::OK();
+}
+
 Status DecimalIR::AddFunctions(Engine* engine) {
   auto decimal_ir = std::make_shared<DecimalIR>(engine);
 
@@ -418,6 +472,10 @@ Status DecimalIR::AddFunctions(Engine* engine) {
   ARROW_RETURN_NOT_OK(decimal_ir->BuildAdd());
   ARROW_RETURN_NOT_OK(decimal_ir->BuildSubtract());
   ARROW_RETURN_NOT_OK(decimal_ir->BuildMultiply());
+  ARROW_RETURN_NOT_OK(decimal_ir->BuildDivideOrMod(
+      "divide_decimal128_decimal128", 
"divide_internal_decimal128_decimal128"));
+  ARROW_RETURN_NOT_OK(decimal_ir->BuildDivideOrMod("mod_decimal128_decimal128",
+                                                   
"mod_internal_decimal128_decimal128"));
   return Status::OK();
 }
 
diff --git a/cpp/src/gandiva/decimal_ir.h b/cpp/src/gandiva/decimal_ir.h
index e552cf1..048b9d3 100644
--- a/cpp/src/gandiva/decimal_ir.h
+++ b/cpp/src/gandiva/decimal_ir.h
@@ -149,6 +149,10 @@ class DecimalIR : public FunctionIRBuilder {
   // Build the function for decimal multiplication.
   Status BuildMultiply();
 
+  // Build the function for decimal division/mod.
+  Status BuildDivideOrMod(const std::string& function_name,
+                          const std::string& internal_name);
+
   // Add a trace in IR code.
   void AddTrace(const std::string& fmt, std::vector<llvm::Value*> args);
 
diff --git a/cpp/src/gandiva/decimal_xlarge.cc 
b/cpp/src/gandiva/decimal_xlarge.cc
index 570cd88..4a8f3e5 100644
--- a/cpp/src/gandiva/decimal_xlarge.cc
+++ b/cpp/src/gandiva/decimal_xlarge.cc
@@ -55,7 +55,35 @@ void ExportedDecimalFunctions::AddMappings(Engine* engine) 
const {
   engine->AddGlobalMappingForFunc(
       "gdv_xlarge_multiply_and_scale_down", types->void_type() 
/*return_type*/, args,
       reinterpret_cast<void*>(gdv_xlarge_multiply_and_scale_down));
+
+  // gdv_xlarge_scale_up_and_divide
+  args = {types->i64_type(),      // int64_t x_high
+          types->i64_type(),      // uint64_t x_low
+          types->i64_type(),      // int64_t y_high
+          types->i64_type(),      // uint64_t y_low
+          types->i32_type(),      // int32_t increase_scale_by
+          types->i64_ptr_type(),  // int64_t* out_high
+          types->i64_ptr_type(),  // uint64_t* out_low
+          types->i8_ptr_type()};  // bool* overflow
+
+  engine->AddGlobalMappingForFunc(
+      "gdv_xlarge_scale_up_and_divide", types->void_type() /*return_type*/, 
args,
+      reinterpret_cast<void*>(gdv_xlarge_scale_up_and_divide));
+
+  // gdv_xlarge_mod
+  args = {types->i64_type(),       // int64_t x_high
+          types->i64_type(),       // uint64_t x_low
+          types->i32_type(),       // int32_t x_scale
+          types->i64_type(),       // int64_t y_high
+          types->i64_type(),       // uint64_t y_low
+          types->i32_type(),       // int32_t y_scale
+          types->i64_ptr_type(),   // int64_t* out_high
+          types->i64_ptr_type()};  // uint64_t* out_low
+
+  engine->AddGlobalMappingForFunc("gdv_xlarge_mod", types->void_type() 
/*return_type*/,
+                                  args, 
reinterpret_cast<void*>(gdv_xlarge_mod));
 }
+
 }  // namespace gandiva
 
 #endif  // !GANDIVA_UNIT_TEST
@@ -103,27 +131,34 @@ static BasicDecimal128 ConvertToDecimal128(int256_t in, 
bool* overflow) {
   return is_negative ? -result : result;
 }
 
+static constexpr int32_t kMaxLargeScale = 2 * DecimalTypeUtil::kMaxPrecision;
+
+// Compute the scale multipliers once.
+static std::array<int256_t, kMaxLargeScale + 1> kLargeScaleMultipliers =
+    ([]() -> std::array<int256_t, kMaxLargeScale + 1> {
+      std::array<int256_t, kMaxLargeScale + 1> values;
+      values[0] = 1;
+      for (int32_t idx = 1; idx <= kMaxLargeScale; idx++) {
+        values[idx] = values[idx - 1] * 10;
+      }
+      return values;
+    })();
+
+static int256_t GetScaleMultiplier(int scale) {
+  DCHECK_GE(scale, 0);
+  DCHECK_LE(scale, kMaxLargeScale);
+
+  return kLargeScaleMultipliers[scale];
+}
+
 // divide input by 10^reduce_by, and round up the fractional part.
 static int256_t ReduceScaleBy(int256_t in, int32_t reduce_by) {
-  DCHECK_GE(reduce_by, 0);
-  DCHECK_LE(reduce_by, 2 * DecimalTypeUtil::kMaxPrecision);
-
   if (reduce_by == 0) {
     // nothing to do.
     return in;
   }
 
-  int256_t divisor;
-  if (reduce_by <= DecimalTypeUtil::kMaxPrecision) {
-    divisor = ConvertToInt256(BasicDecimal128::GetScaleMultiplier(reduce_by));
-  } else {
-    divisor = ConvertToInt256(
-        BasicDecimal128::GetScaleMultiplier(DecimalTypeUtil::kMaxPrecision));
-    for (auto i = DecimalTypeUtil::kMaxPrecision; i < reduce_by; i++) {
-      divisor *= 10;
-    }
-  }
-
+  int256_t divisor = GetScaleMultiplier(reduce_by);
   DCHECK_GT(divisor, 0);
   DCHECK_EQ(divisor % 2, 0);  // multiple of 10.
   auto result = in / divisor;
@@ -135,6 +170,14 @@ static int256_t ReduceScaleBy(int256_t in, int32_t 
reduce_by) {
   return result;
 }
 
+// multiply input by 10^increase_by.
+static int256_t IncreaseScaleBy(int256_t in, int32_t increase_by) {
+  DCHECK_GE(increase_by, 0);
+  DCHECK_LE(increase_by, 2 * DecimalTypeUtil::kMaxPrecision);
+
+  return in * GetScaleMultiplier(increase_by);
+}
+
 }  // namespace internal
 }  // namespace gandiva
 
@@ -155,4 +198,54 @@ void gdv_xlarge_multiply_and_scale_down(int64_t x_high, 
uint64_t x_low, int64_t
   *out_low = result.low_bits();
 }
 
+void gdv_xlarge_scale_up_and_divide(int64_t x_high, uint64_t x_low, int64_t 
y_high,
+                                    uint64_t y_low, int32_t increase_scale_by,
+                                    int64_t* out_high, uint64_t* out_low,
+                                    bool* overflow) {
+  BasicDecimal128 x{x_high, x_low};
+  BasicDecimal128 y{y_high, y_low};
+
+  int256_t x_large = gandiva::internal::ConvertToInt256(x);
+  int256_t x_large_scaled_up =
+      gandiva::internal::IncreaseScaleBy(x_large, increase_scale_by);
+  int256_t y_large = gandiva::internal::ConvertToInt256(y);
+  int256_t result_large = x_large_scaled_up / y_large;
+  int256_t remainder_large = x_large_scaled_up % y_large;
+
+  // Since we are scaling up and then, scaling down, round-up the result (+1 
for +ve,
+  // -1 for -ve), if the remainder is >= 2 * divisor.
+  if (abs(2 * remainder_large) >= abs(y_large)) {
+    // x +ve and y +ve, result is +ve =>   (1 ^ 1)  + 1 =  0 + 1 = +1
+    // x +ve and y -ve, result is -ve =>  (-1 ^ 1)  + 1 = -2 + 1 = -1
+    // x +ve and y -ve, result is -ve =>   (1 ^ -1) + 1 = -2 + 1 = -1
+    // x -ve and y -ve, result is +ve =>  (-1 ^ -1) + 1 =  0 + 1 = +1
+    result_large += (x.Sign() ^ y.Sign()) + 1;
+  }
+  auto result = gandiva::internal::ConvertToDecimal128(result_large, overflow);
+  *out_high = result.high_bits();
+  *out_low = result.low_bits();
+}
+
+void gdv_xlarge_mod(int64_t x_high, uint64_t x_low, int32_t x_scale, int64_t 
y_high,
+                    uint64_t y_low, int32_t y_scale, int64_t* out_high,
+                    uint64_t* out_low) {
+  BasicDecimal128 x{x_high, x_low};
+  BasicDecimal128 y{y_high, y_low};
+
+  int256_t x_large = gandiva::internal::ConvertToInt256(x);
+  int256_t y_large = gandiva::internal::ConvertToInt256(y);
+  if (x_scale < y_scale) {
+    x_large = gandiva::internal::IncreaseScaleBy(x_large, y_scale - x_scale);
+  } else {
+    y_large = gandiva::internal::IncreaseScaleBy(y_large, x_scale - y_scale);
+  }
+  auto intermediate_result = x_large % y_large;
+  bool overflow = false;
+  auto result = gandiva::internal::ConvertToDecimal128(intermediate_result, 
&overflow);
+  DCHECK_EQ(overflow, false);
+
+  *out_high = result.high_bits();
+  *out_low = result.low_bits();
+}
+
 }  // extern "C"
diff --git a/cpp/src/gandiva/decimal_xlarge.h b/cpp/src/gandiva/decimal_xlarge.h
index 9d48937..c2e2dd8 100644
--- a/cpp/src/gandiva/decimal_xlarge.h
+++ b/cpp/src/gandiva/decimal_xlarge.h
@@ -27,4 +27,12 @@ void gdv_xlarge_multiply_and_scale_down(int64_t x_high, 
uint64_t x_low, int64_t
                                         uint64_t y_low, int32_t 
reduce_scale_by,
                                         int64_t* out_high, uint64_t* out_low,
                                         bool* overflow);
+
+void gdv_xlarge_scale_up_and_divide(int64_t x_high, uint64_t x_low, int64_t 
y_high,
+                                    uint64_t y_low, int32_t increase_scale_by,
+                                    int64_t* out_high, uint64_t* out_low, 
bool* overflow);
+
+void gdv_xlarge_mod(int64_t x_high, uint64_t x_low, int32_t x_scale, int64_t 
y_high,
+                    uint64_t y_low, int32_t y_scale, int64_t* out_high,
+                    uint64_t* out_low);
 }
diff --git a/cpp/src/gandiva/function_registry_arithmetic.cc 
b/cpp/src/gandiva/function_registry_arithmetic.cc
index 921f91c..ad8445b 100644
--- a/cpp/src/gandiva/function_registry_arithmetic.cc
+++ b/cpp/src/gandiva/function_registry_arithmetic.cc
@@ -57,6 +57,8 @@ std::vector<NativeFunction> GetArithmeticFunctionRegistry() {
       BINARY_SYMMETRIC_SAFE_NULL_IF_NULL(add, decimal128),
       BINARY_SYMMETRIC_SAFE_NULL_IF_NULL(subtract, decimal128),
       BINARY_SYMMETRIC_SAFE_NULL_IF_NULL(multiply, decimal128),
+      BINARY_SYMMETRIC_UNSAFE_NULL_IF_NULL(divide, decimal128),
+      BINARY_SYMMETRIC_UNSAFE_NULL_IF_NULL(mod, decimal128),
 
       BINARY_RELATIONAL_BOOL_FN(equal),
       BINARY_RELATIONAL_BOOL_FN(not_equal),
diff --git a/cpp/src/gandiva/precompiled/CMakeLists.txt 
b/cpp/src/gandiva/precompiled/CMakeLists.txt
index 3ad0e09..b2c3017 100644
--- a/cpp/src/gandiva/precompiled/CMakeLists.txt
+++ b/cpp/src/gandiva/precompiled/CMakeLists.txt
@@ -128,6 +128,9 @@ if(ARROW_BUILD_TESTS)
   add_precompiled_unit_test(arithmetic_ops_test.cc arithmetic_ops.cc 
../context_helper.cc)
   add_precompiled_unit_test(extended_math_ops_test.cc extended_math_ops.cc
                             ../context_helper.cc)
-  add_precompiled_unit_test(decimal_ops_test.cc decimal_ops.cc 
../decimal_type_util.cc
-                            ../decimal_xlarge.cc)
+  add_precompiled_unit_test(decimal_ops_test.cc
+                            decimal_ops.cc
+                            ../decimal_type_util.cc
+                            ../decimal_xlarge.cc
+                            ../context_helper.cc)
 endif()
diff --git a/cpp/src/gandiva/precompiled/decimal_ops.cc 
b/cpp/src/gandiva/precompiled/decimal_ops.cc
index 9aa1f41..e13a5d8 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops.cc
+++ b/cpp/src/gandiva/precompiled/decimal_ops.cc
@@ -23,8 +23,14 @@
 
 #include "gandiva/decimal_type_util.h"
 #include "gandiva/decimal_xlarge.h"
+#include "gandiva/gdv_function_stubs.h"
 #include "gandiva/logging.h"
 
+// Several operations (multiply, divide, mod, ..) require converting to 
256-bit, and we
+// use the boost library for doing 256-bit operations. To avoid references to 
boost from
+// the precompiled-to-ir code (this causes issues with symbol resolution at 
runtime), we
+// use a wrapper exported from the CPP code. The wrapper functions are named 
gdv_xlarge_xx
+
 namespace gandiva {
 namespace decimalops {
 
@@ -339,5 +345,83 @@ BasicDecimal128 Multiply(const BasicDecimalScalar128& x, 
const BasicDecimalScala
   return result;
 }
 
+BasicDecimal128 Divide(int64_t context, const BasicDecimalScalar128& x,
+                       const BasicDecimalScalar128& y, int32_t out_precision,
+                       int32_t out_scale, bool* overflow) {
+  if (y.value() == 0) {
+    char const* err_msg = "divide by zero error";
+    gdv_fn_context_set_error_msg(context, err_msg);
+    return 0;
+  }
+
+  // scale upto the output scale, and do an integer division.
+  int32_t delta_scale = out_scale + y.scale() - x.scale();
+  DCHECK_GE(delta_scale, 0);
+
+  BasicDecimal128 result;
+  auto num_bits_required_after_scaling = MaxBitsRequiredAfterScaling(x, 
delta_scale);
+  if (num_bits_required_after_scaling <= 127) {
+    // fast-path. The dividend fits in 128-bit after scaling too.
+    *overflow = false;
+
+    // do the division.
+    auto x_scaled = CheckAndIncreaseScale(x.value(), delta_scale);
+    BasicDecimal128 remainder;
+    auto status = x_scaled.Divide(y.value(), &result, &remainder);
+    DCHECK_EQ(status, arrow::DecimalStatus::kSuccess);
+
+    // round-up
+    if (BasicDecimal128::Abs(2 * remainder) >= 
BasicDecimal128::Abs(y.value())) {
+      result += (x.value().Sign() ^ y.value().Sign()) + 1;
+    }
+  } else {
+    // convert to 256-bit and do the divide.
+    *overflow = delta_scale > 38 && num_bits_required_after_scaling > 255;
+    if (!*overflow) {
+      int64_t result_high;
+      uint64_t result_low;
+
+      gdv_xlarge_scale_up_and_divide(x.value().high_bits(), 
x.value().low_bits(),
+                                     y.value().high_bits(), 
y.value().low_bits(),
+                                     delta_scale, &result_high, &result_low, 
overflow);
+      result = BasicDecimal128(result_high, result_low);
+    }
+  }
+  return result;
+}
+
+BasicDecimal128 Mod(int64_t context, const BasicDecimalScalar128& x,
+                    const BasicDecimalScalar128& y, int32_t out_precision,
+                    int32_t out_scale, bool* overflow) {
+  if (y.value() == 0) {
+    char const* err_msg = "divide by zero error";
+    gdv_fn_context_set_error_msg(context, err_msg);
+    return 0;
+  }
+
+  // Adsjust x and y to the same scale (higher one), and then, do a integer 
mod.
+  *overflow = false;
+  BasicDecimal128 result;
+  int32_t min_lz = MinLeadingZeros(x, y);
+  if (min_lz >= 2) {
+    auto higher_scale = std::max(x.scale(), y.scale());
+    auto x_scaled = CheckAndIncreaseScale(x.value(), higher_scale - x.scale());
+    auto y_scaled = CheckAndIncreaseScale(y.value(), higher_scale - y.scale());
+    result = x_scaled % y_scaled;
+    DCHECK_LE(BasicDecimal128::Abs(result), BasicDecimal128::GetMaxValue());
+  } else {
+    int64_t result_high;
+    uint64_t result_low;
+
+    gdv_xlarge_mod(x.value().high_bits(), x.value().low_bits(), x.scale(),
+                   y.value().high_bits(), y.value().low_bits(), y.scale(), 
&result_high,
+                   &result_low);
+    result = BasicDecimal128(result_high, result_low);
+  }
+  DCHECK(BasicDecimal128::Abs(result) <= BasicDecimal128::Abs(x.value()) ||
+         BasicDecimal128::Abs(result) <= BasicDecimal128::Abs(y.value()));
+  return result;
+}
+
 }  // namespace decimalops
 }  // namespace gandiva
diff --git a/cpp/src/gandiva/precompiled/decimal_ops.h 
b/cpp/src/gandiva/precompiled/decimal_ops.h
index f45bc78..e0aea7e 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops.h
+++ b/cpp/src/gandiva/precompiled/decimal_ops.h
@@ -40,5 +40,15 @@ arrow::BasicDecimal128 Multiply(const BasicDecimalScalar128& 
x,
                                 const BasicDecimalScalar128& y, int32_t 
out_precision,
                                 int32_t out_scale, bool* overflow);
 
+/// Divide 'x' by 'y', and return the result.
+arrow::BasicDecimal128 Divide(int64_t context, const BasicDecimalScalar128& x,
+                              const BasicDecimalScalar128& y, int32_t 
out_precision,
+                              int32_t out_scale, bool* overflow);
+
+/// Divide 'x' by 'y', and return the remainder.
+arrow::BasicDecimal128 Mod(int64_t context, const BasicDecimalScalar128& x,
+                           const BasicDecimalScalar128& y, int32_t 
out_precision,
+                           int32_t out_scale, bool* overflow);
+
 }  // namespace decimalops
 }  // namespace gandiva
diff --git a/cpp/src/gandiva/precompiled/decimal_ops_test.cc 
b/cpp/src/gandiva/precompiled/decimal_ops_test.cc
index f6d0b02..9672a25 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops_test.cc
+++ b/cpp/src/gandiva/precompiled/decimal_ops_test.cc
@@ -22,17 +22,27 @@
 #include "arrow/testing/gtest_util.h"
 #include "gandiva/decimal_scalar.h"
 #include "gandiva/decimal_type_util.h"
+#include "gandiva/execution_context.h"
 #include "gandiva/precompiled/decimal_ops.h"
 #include "gandiva/precompiled/types.h"
 
 namespace gandiva {
 
+const arrow::Decimal128 kThirtyFive9s(std::string(35, '9'));
+const arrow::Decimal128 kThirtySix9s(std::string(36, '9'));
+const arrow::Decimal128 kThirtyEight9s(std::string(38, '9'));
+
 class TestDecimalSql : public ::testing::Test {
  protected:
   static void Verify(DecimalTypeUtil::Op op, const DecimalScalar128& x,
                      const DecimalScalar128& y, const DecimalScalar128& 
expected_result,
                      bool expected_overflow);
 
+  static void VerifyAllSign(DecimalTypeUtil::Op op, const DecimalScalar128& 
left,
+                            const DecimalScalar128& right,
+                            const DecimalScalar128& expected_output,
+                            bool expected_overflow);
+
   void AddAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
                     const DecimalScalar128& expected_result) {
     // TODO: overflow checks
@@ -53,7 +63,34 @@ class TestDecimalSql : public ::testing::Test {
 
   void MultiplyAndVerifyAllSign(const DecimalScalar128& x, const 
DecimalScalar128& y,
                                 const DecimalScalar128& expected_result,
-                                bool expected_overflow);
+                                bool expected_overflow) {
+    return VerifyAllSign(DecimalTypeUtil::kOpMultiply, x, y, expected_result,
+                         expected_overflow);
+  }
+
+  void DivideAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
+                       const DecimalScalar128& expected_result, bool 
expected_overflow) {
+    return Verify(DecimalTypeUtil::kOpDivide, x, y, expected_result, 
expected_overflow);
+  }
+
+  void DivideAndVerifyAllSign(const DecimalScalar128& x, const 
DecimalScalar128& y,
+                              const DecimalScalar128& expected_result,
+                              bool expected_overflow) {
+    return VerifyAllSign(DecimalTypeUtil::kOpDivide, x, y, expected_result,
+                         expected_overflow);
+  }
+
+  void ModAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
+                    const DecimalScalar128& expected_result, bool 
expected_overflow) {
+    return Verify(DecimalTypeUtil::kOpMod, x, y, expected_result, 
expected_overflow);
+  }
+
+  void ModAndVerifyAllSign(const DecimalScalar128& x, const DecimalScalar128& 
y,
+                           const DecimalScalar128& expected_result,
+                           bool expected_overflow) {
+    return VerifyAllSign(DecimalTypeUtil::kOpMod, x, y, expected_result,
+                         expected_overflow);
+  }
 };
 
 #define EXPECT_DECIMAL_EQ(op, x, y, expected_result, expected_overflow, 
actual_result, \
@@ -78,6 +115,7 @@ void TestDecimalSql::Verify(DecimalTypeUtil::Op op, const 
DecimalScalar128& x,
   auto t1 = std::make_shared<arrow::Decimal128Type>(x.precision(), x.scale());
   auto t2 = std::make_shared<arrow::Decimal128Type>(y.precision(), y.scale());
   bool overflow = false;
+  int64_t context = 0;
 
   Decimal128TypePtr out_type;
   EXPECT_OK(DecimalTypeUtil::GetResultType(op, {t1, t2}, &out_type));
@@ -101,6 +139,18 @@ void TestDecimalSql::Verify(DecimalTypeUtil::Op op, const 
DecimalScalar128& x,
           decimalops::Multiply(x, y, out_type->precision(), out_type->scale(), 
&overflow);
       break;
 
+    case DecimalTypeUtil::kOpDivide:
+      op_name = "divide";
+      out_value = decimalops::Divide(context, x, y, out_type->precision(),
+                                     out_type->scale(), &overflow);
+      break;
+
+    case DecimalTypeUtil::kOpMod:
+      op_name = "mod";
+      out_value = decimalops::Mod(context, x, y, out_type->precision(), 
out_type->scale(),
+                                  &overflow);
+      break;
+
     default:
       // not implemented.
       ASSERT_FALSE(true);
@@ -110,6 +160,33 @@ void TestDecimalSql::Verify(DecimalTypeUtil::Op op, const 
DecimalScalar128& x,
                     overflow);
 }
 
+void TestDecimalSql::VerifyAllSign(DecimalTypeUtil::Op op, const 
DecimalScalar128& left,
+                                   const DecimalScalar128& right,
+                                   const DecimalScalar128& expected_output,
+                                   bool expected_overflow) {
+  // both +ve
+  Verify(op, left, right, expected_output, expected_overflow);
+
+  // left -ve
+  Verify(op, -left, right, -expected_output, expected_overflow);
+
+  if (op == DecimalTypeUtil::kOpMod) {
+    // right -ve
+    Verify(op, left, -right, expected_output, expected_overflow);
+
+    // both -ve
+    Verify(op, -left, -right, -expected_output, expected_overflow);
+  } else {
+    DCHECK(op == DecimalTypeUtil::kOpMultiply || op == 
DecimalTypeUtil::kOpDivide);
+
+    // right -ve
+    Verify(op, left, -right, -expected_output, expected_overflow);
+
+    // both -ve
+    Verify(op, -left, -right, expected_output, expected_overflow);
+  }
+}
+
 TEST_F(TestDecimalSql, Add) {
   // fast-path
   AddAndVerify(DecimalScalar128{"201", 30, 3},   // x
@@ -156,28 +233,7 @@ TEST_F(TestDecimalSql, Subtract) {
       DecimalScalar128{"-99999999999999999999999999999989999990", 38, 6});
 }
 
-void TestDecimalSql::MultiplyAndVerifyAllSign(const DecimalScalar128& left,
-                                              const DecimalScalar128& right,
-                                              const DecimalScalar128& 
expected_output,
-                                              bool expected_overflow) {
-  // both +ve
-  MultiplyAndVerify(left, right, expected_output, expected_overflow);
-
-  // left -ve
-  MultiplyAndVerify(-left, right, -expected_output, expected_overflow);
-
-  // right -ve
-  MultiplyAndVerify(left, -right, -expected_output, expected_overflow);
-
-  // both -ve
-  MultiplyAndVerify(-left, -right, expected_output, expected_overflow);
-}
-
 TEST_F(TestDecimalSql, Multiply) {
-  const std::string thirty_five_9s(35, '9');
-  const std::string thirty_six_9s(36, '9');
-  const std::string thirty_eight_9s(38, '9');
-
   // fast-path : out_precision < 38
   MultiplyAndVerifyAllSign(DecimalScalar128{"201", 10, 3},    // x
                            DecimalScalar128{"301", 10, 2},    // y
@@ -207,21 +263,21 @@ TEST_F(TestDecimalSql, Multiply) {
   // get trimmed).
   MultiplyAndVerifyAllSign(
       DecimalScalar128{"201", 20, 3},                                     // x
-      DecimalScalar128{thirty_five_9s, 35, 2},                            // y
+      DecimalScalar128{kThirtyFive9s, 35, 2},                             // y
       DecimalScalar128{"20099999999999999999999999999999999799", 38, 5},  // 
expected
       false);                                                             // 
overflow
 
   // out_precision == 38, very large values, no trimming of scale (scale <= 6 
doesn't
   // get trimmed). overflow expected.
-  MultiplyAndVerifyAllSign(DecimalScalar128{"201", 20, 3},          // x
-                           DecimalScalar128{thirty_six_9s, 35, 2},  // y
-                           DecimalScalar128{"0", 38, 5},            // expected
-                           true);                                   // overflow
-
-  MultiplyAndVerifyAllSign(DecimalScalar128{"201", 20, 3},            // x
-                           DecimalScalar128{thirty_eight_9s, 35, 2},  // y
-                           DecimalScalar128{"0", 38, 5},              // 
expected
-                           true);                                     // 
overflow
+  MultiplyAndVerifyAllSign(DecimalScalar128{"201", 20, 3},         // x
+                           DecimalScalar128{kThirtySix9s, 35, 2},  // y
+                           DecimalScalar128{"0", 38, 5},           // expected
+                           true);                                  // overflow
+
+  MultiplyAndVerifyAllSign(DecimalScalar128{"201", 20, 3},           // x
+                           DecimalScalar128{kThirtyEight9s, 35, 2},  // y
+                           DecimalScalar128{"0", 38, 5},             // 
expected
+                           true);                                    // 
overflow
 
   // out_precision == 38, small input values, trimming of scale.
   MultiplyAndVerifyAllSign(DecimalScalar128{"201", 20, 5},  // x
@@ -232,23 +288,23 @@ TEST_F(TestDecimalSql, Multiply) {
   // out_precision == 38, large values, trimming of scale.
   MultiplyAndVerifyAllSign(
       DecimalScalar128{"201", 20, 5},                                 // x
-      DecimalScalar128{thirty_five_9s, 35, 5},                        // y
+      DecimalScalar128{kThirtyFive9s, 35, 5},                         // y
       DecimalScalar128{"2010000000000000000000000000000000", 38, 6},  // 
expected
       false);                                                         // 
overflow
 
   // out_precision == 38, very large values, trimming of scale (requires 
convert to 256).
   MultiplyAndVerifyAllSign(
-      DecimalScalar128{thirty_five_9s, 38, 20},                          // x
-      DecimalScalar128{thirty_six_9s, 38, 20},                           // y
+      DecimalScalar128{kThirtyFive9s, 38, 20},                           // x
+      DecimalScalar128{kThirtySix9s, 38, 20},                            // y
       DecimalScalar128{"9999999999999999999999999999999999890", 38, 6},  // 
expected
       false);                                                            // 
overflow
 
   // out_precision == 38, very large values, trimming of scale (requires 
convert to 256).
   // should cause overflow.
-  MultiplyAndVerifyAllSign(DecimalScalar128{thirty_five_9s, 38, 4},  // x
-                           DecimalScalar128{thirty_six_9s, 38, 4},   // y
-                           DecimalScalar128{"0", 38, 6},             // 
expected
-                           true);                                    // 
overflow
+  MultiplyAndVerifyAllSign(DecimalScalar128{kThirtyFive9s, 38, 4},  // x
+                           DecimalScalar128{kThirtySix9s, 38, 4},   // y
+                           DecimalScalar128{"0", 38, 6},            // expected
+                           true);                                   // overflow
 
   // corner cases.
   MultiplyAndVerifyAllSign(
@@ -274,10 +330,153 @@ TEST_F(TestDecimalSql, Multiply) {
                            false);                                   // 
overflow
 
   MultiplyAndVerifyAllSign(
-      DecimalScalar128{thirty_five_9s, 38, 38},                       // x
-      DecimalScalar128{thirty_six_9s, 38, 38},                        // y
+      DecimalScalar128{kThirtyFive9s, 38, 38},                        // x
+      DecimalScalar128{kThirtySix9s, 38, 38},                         // y
       DecimalScalar128{"100000000000000000000000000000000", 38, 37},  // 
expected
       false);                                                         // 
overflow
 }
 
+TEST_F(TestDecimalSql, Divide) {
+  DivideAndVerifyAllSign(DecimalScalar128{"201", 10, 3},             // x
+                         DecimalScalar128{"301", 10, 2},             // y
+                         DecimalScalar128{"6677740863787", 23, 14},  // 
expected
+                         false);                                     // 
overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{"201", 20, 3},                  // x
+                         DecimalScalar128{"301", 20, 2},                  // y
+                         DecimalScalar128{"667774086378737542", 38, 19},  // 
expected
+                         false);                                          // 
overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{"201", 20, 3},          // x
+                         DecimalScalar128{kThirtyFive9s, 35, 2},  // y
+                         DecimalScalar128{"0", 38, 19},           // expected
+                         false);                                  // overflow
+
+  DivideAndVerifyAllSign(
+      DecimalScalar128{kThirtyFive9s, 35, 6},                           // x
+      DecimalScalar128{"201", 20, 3},                                   // y
+      DecimalScalar128{"497512437810945273631840796019900493", 38, 6},  // 
expected
+      false);                                                           // 
overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{kThirtyEight9s, 38, 20},  // x
+                         DecimalScalar128{kThirtyFive9s, 38, 20},   // y
+                         DecimalScalar128{"1000000000", 38, 6},     // expected
+                         false);                                    // overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{"31939128063561476055", 38, 8},  // x
+                         DecimalScalar128{"10000", 20, 0},                 // y
+                         DecimalScalar128{"3193912806356148", 38, 8},      // 
expected
+                         false);
+
+  // Corner cases
+  DivideAndVerifyAllSign(DecimalScalar128{0, UINT64_MAX, 38, 4},  // x
+                         DecimalScalar128{0, UINT64_MAX, 38, 4},  // y
+                         DecimalScalar128{"1000000", 38, 6},      // expected
+                         false);                                  // overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{0, UINT64_MAX, 38, 4},  // x
+                         DecimalScalar128{0, INT64_MAX, 38, 4},   // y
+                         DecimalScalar128{"2000000", 38, 6},      // expected
+                         false);                                  // overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{0, UINT64_MAX, 19, 5},            // 
x
+                         DecimalScalar128{0, INT64_MAX, 19, 5},             // 
y
+                         DecimalScalar128{"20000000000000000001", 38, 19},  // 
expected
+                         false);                                            // 
overflow
+
+  DivideAndVerifyAllSign(DecimalScalar128{kThirtyFive9s, 38, 37},  // x
+                         DecimalScalar128{kThirtyFive9s, 38, 38},  // y
+                         DecimalScalar128{"10000000", 38, 6},      // expected
+                         false);                                   // overflow
+
+  // overflow
+  DivideAndVerifyAllSign(DecimalScalar128{kThirtyEight9s, 38, 6},  // x
+                         DecimalScalar128{"201", 20, 3},           // y
+                         DecimalScalar128{"0", 38, 6},             // expected
+                         true);
+}
+
+TEST_F(TestDecimalSql, Mod) {
+  ModAndVerifyAllSign(DecimalScalar128{"201", 10, 3},  // x
+                      DecimalScalar128{"301", 10, 2},  // y
+                      DecimalScalar128{"201", 10, 3},  // expected
+                      false);                          // overflow
+
+  ModAndVerify(DecimalScalar128{"201", 20, 2},  // x
+               DecimalScalar128{"301", 20, 3},  // y
+               DecimalScalar128{"204", 20, 3},  // expected
+               false);                          // overflow
+
+  ModAndVerifyAllSign(DecimalScalar128{"201", 20, 3},          // x
+                      DecimalScalar128{kThirtyFive9s, 35, 2},  // y
+                      DecimalScalar128{"201", 20, 3},          // expected
+                      false);                                  // overflow
+
+  ModAndVerifyAllSign(DecimalScalar128{kThirtyFive9s, 35, 6},  // x
+                      DecimalScalar128{"201", 20, 3},          // y
+                      DecimalScalar128{"180999", 23, 6},       // expected
+                      false);                                  // overflow
+
+  ModAndVerifyAllSign(DecimalScalar128{kThirtyEight9s, 38, 20},  // x
+                      DecimalScalar128{kThirtyFive9s, 38, 21},   // y
+                      DecimalScalar128{"9990", 38, 21},          // expected
+                      false);                                    // overflow
+
+  ModAndVerifyAllSign(DecimalScalar128{"31939128063561476055", 38, 8},  // x
+                      DecimalScalar128{"10000", 20, 0},                 // y
+                      DecimalScalar128{"63561476055", 28, 8},           // 
expected
+                      false);
+
+  ModAndVerifyAllSign(DecimalScalar128{0, UINT64_MAX, 38, 4},  // x
+                      DecimalScalar128{0, UINT64_MAX, 38, 4},  // y
+                      DecimalScalar128{"0", 38, 4},            // expected
+                      false);                                  // overflow
+
+  ModAndVerifyAllSign(DecimalScalar128{0, UINT64_MAX, 38, 4},  // x
+                      DecimalScalar128{0, INT64_MAX, 38, 4},   // y
+                      DecimalScalar128{"1", 38, 4},            // expected
+                      false);                                  // overflow
+}
+
+TEST_F(TestDecimalSql, DivideByZero) {
+  gandiva::ExecutionContext context;
+  int32_t result_precision;
+  int32_t result_scale;
+  bool overflow;
+
+  // divide-by-zero should cause an error.
+  context.Reset();
+  result_precision = 38;
+  result_scale = 19;
+  decimalops::Divide(reinterpret_cast<int64>(&context), 
DecimalScalar128{"201", 20, 3},
+                     DecimalScalar128{"0", 20, 2}, result_precision, 
result_scale,
+                     &overflow);
+  EXPECT_TRUE(context.has_error());
+  EXPECT_EQ(context.get_error(), "divide by zero error");
+
+  // divide-by-nonzero should not cause an error.
+  context.Reset();
+  decimalops::Divide(reinterpret_cast<int64>(&context), 
DecimalScalar128{"201", 20, 3},
+                     DecimalScalar128{"1", 20, 2}, result_precision, 
result_scale,
+                     &overflow);
+  EXPECT_FALSE(context.has_error());
+
+  // mod-by-zero should cause an error.
+  context.Reset();
+  result_precision = 20;
+  result_scale = 3;
+  decimalops::Mod(reinterpret_cast<int64>(&context), DecimalScalar128{"201", 
20, 3},
+                  DecimalScalar128{"0", 20, 2}, result_precision, result_scale,
+                  &overflow);
+  EXPECT_TRUE(context.has_error());
+  EXPECT_EQ(context.get_error(), "divide by zero error");
+
+  // mod-by-nonzero should not cause an error.
+  context.Reset();
+  decimalops::Mod(reinterpret_cast<int64>(&context), DecimalScalar128{"201", 
20, 3},
+                  DecimalScalar128{"1", 20, 2}, result_precision, result_scale,
+                  &overflow);
+  EXPECT_FALSE(context.has_error());
+}
+
 }  // namespace gandiva
diff --git a/cpp/src/gandiva/precompiled/decimal_wrapper.cc 
b/cpp/src/gandiva/precompiled/decimal_wrapper.cc
index 1066c5c..d5c919e 100644
--- a/cpp/src/gandiva/precompiled/decimal_wrapper.cc
+++ b/cpp/src/gandiva/precompiled/decimal_wrapper.cc
@@ -52,4 +52,38 @@ void multiply_internal_decimal128_decimal128(int64_t x_high, 
uint64_t x_low,
   *out_low = out.low_bits();
 }
 
+FORCE_INLINE
+void divide_internal_decimal128_decimal128(
+    int64_t context, int64_t x_high, uint64_t x_low, int32_t x_precision, 
int32_t x_scale,
+    int64_t y_high, uint64_t y_low, int32_t y_precision, int32_t y_scale,
+    int32_t out_precision, int32_t out_scale, int64_t* out_high, uint64_t* 
out_low) {
+  gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
+  gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
+  bool overflow;
+
+  // TODO ravindra: generate error on overflows (ARROW-4570).
+  arrow::BasicDecimal128 out =
+      gandiva::decimalops::Divide(context, x, y, out_precision, out_scale, 
&overflow);
+  *out_high = out.high_bits();
+  *out_low = out.low_bits();
+}
+
+FORCE_INLINE
+void mod_internal_decimal128_decimal128(int64_t context, int64_t x_high, 
uint64_t x_low,
+                                        int32_t x_precision, int32_t x_scale,
+                                        int64_t y_high, uint64_t y_low,
+                                        int32_t y_precision, int32_t y_scale,
+                                        int32_t out_precision, int32_t 
out_scale,
+                                        int64_t* out_high, uint64_t* out_low) {
+  gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
+  gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
+  bool overflow;
+
+  // TODO ravindra: generate error on overflows (ARROW-4570).
+  arrow::BasicDecimal128 out =
+      gandiva::decimalops::Mod(context, x, y, out_precision, out_scale, 
&overflow);
+  *out_high = out.high_bits();
+  *out_low = out.low_bits();
+}
+
 }  // extern "C"
diff --git a/cpp/src/gandiva/tests/decimal_single_test.cc 
b/cpp/src/gandiva/tests/decimal_single_test.cc
index 0cc93e7..c28c47e 100644
--- a/cpp/src/gandiva/tests/decimal_single_test.cc
+++ b/cpp/src/gandiva/tests/decimal_single_test.cc
@@ -66,6 +66,16 @@ class TestDecimalOps : public ::testing::Test {
     Verify(DecimalTypeUtil::kOpMultiply, "multiply", x, y, expected);
   }
 
+  void DivideAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
+                       const DecimalScalar128& expected) {
+    Verify(DecimalTypeUtil::kOpDivide, "divide", x, y, expected);
+  }
+
+  void ModAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
+                    const DecimalScalar128& expected) {
+    Verify(DecimalTypeUtil::kOpMod, "mod", x, y, expected);
+  }
+
  protected:
   arrow::MemoryPool* pool_;
 };
@@ -258,7 +268,8 @@ TEST_F(TestDecimalOps, TestSubtract) {
                     decimal_literal("-3211", 32, 3));  // expected
 }
 
-// Lots of unit tests for multiply in decimal_ops_test.cc. So, keeping this 
basic.
+// Lots of unit tests for multiply/divide/mod in decimal_ops_test.cc. So, 
keeping these
+// basic.
 TEST_F(TestDecimalOps, TestMultiply) {
   // fast-path
   MultiplyAndVerify(decimal_literal("201", 10, 3),     // x
@@ -271,4 +282,24 @@ TEST_F(TestDecimalOps, TestMultiply) {
                     DecimalScalar128("9999999999999999999999999999999999890", 
38, 6));
 }
 
+TEST_F(TestDecimalOps, TestDivide) {
+  DivideAndVerify(decimal_literal("201", 10, 3),              // x
+                  decimal_literal("301", 10, 2),              // y
+                  decimal_literal("6677740863787", 23, 14));  // expected
+
+  DivideAndVerify(DecimalScalar128(std::string(38, '9'), 38, 20),  // x
+                  DecimalScalar128(std::string(35, '9'), 38, 20),  // x
+                  DecimalScalar128("1000000000", 38, 6));
+}
+
+TEST_F(TestDecimalOps, TestMod) {
+  ModAndVerify(decimal_literal("201", 20, 2),   // x
+               decimal_literal("301", 20, 3),   // y
+               decimal_literal("204", 20, 3));  // expected
+
+  ModAndVerify(DecimalScalar128(std::string(38, '9'), 38, 20),  // x
+               DecimalScalar128(std::string(35, '9'), 38, 21),  // x
+               DecimalScalar128("9990", 38, 21));
+}
+
 }  // namespace gandiva

Reply via email to