Skip to content

Commit ffef5a0

Browse files
committed
Fix an edge case with Round function when the scaled number exceeds Double.MAX_VALUE
1 parent 488c597 commit ffef5a0

File tree

2 files changed

+26
-0
lines changed

2 files changed

+26
-0
lines changed

core/trino-main/src/main/java/io/trino/operator/scalar/MathFunctions.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,13 @@ public static double round(@SqlType(StandardTypes.DOUBLE) double num, @SqlType(S
837837
if (rescaledRound != Long.MAX_VALUE) {
838838
return sign * (rescaledRound / factor);
839839
}
840+
if (Double.isInfinite(rescaled)) {
841+
// num has max 17 precisions, so to make round actually do something, decimals must be smaller than 17.
842+
// then factor must be smaller than 10^17
843+
// then in order for rescaled to be greater than Double.MAX_VALUE, num must be greater than 1.8E291 with many trailing zeros
844+
// in which case, rounding is no op anyway
845+
return num;
846+
}
840847
return sign * DoubleMath.roundToBigInteger(rescaled, RoundingMode.HALF_UP).doubleValue() / factor;
841848
}
842849

@@ -858,6 +865,11 @@ public static long roundReal(@SqlType(StandardTypes.REAL) long num, @SqlType(Sta
858865
if (rescaledRound != Long.MAX_VALUE) {
859866
result = sign * (rescaledRound / factor);
860867
}
868+
else if (Double.isInfinite(rescaled)) {
869+
// numInFloat is max at 3.4028235e+38f, to make rescale greater than Double.MAX_VALUE, decimals must be greater than 270
870+
// but numInFloat has max 8 precision, so rounding is no op
871+
return num;
872+
}
861873
else {
862874
result = sign * (DoubleMath.roundToBigInteger(rescaled, RoundingMode.HALF_UP).doubleValue() / factor);
863875
}

core/trino-main/src/test/java/io/trino/operator/scalar/TestMathFunctions.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,13 @@ public void testRound()
16581658
assertThat(assertions.function("round", "DOUBLE '3000.1234567890123456789'", "16"))
16591659
.isEqualTo(3000.1234567890124);
16601660

1661+
// 1.8E292*10^16 is infinity.
1662+
assertThat(assertions.function("round", "DOUBLE '1.8E292'", "16"))
1663+
.isEqualTo(1.8E292);
1664+
1665+
assertThat(assertions.function("round", "DOUBLE '-1.8E292'", "16"))
1666+
.isEqualTo(-1.8E292);
1667+
16611668
assertThat(assertions.function("round", "TINYINT '3'", "TINYINT '1'"))
16621669
.isEqualTo((byte) 3);
16631670

@@ -1702,6 +1709,13 @@ public void testRound()
17021709
assertThat(assertions.function("round", "REAL '3000.1234567890123456789'", "16"))
17031710
.isEqualTo(3000.1235f);
17041711

1712+
// 3.4028235e+38 * 10 ^ 271 is infinity
1713+
assertThat(assertions.function("round", "REAL '3.4028235e+38'", "271"))
1714+
.isEqualTo(3.4028235e+38f);
1715+
1716+
assertThat(assertions.function("round", "REAL '-3.4028235e+38'", "271"))
1717+
.isEqualTo(-3.4028235e+38f);
1718+
17051719
assertThat(assertions.function("round", "3", "1"))
17061720
.isEqualTo(3);
17071721

0 commit comments

Comments
 (0)