Skip to content

Commit 9bf42cb

Browse files
LiBrian415jaystarshot
authored andcommitted
[Presto-Main] Add long overflow checks for IntervalDayTime
1 parent 7882d83 commit 9bf42cb

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

presto-main/src/main/java/com/facebook/presto/type/IntervalDayTimeOperators.java

+59-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.facebook.presto.common.block.Block;
1717
import com.facebook.presto.common.type.AbstractLongType;
1818
import com.facebook.presto.common.type.StandardTypes;
19+
import com.facebook.presto.spi.PrestoException;
1920
import com.facebook.presto.spi.function.BlockIndex;
2021
import com.facebook.presto.spi.function.BlockPosition;
2122
import com.facebook.presto.spi.function.IsNull;
@@ -42,8 +43,11 @@
4243
import static com.facebook.presto.common.function.OperatorType.NEGATION;
4344
import static com.facebook.presto.common.function.OperatorType.NOT_EQUAL;
4445
import static com.facebook.presto.common.function.OperatorType.SUBTRACT;
46+
import static com.facebook.presto.spi.StandardErrorCode.DIVISION_BY_ZERO;
47+
import static com.facebook.presto.spi.StandardErrorCode.NUMERIC_VALUE_OUT_OF_RANGE;
4548
import static com.facebook.presto.type.IntervalDayTimeType.INTERVAL_DAY_TIME;
4649
import static io.airlift.slice.Slices.utf8Slice;
50+
import static java.lang.String.format;
4751

4852
public final class IntervalDayTimeOperators
4953
{
@@ -55,56 +59,103 @@ private IntervalDayTimeOperators()
5559
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
5660
public static long add(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long left, @SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long right)
5761
{
58-
return left + right;
62+
try {
63+
return Math.addExact(left, right);
64+
}
65+
catch (ArithmeticException e) {
66+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second addition overflow: %s ms + %s ms", left, right), e);
67+
}
5968
}
6069

6170
@ScalarOperator(SUBTRACT)
6271
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
6372
public static long subtract(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long left, @SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long right)
6473
{
65-
return left - right;
74+
try {
75+
return Math.subtractExact(left, right);
76+
}
77+
catch (ArithmeticException e) {
78+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second subtraction overflow: %s ms - %s ms", left, right), e);
79+
}
6680
}
6781

6882
@ScalarOperator(MULTIPLY)
6983
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
7084
public static long multiplyByBigint(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long left, @SqlType(StandardTypes.BIGINT) long right)
7185
{
72-
return left * right;
86+
try {
87+
return Math.multiplyExact(left, right);
88+
}
89+
catch (ArithmeticException e) {
90+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second multiply overflow: %s ms * %s", left, right), e);
91+
}
7392
}
7493

7594
@ScalarOperator(MULTIPLY)
7695
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
7796
public static long multiplyByDouble(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long left, @SqlType(StandardTypes.DOUBLE) double right)
7897
{
79-
return (long) (left * right);
98+
try {
99+
return Math.addExact(
100+
(long) (left * (right - (long) right)),
101+
Math.multiplyExact(left, (long) right));
102+
}
103+
catch (ArithmeticException e) {
104+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second multiply overflow: %s ms * %s", left, right), e);
105+
}
80106
}
81107

82108
@ScalarOperator(MULTIPLY)
83109
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
84110
public static long bigintMultiply(@SqlType(StandardTypes.BIGINT) long left, @SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long right)
85111
{
86-
return left * right;
112+
try {
113+
return Math.multiplyExact(left, right);
114+
}
115+
catch (ArithmeticException e) {
116+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second multiply overflow: %s * %s ms", left, right), e);
117+
}
87118
}
88119

89120
@ScalarOperator(MULTIPLY)
90121
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
91122
public static long doubleMultiply(@SqlType(StandardTypes.DOUBLE) double left, @SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long right)
92123
{
93-
return (long) (left * right);
124+
try {
125+
return Math.addExact(
126+
Math.multiplyExact((long) left, right),
127+
(long) ((left - (long) left) * right));
128+
}
129+
catch (ArithmeticException e) {
130+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second multiply overflow: %s * %s ms", left, right), e);
131+
}
94132
}
95133

96134
@ScalarOperator(DIVIDE)
97135
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
98136
public static long divideByDouble(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long left, @SqlType(StandardTypes.DOUBLE) double right)
99137
{
100-
return (long) (left / right);
138+
if (right == 0) {
139+
throw new PrestoException(DIVISION_BY_ZERO, format("interval_day_to_second division by zero: %s ms / %s", left, right));
140+
}
141+
142+
try {
143+
return multiplyByDouble(left, 1.0 / right);
144+
} catch (PrestoException e) {
145+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, format("interval_day_to_second division overflow: %s ms / %s", left, right));
146+
}
101147
}
102148

