Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ object MathUtils {
if (r < 0) (r + n) % n else r
}

// Casts a rounded double (the result of Math.ceil/Math.floor) to long, throwing an arithmetic
// overflow error when the value cannot be represented as a long. NaN is passed through to the
// JVM cast (which yields 0), matching the previous behavior. Shared by the eval and codegen
// paths of `Ceil`/`Floor` so the two never diverge.
def doubleToLong(value: Double, context: QueryContext): Long = {
if (!value.isNaN &&
(value < Long.MinValue.toDouble || value >= Long.MaxValue.toDouble)) {
throw ExecutionErrors.arithmeticOverflowError("long overflow", context = context)
}
value.toLong
}

def withOverflow[A](f: => A, hint: String = "", context: QueryContext = null): A = {
try {
f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,34 +252,6 @@ case class Cbrt(child: Expression) extends UnaryMathExpression(math.cbrt, "CBRT"
override protected def withNewChildInternal(newChild: Expression): Cbrt = copy(child = newChild)
}

private object CeilFloor {
def doubleToLong(value: Double, context: QueryContext): Long = {
if (!value.isNaN &&
(value < Long.MinValue.toDouble || value >= Long.MaxValue.toDouble)) {
throw QueryExecutionErrors.arithmeticOverflowError("long overflow", context = context)
}
value.toLong
}

def doubleToLongCode(
input: String,
funcName: String,
result: String,
roundedValue: String,
errorContext: String): String = {
s"""
|double $roundedValue = java.lang.Math.$funcName($input);
|if (!java.lang.Double.isNaN($roundedValue) &&
| ($roundedValue < (double) java.lang.Long.MIN_VALUE ||
| $roundedValue >= (double) java.lang.Long.MAX_VALUE)) {
| throw QueryExecutionErrors.arithmeticOverflowError(
| "long overflow", "", $errorContext);
|}
|$result = (long) $roundedValue;
|""".stripMargin
}
}

case class Ceil(child: Expression, failOnError: Boolean = SQLConf.get.ansiEnabled)
extends UnaryMathExpression(math.ceil, "CEIL") with SupportQueryContext {
override def dataType: DataType = child.dataType match {
Expand All @@ -299,7 +271,7 @@ case class Ceil(child: Expression, failOnError: Boolean = SQLConf.get.ansiEnable
protected override def nullSafeEval(input: Any): Any = child.dataType match {
case LongType => input.asInstanceOf[Long]
case DoubleType if failOnError =>
CeilFloor.doubleToLong(f(input.asInstanceOf[Double]), getContextOrNull())
MathUtils.doubleToLong(f(input.asInstanceOf[Double]), getContextOrNull())
case DoubleType => f(input.asInstanceOf[Double]).toLong
case DecimalType.Fixed(_, _) => input.asInstanceOf[Decimal].ceil
}
Expand All @@ -311,11 +283,9 @@ case class Ceil(child: Expression, failOnError: Boolean = SQLConf.get.ansiEnable
defineCodeGen(ctx, ev, c => s"$c.ceil()")
case LongType => defineCodeGen(ctx, ev, c => s"$c")
case DoubleType if failOnError =>
nullSafeCodeGen(ctx, ev, c => {
val roundedValue = ctx.freshName("roundedValue")
val errorContext = getContextOrNullCode(ctx)
CeilFloor.doubleToLongCode(c, funcName, ev.value, roundedValue, errorContext)
})
val mathUtils = MathUtils.getClass.getCanonicalName.stripSuffix("$")
defineCodeGen(ctx, ev, c =>
s"$mathUtils.doubleToLong(java.lang.Math.$funcName($c), ${getContextOrNullCode(ctx)})")
case _ => defineCodeGen(ctx, ev, c => s"(long)(java.lang.Math.${funcName}($c))")
}
}
Expand Down Expand Up @@ -591,7 +561,7 @@ case class Floor(child: Expression, failOnError: Boolean = SQLConf.get.ansiEnabl
protected override def nullSafeEval(input: Any): Any = child.dataType match {
case LongType => input.asInstanceOf[Long]
case DoubleType if failOnError =>
CeilFloor.doubleToLong(f(input.asInstanceOf[Double]), getContextOrNull())
MathUtils.doubleToLong(f(input.asInstanceOf[Double]), getContextOrNull())
case DoubleType => f(input.asInstanceOf[Double]).toLong
case DecimalType.Fixed(_, _) => input.asInstanceOf[Decimal].floor
}
Expand All @@ -603,11 +573,9 @@ case class Floor(child: Expression, failOnError: Boolean = SQLConf.get.ansiEnabl
defineCodeGen(ctx, ev, c => s"$c.floor()")
case LongType => defineCodeGen(ctx, ev, c => s"$c")
case DoubleType if failOnError =>
nullSafeCodeGen(ctx, ev, c => {
val roundedValue = ctx.freshName("roundedValue")
val errorContext = getContextOrNullCode(ctx)
CeilFloor.doubleToLongCode(c, funcName, ev.value, roundedValue, errorContext)
})
val mathUtils = MathUtils.getClass.getCanonicalName.stripSuffix("$")
defineCodeGen(ctx, ev, c =>
s"$mathUtils.doubleToLong(java.lang.Math.$funcName($c), ${getContextOrNullCode(ctx)})")
case _ => defineCodeGen(ctx, ev, c => s"(long)(java.lang.Math.${funcName}($c))")
}
}
Expand Down