From 9497377ee9fae4f5a61c3d1becb0b7a0a438a11a Mon Sep 17 00:00:00 2001 From: Rok Date: Thu, 13 Jan 2022 11:28:16 +0100 Subject: [PATCH 1/6] SubtractTimeAndDuration --- .../compute/kernels/scalar_arithmetic.cc | 33 ++++++++++++++++ .../compute/kernels/scalar_temporal_test.cc | 38 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index dd0476584fc..05acf7bebd9 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -239,6 +239,20 @@ struct SubtractCheckedDate32 { } }; +struct SubtractTime32AndDuration { + template + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + return arrow::internal::SafeSignedSubtract(left, static_cast(right)); + } +}; + +struct SubtractTime64AndDuration { + template + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + return arrow::internal::SafeSignedSubtract(left, right); + } +}; + struct Multiply { static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); @@ -2506,6 +2520,25 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { auto exec_date_64 = ScalarBinaryEqualTypes::Exec; DCHECK_OK(subtract->AddKernel({in_type_date_64, in_type_date_64}, duration(TimeUnit::MILLI), std::move(exec_date_64))); + } + + // Add subtract(time32, duration) -> time32 + for (auto unit : {TimeUnit::SECOND, TimeUnit::MILLI}) { + InputType in_type(match::Time32TypeUnit(unit)); + auto exec = + ScalarBinary::Exec; + DCHECK_OK(subtract->AddKernel({in_type, duration(unit)}, OutputType(FirstType), + std::move(exec))); + } + + // Add subtract(time64, duration) -> time64 + for (auto unit : {TimeUnit::MICRO, TimeUnit::NANO}) { + InputType in_type(match::Time64TypeUnit(unit)); + auto exec = + ScalarBinary::Exec; + DCHECK_OK(subtract->AddKernel({in_type, duration(unit)}, OutputType(FirstType), + std::move(exec))); + } DCHECK_OK(registry->AddFunction(std::move(subtract))); diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc index 7b7a31422bf..44b2744b0b4 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc @@ -1156,6 +1156,44 @@ TEST_F(ScalarTemporalTest, TestTemporalSubtractTime) { } } +TEST_F(ScalarTemporalTest, TestTemporalSubtractTimeAndDuration) { + std::string op = "subtract"; + auto arr_s = ArrayFromJSON(time32(TimeUnit::SECOND), times_s); + auto arr_s2 = ArrayFromJSON(time32(TimeUnit::SECOND), times_s2); + auto arr_ms = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms); + auto arr_ms2 = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms2); + auto arr_us = ArrayFromJSON(time64(TimeUnit::MICRO), times_us); + auto arr_us2 = ArrayFromJSON(time64(TimeUnit::MICRO), times_us2); + auto arr_ns = ArrayFromJSON(time64(TimeUnit::NANO), times_ns); + auto arr_ns2 = ArrayFromJSON(time64(TimeUnit::NANO), times_ns2); + + CheckScalarBinary( + op, arr_s2, ArrayFromJSON(duration(TimeUnit::SECOND), seconds_between_time), arr_s); + CheckScalarBinary(op, arr_ms2, + ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_time), + arr_ms); + CheckScalarBinary(op, arr_us2, + ArrayFromJSON(duration(TimeUnit::MICRO), microseconds_between_time), + arr_us); + CheckScalarBinary(op, arr_ns2, + ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_time), + arr_ns); + + CheckScalarBinary(op, arr_s, ArrayFromJSON(duration(TimeUnit::SECOND), zeros), arr_s); + CheckScalarBinary(op, arr_ms, ArrayFromJSON(duration(TimeUnit::MILLI), zeros), arr_ms); + CheckScalarBinary(op, arr_us, ArrayFromJSON(duration(TimeUnit::MICRO), zeros), arr_us); + CheckScalarBinary(op, arr_ns, ArrayFromJSON(duration(TimeUnit::NANO), zeros), arr_ns); + + EXPECT_RAISES_WITH_MESSAGE_THAT( + NotImplemented, testing::HasSubstr("no kernel matching input types"), + Subtract(ArrayFromJSON(time32(TimeUnit::SECOND), times_s), + ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_time))); + EXPECT_RAISES_WITH_MESSAGE_THAT( + NotImplemented, testing::HasSubstr("no kernel matching input types"), + Subtract(ArrayFromJSON(time64(TimeUnit::MICRO), times_us), + ArrayFromJSON(duration(TimeUnit::SECOND), milliseconds_between_time))); +} + TEST_F(ScalarTemporalTest, TestTemporalDifferenceWeeks) { auto raw_days = ArrayFromJSON(timestamp(TimeUnit::SECOND), R"([ "2021-08-09", "2021-08-10", "2021-08-11", "2021-08-12", "2021-08-13", "2021-08-14", "2021-08-15", From fde7ac19b5c5bb65227abff124bcf4aad8a37f20 Mon Sep 17 00:00:00 2001 From: Rok Date: Thu, 20 Jan 2022 18:03:00 +0100 Subject: [PATCH 2/6] Add ReplaceTemporalTypes --- .../compute/kernels/codegen_internal_test.cc | 1 + .../compute/kernels/scalar_arithmetic.cc | 61 +++++++++++++----- .../compute/kernels/scalar_cast_temporal.cc | 16 ++++- .../compute/kernels/scalar_temporal_test.cc | 64 ++++++++++++++----- 4 files changed, 109 insertions(+), 33 deletions(-) diff --git a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc index c2e17e377f2..4b8409b80a4 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc +++ b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc @@ -247,6 +247,7 @@ TEST(TestDispatchBest, ReplaceTemporalTypes) { args = {timestamp(TimeUnit::SECOND, "UTC"), timestamp(TimeUnit::SECOND, tz)}; ty = CommonTemporalResolution(args.data(), args.size()); + ReplaceTemporalTypes(ty, &args); AssertTypeEqual(args[0].type, timestamp(TimeUnit::SECOND, "UTC")); AssertTypeEqual(args[1].type, timestamp(TimeUnit::SECOND, tz)); } diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index 05acf7bebd9..3f6c2a16b15 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -239,17 +239,23 @@ struct SubtractCheckedDate32 { } }; -struct SubtractTime32AndDuration { +struct SubtractLeft32 { template - static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { - return arrow::internal::SafeSignedSubtract(left, static_cast(right)); + static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg0 left, + Arg1 right, Status*) { + return arrow::internal::SafeSignedSubtract(static_cast(left), right); } }; -struct SubtractTime64AndDuration { +struct SubtractLeft32Checked { template - static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { - return arrow::internal::SafeSignedSubtract(left, right); + static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, + Status* st) { + T result = 0; + if (ARROW_PREDICT_FALSE(SubtractWithOverflow(static_cast(left), right, &result))) { + *st = Status::Invalid("overflow"); + } + return result; } }; @@ -1527,6 +1533,7 @@ ArrayKernelExec ArithmeticExecFromOp(detail::GetTypeId get_id) { case Type::UINT32: return KernelGenerator::Exec; case Type::INT64: + case Type::DURATION: case Type::TIMESTAMP: return KernelGenerator::Exec; case Type::UINT64: @@ -2487,6 +2494,15 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { std::move(exec))); } + // Add subtract_checked(duration, duration) -> duration + for (auto unit : TimeUnit::values()) { + InputType in_type(match::DurationTypeUnit(unit)); + auto exec = + ArithmeticExecFromOp(Type::DURATION); + DCHECK_OK( + subtract_checked->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + // Add subtract(timestamp, duration) -> timestamp for (auto unit : TimeUnit::values()) { InputType in_type(match::TimestampTypeUnit(unit)); @@ -2522,22 +2538,28 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { duration(TimeUnit::MILLI), std::move(exec_date_64))); } - // Add subtract(time32, duration) -> time32 + // Add subtract(duration, duration) -> duration + for (auto unit : TimeUnit::values()) { + InputType in_type(match::DurationTypeUnit(unit)); + auto exec = ArithmeticExecFromOp(Type::DURATION); + DCHECK_OK(subtract->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + + // Add subtract(time32, duration) -> duration for (auto unit : {TimeUnit::SECOND, TimeUnit::MILLI}) { InputType in_type(match::Time32TypeUnit(unit)); auto exec = - ScalarBinary::Exec; - DCHECK_OK(subtract->AddKernel({in_type, duration(unit)}, OutputType(FirstType), - std::move(exec))); + ScalarBinary::Exec; + DCHECK_OK( + subtract->AddKernel({in_type, duration(unit)}, duration(unit), std::move(exec))); } - // Add subtract(time64, duration) -> time64 + // Add subtract(time64, duration) -> duration for (auto unit : {TimeUnit::MICRO, TimeUnit::NANO}) { InputType in_type(match::Time64TypeUnit(unit)); - auto exec = - ScalarBinary::Exec; - DCHECK_OK(subtract->AddKernel({in_type, duration(unit)}, OutputType(FirstType), - std::move(exec))); + auto exec = ScalarBinary::Exec; + DCHECK_OK( + subtract->AddKernel({in_type, duration(unit)}, duration(unit), std::move(exec))); } DCHECK_OK(registry->AddFunction(std::move(subtract))); @@ -2557,6 +2579,15 @@ void RegisterScalarArithmetic(FunctionRegistry* registry) { std::move(exec))); } + // Add subtract_checked(duration, duration) -> duration + for (auto unit : TimeUnit::values()) { + InputType in_type(match::DurationTypeUnit(unit)); + auto exec = + ArithmeticExecFromOp(Type::DURATION); + DCHECK_OK( + subtract_checked->AddKernel({in_type, in_type}, duration(unit), std::move(exec))); + } + // Add subtract_checked(timestamp, duration) -> timestamp for (auto unit : TimeUnit::values()) { InputType in_type(match::TimestampTypeUnit(unit)); diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_temporal.cc b/cpp/src/arrow/compute/kernels/scalar_cast_temporal.cc index 74274e963a1..c9ca037a7b8 100644 --- a/cpp/src/arrow/compute/kernels/scalar_cast_temporal.cc +++ b/cpp/src/arrow/compute/kernels/scalar_cast_temporal.cc @@ -338,10 +338,12 @@ struct CastFunctor { }; // ---------------------------------------------------------------------- -// From one time32 or time64 to another +// From one time32 or time64 to another or to duration template -struct CastFunctor::value && is_time_type::value>> { +struct CastFunctor::value && is_time_type::value) || + (is_time_type::value && is_duration_type::value)>> { using in_t = typename I::c_type; using out_t = typename O::c_type; @@ -519,6 +521,16 @@ std::shared_ptr GetDurationCast() { // Between durations AddCrossUnitCast(func.get()); + // time32/64 -> duration + AddSimpleCast(InputType(Type::TIME64), kOutputTargetType, + func.get()); + AddSimpleCast(InputType(Type::TIME64), kOutputTargetType, + func.get()); + AddSimpleCast(InputType(Type::TIME32), kOutputTargetType, + func.get()); + AddSimpleCast(InputType(Type::TIME32), kOutputTargetType, + func.get()); + return func; } diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc index 44b2744b0b4..89f51887f4e 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc @@ -1158,13 +1158,13 @@ TEST_F(ScalarTemporalTest, TestTemporalSubtractTime) { TEST_F(ScalarTemporalTest, TestTemporalSubtractTimeAndDuration) { std::string op = "subtract"; - auto arr_s = ArrayFromJSON(time32(TimeUnit::SECOND), times_s); + auto arr_s = ArrayFromJSON(duration(TimeUnit::SECOND), times_s); auto arr_s2 = ArrayFromJSON(time32(TimeUnit::SECOND), times_s2); - auto arr_ms = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms); + auto arr_ms = ArrayFromJSON(duration(TimeUnit::MILLI), times_ms); auto arr_ms2 = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms2); - auto arr_us = ArrayFromJSON(time64(TimeUnit::MICRO), times_us); + auto arr_us = ArrayFromJSON(duration(TimeUnit::MICRO), times_us); auto arr_us2 = ArrayFromJSON(time64(TimeUnit::MICRO), times_us2); - auto arr_ns = ArrayFromJSON(time64(TimeUnit::NANO), times_ns); + auto arr_ns = ArrayFromJSON(duration(TimeUnit::NANO), times_ns); auto arr_ns2 = ArrayFromJSON(time64(TimeUnit::NANO), times_ns2); CheckScalarBinary( @@ -1179,19 +1179,51 @@ TEST_F(ScalarTemporalTest, TestTemporalSubtractTimeAndDuration) { ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_time), arr_ns); - CheckScalarBinary(op, arr_s, ArrayFromJSON(duration(TimeUnit::SECOND), zeros), arr_s); - CheckScalarBinary(op, arr_ms, ArrayFromJSON(duration(TimeUnit::MILLI), zeros), arr_ms); - CheckScalarBinary(op, arr_us, ArrayFromJSON(duration(TimeUnit::MICRO), zeros), arr_us); - CheckScalarBinary(op, arr_ns, ArrayFromJSON(duration(TimeUnit::NANO), zeros), arr_ns); + auto seconds_3 = ArrayFromJSON(time32(TimeUnit::SECOND), R"([3, null])"); + auto milliseconds_2k = ArrayFromJSON(duration(TimeUnit::MILLI), R"([2000, null])"); + auto milliseconds_1k = ArrayFromJSON(duration(TimeUnit::MILLI), R"([1000, null])"); + auto nanoseconds_3G = ArrayFromJSON(duration(TimeUnit::NANO), R"([3000000000, null])"); + auto microseconds_2M = ArrayFromJSON(duration(TimeUnit::MICRO), R"([2000000, null])"); + auto nanoseconds_1M = ArrayFromJSON(duration(TimeUnit::NANO), R"([1000000000, null])"); + auto microseconds_1M = ArrayFromJSON(duration(TimeUnit::MICRO), R"([1000000, null])"); + CheckScalarBinary(op, seconds_3, milliseconds_2k, milliseconds_1k); + CheckScalarBinary(op, nanoseconds_3G, microseconds_2M, nanoseconds_1M); + CheckScalarBinary(op, seconds_3, microseconds_2M, microseconds_1M); +} - EXPECT_RAISES_WITH_MESSAGE_THAT( - NotImplemented, testing::HasSubstr("no kernel matching input types"), - Subtract(ArrayFromJSON(time32(TimeUnit::SECOND), times_s), - ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_time))); - EXPECT_RAISES_WITH_MESSAGE_THAT( - NotImplemented, testing::HasSubstr("no kernel matching input types"), - Subtract(ArrayFromJSON(time64(TimeUnit::MICRO), times_us), - ArrayFromJSON(duration(TimeUnit::SECOND), milliseconds_between_time))); +TEST_F(ScalarTemporalTest, TestTemporalSubtractTimeAndDurationChecked) { + std::string op = "subtract_checked"; + auto arr_s = ArrayFromJSON(duration(TimeUnit::SECOND), times_s); + auto arr_s2 = ArrayFromJSON(time32(TimeUnit::SECOND), times_s2); + auto arr_ms = ArrayFromJSON(duration(TimeUnit::MILLI), times_ms); + auto arr_ms2 = ArrayFromJSON(time32(TimeUnit::MILLI), times_ms2); + auto arr_us = ArrayFromJSON(duration(TimeUnit::MICRO), times_us); + auto arr_us2 = ArrayFromJSON(time64(TimeUnit::MICRO), times_us2); + auto arr_ns = ArrayFromJSON(duration(TimeUnit::NANO), times_ns); + auto arr_ns2 = ArrayFromJSON(time64(TimeUnit::NANO), times_ns2); + + CheckScalarBinary( + op, arr_s2, ArrayFromJSON(duration(TimeUnit::SECOND), seconds_between_time), arr_s); + CheckScalarBinary(op, arr_ms2, + ArrayFromJSON(duration(TimeUnit::MILLI), milliseconds_between_time), + arr_ms); + CheckScalarBinary(op, arr_us2, + ArrayFromJSON(duration(TimeUnit::MICRO), microseconds_between_time), + arr_us); + CheckScalarBinary(op, arr_ns2, + ArrayFromJSON(duration(TimeUnit::NANO), nanoseconds_between_time), + arr_ns); + + auto seconds_3 = ArrayFromJSON(time32(TimeUnit::SECOND), R"([3, null])"); + auto milliseconds_2k = ArrayFromJSON(duration(TimeUnit::MILLI), R"([2000, null])"); + auto milliseconds_1k = ArrayFromJSON(duration(TimeUnit::MILLI), R"([1000, null])"); + auto nanoseconds_3G = ArrayFromJSON(duration(TimeUnit::NANO), R"([3000000000, null])"); + auto microseconds_2M = ArrayFromJSON(duration(TimeUnit::MICRO), R"([2000000, null])"); + auto nanoseconds_1M = ArrayFromJSON(duration(TimeUnit::NANO), R"([1000000000, null])"); + auto microseconds_1M = ArrayFromJSON(duration(TimeUnit::MICRO), R"([1000000, null])"); + CheckScalarBinary(op, seconds_3, milliseconds_2k, milliseconds_1k); + CheckScalarBinary(op, nanoseconds_3G, microseconds_2M, nanoseconds_1M); + CheckScalarBinary(op, seconds_3, microseconds_2M, microseconds_1M); } TEST_F(ScalarTemporalTest, TestTemporalDifferenceWeeks) { From 55fce19aa33e674fdaed232fd3ce8c008e6bd76d Mon Sep 17 00:00:00 2001 From: Rok Date: Fri, 28 Jan 2022 18:06:00 +0100 Subject: [PATCH 3/6] Review feedback --- .../compute/kernels/codegen_internal_test.cc | 18 ++++ .../compute/kernels/scalar_arithmetic.cc | 86 +++++++++++++++++-- .../compute/kernels/scalar_cast_temporal.cc | 16 +--- .../compute/kernels/scalar_temporal_test.cc | 58 +++++++++---- 4 files changed, 139 insertions(+), 39 deletions(-) diff --git a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc index 4b8409b80a4..bf1dff53adb 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal_test.cc +++ b/cpp/src/arrow/compute/kernels/codegen_internal_test.cc @@ -250,6 +250,24 @@ TEST(TestDispatchBest, ReplaceTemporalTypes) { ReplaceTemporalTypes(ty, &args); AssertTypeEqual(args[0].type, timestamp(TimeUnit::SECOND, "UTC")); AssertTypeEqual(args[1].type, timestamp(TimeUnit::SECOND, tz)); + + args = {time32(TimeUnit::SECOND), duration(TimeUnit::SECOND)}; + ty = CommonTemporalResolution(args.data(), args.size()); + ReplaceTemporalTypes(ty, &args); + AssertTypeEqual(args[0].type, time32(TimeUnit::SECOND)); + AssertTypeEqual(args[1].type, duration(TimeUnit::SECOND)); + + args = {time64(TimeUnit::MICRO), duration(TimeUnit::SECOND)}; + ty = CommonTemporalResolution(args.data(), args.size()); + ReplaceTemporalTypes(ty, &args); + AssertTypeEqual(args[0].type, time64(TimeUnit::MICRO)); + AssertTypeEqual(args[1].type, duration(TimeUnit::MICRO)); + + args = {time32(TimeUnit::SECOND), duration(TimeUnit::NANO)}; + ty = CommonTemporalResolution(args.data(), args.size()); + ReplaceTemporalTypes(ty, &args); + AssertTypeEqual(args[0].type, time64(TimeUnit::NANO)); + AssertTypeEqual(args[1].type, duration(TimeUnit::NANO)); } } // namespace internal diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index 3f6c2a16b15..1e646e22a24 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -239,22 +239,58 @@ struct SubtractCheckedDate32 { } }; -struct SubtractLeft32 { +template +struct SubtractTimeDuration { template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg0 left, - Arg1 right, Status*) { - return arrow::internal::SafeSignedSubtract(static_cast(left), right); + static enable_if_t Call(KernelContext*, Arg0 left, Arg1 right, + Status* st) { + T result = arrow::internal::SafeSignedSubtract(left, static_cast(right)); + if (result < 0) { + *st = Status::Invalid(result, " is not within the acceptable range of ", "[0, ", + multiple, ") s"); + } + return result; + } + + template + static enable_if_t Call(KernelContext*, Arg0 left, Arg1 right, + Status* st) { + T result = arrow::internal::SafeSignedSubtract(left, right); + if (result < 0) { + *st = Status::Invalid(result, " is not within the acceptable range of ", "[0, ", + multiple, ") s"); + } + return result; } }; -struct SubtractLeft32Checked { +template +struct SubtractTimeDurationChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + static enable_if_t Call(KernelContext*, Arg0 left, Arg1 right, + Status* st) { T result = 0; - if (ARROW_PREDICT_FALSE(SubtractWithOverflow(static_cast(left), right, &result))) { + if (ARROW_PREDICT_FALSE(SubtractWithOverflow(left, static_cast(right), &result))) { *st = Status::Invalid("overflow"); } + if (result < 0) { + *st = Status::Invalid(result, " is not within the acceptable range of ", "[0, ", + multiple, ") s"); + } + return result; + } + + template + static enable_if_t Call(KernelContext*, Arg0 left, Arg1 right, + Status* st) { + T result = 0; + if (ARROW_PREDICT_FALSE(SubtractWithOverflow(left, static_cast(right), &result))) { + *st = Status::Invalid("overflow"); + } + if (result < 0) { + *st = Status::Invalid(result, " is not within the acceptable range of ", "[0, ", + multiple, ") s"); + } return result; } }; @@ -1533,7 +1569,6 @@ ArrayKernelExec ArithmeticExecFromOp(detail::GetTypeId get_id) { case Type::UINT32: return KernelGenerator::Exec; case Type::INT64: - case Type::DURATION: case Type::TIMESTAMP: return KernelGenerator::Exec; case Type::UINT64: @@ -2153,6 +2188,34 @@ std::shared_ptr MakeArithmeticFunctionFloatingPointNotNull( return func; } +template