103149
@ScalarOperator(NEGATION)
104150
@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND)
105151
public static long negate(@SqlType(StandardTypes.INTERVAL_DAY_TO_SECOND) long value)
106152
{
107-
return -value;
153+
try {
154+
return Math.negateExact(value);
155+
}
156+
catch (ArithmeticException e) {
157+
throw new PrestoException(NUMERIC_VALUE_OUT_OF_RANGE, "interval_day_to_second negation overflow: " + value, e);
158+
}
108159
}
109160

110161
@ScalarOperator(EQUAL)

presto-main/src/test/java/com/facebook/presto/type/TestIntervalDayTime.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static com.facebook.presto.common.type.BooleanType.BOOLEAN;
2222
import static com.facebook.presto.common.type.VarcharType.VARCHAR;
2323
import static com.facebook.presto.type.IntervalDayTimeType.INTERVAL_DAY_TIME;
24+
import static java.lang.String.format;
2425
import static java.util.concurrent.TimeUnit.DAYS;
2526
import static org.testng.Assert.assertEquals;
2627

@@ -109,14 +110,14 @@ public void testAdd()
109110
assertFunction("INTERVAL '3' SECOND + INTERVAL '3' SECOND", INTERVAL_DAY_TIME, new SqlIntervalDayTime(6 * 1000));
110111
assertFunction("INTERVAL '6' DAY + INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime(12 * 24 * 60 * 60 * 1000));
111112
assertFunction("INTERVAL '3' SECOND + INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime((6 * 24 * 60 * 60 * 1000) + (3 * 1000)));
113+
assertFunction("INTERVAL '3' DAY + INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime((6 * 24 * 60 * 60 * 1000) + (3 * 1000)));
112114
}
113115

114116
@Test
115117
public void testSubtract()
116118
{
117119
assertFunction("INTERVAL '6' SECOND - INTERVAL '3' SECOND", INTERVAL_DAY_TIME, new SqlIntervalDayTime(3 * 1000));
118120
assertFunction("INTERVAL '9' DAY - INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime(3 * 24 * 60 * 60 * 1000));
119-
assertFunction("INTERVAL '3' SECOND - INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime((3 * 1000) - (6 * 24 * 60 * 60 * 1000)));
120121
}
121122

122123
@Test
@@ -131,6 +132,9 @@ public void testMultiply()
131132
assertFunction("2 * INTERVAL '6' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime(12 * 24 * 60 * 60 * 1000));
132133
assertFunction("INTERVAL '1' DAY * 2.5", INTERVAL_DAY_TIME, new SqlIntervalDayTime((long) (2.5 * 24 * 60 * 60 * 1000)));
133134
assertFunction("2.5 * INTERVAL '1' DAY", INTERVAL_DAY_TIME, new SqlIntervalDayTime((long) (2.5 * 24 * 60 * 60 * 1000)));
135+
assertNumericOverflow(
136+
format("%s * INTERVAL '%s' DAY", Integer.MAX_VALUE, 64),
137+
format("interval_day_to_second multiply overflow: %s * %s ms", Integer.MAX_VALUE, (64 * 24 * 60 * 60 * 1000L)));
134138
}
135139

136140
@Test
@@ -141,6 +145,9 @@ public void testDivide()
141145

142146
assertFunction("INTERVAL '3' DAY / 2", INTERVAL_DAY_TIME, new SqlIntervalDayTime((long) (1.5 * 24 * 60 * 60 * 1000)));
143147
assertFunction("INTERVAL '4' DAY / 2.5", INTERVAL_DAY_TIME, new SqlIntervalDayTime((long) (1.6 * 24 * 60 * 60 * 1000)));
148+
assertNumericOverflow(
149+
format("INTERVAL '%s' DAY / %s", 64, 1 / (double) Integer.MAX_VALUE),
150+
format("interval_day_to_second division overflow: %s ms / %s", (64 * 24 * 60 * 60 * 1000L), 1 / (double) Integer.MAX_VALUE));
144151
}
145152

146153
@Test

0 commit comments

Comments
 (0)