Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.spark.sql.types

import java.lang.{Long => JLong}
import java.math.{BigInteger, MathContext, RoundingMode}

import org.apache.spark.annotation.DeveloperApi
Expand Down Expand Up @@ -132,17 +133,15 @@ final class Decimal extends Ordered[Decimal] with Serializable {
* Set this Decimal to the given BigInteger value. Will have precision 38 and scale 0.
*/
def set(bigintval: BigInteger): Decimal = {
try {
this.decimalVal = null
this.longVal = bigintval.longValueExact()
this._precision = DecimalType.MAX_PRECISION
this._scale = 0
this
}
catch {
case e: ArithmeticException =>
throw new IllegalArgumentException(s"BigInteger ${bigintval} too large for decimal")
}
// TODO: Remove this once we migrate to java8 and use longValueExact() instead.
require(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why doing this as a require intsead of try catch?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the error is not detected by catching an exception but by manually checking the value. Require is the simplest way to get the desired result which is an IAE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this have a potential perf hit? Also - is this actually related to the problem this ticket is solving?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is we can't call a method that will throw an exception if the value is out of bounds during conversion. We just check it manually. I actually expect this is faster but it is vanishingly small as a difference. I don't think there is a choice if Java 7 is being supported.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. Then well - we have to do this.

bigintval.compareTo(LONG_MAX_BIG_INT) <= 0 && bigintval.compareTo(LONG_MIN_BIG_INT) >= 0,
s"BigInteger $bigintval too large for decimal")
this.decimalVal = null
this.longVal = bigintval.longValue()
this._precision = DecimalType.MAX_PRECISION
this._scale = 0
this
}

/**
Expand Down Expand Up @@ -382,6 +381,9 @@ object Decimal {
private[sql] val ZERO = Decimal(0)
private[sql] val ONE = Decimal(1)

private val LONG_MAX_BIG_INT = BigInteger.valueOf(JLong.MAX_VALUE)
private val LONG_MIN_BIG_INT = BigInteger.valueOf(JLong.MIN_VALUE)

def apply(value: Double): Decimal = new Decimal().set(value)

def apply(value: Long): Decimal = new Decimal().set(value)
Expand Down