Skip to content

Commit 7c6a2a6

Browse files
authored
SQL: Add range checks to interval multiplication operation (#83478)
This adds checks on the multiplication operation on intervals (with integer).
1 parent 221ab4b commit 7c6a2a6

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

docs/changelog/83478.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 83478
2+
summary: Add range checks to interval multiplication operation
3+
area: SQL
4+
type: bug
5+
issues:
6+
- 83336

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/SqlBinaryArithmeticOperation.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.time.temporal.Temporal;
2525
import java.util.function.BiFunction;
2626

27+
import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToLong;
28+
2729
public enum SqlBinaryArithmeticOperation implements BinaryArithmeticOperation {
2830

2931
ADD((Object l, Object r) -> {
@@ -85,17 +87,17 @@ public enum SqlBinaryArithmeticOperation implements BinaryArithmeticOperation {
8587
if (l instanceof Number && r instanceof Number) {
8688
return Arithmetics.mul((Number) l, (Number) r);
8789
}
88-
if (l instanceof Number && r instanceof IntervalYearMonth) {
89-
return ((IntervalYearMonth) r).mul(((Number) l).intValue());
90+
if (l instanceof Number number && r instanceof IntervalYearMonth) {
91+
return ((IntervalYearMonth) r).mul(safeToLong(number));
9092
}
91-
if (r instanceof Number && l instanceof IntervalYearMonth) {
92-
return ((IntervalYearMonth) l).mul(((Number) r).intValue());
93+
if (r instanceof Number number && l instanceof IntervalYearMonth) {
94+
return ((IntervalYearMonth) l).mul(safeToLong(number));
9395
}
94-
if (l instanceof Number && r instanceof IntervalDayTime) {
95-
return ((IntervalDayTime) r).mul(((Number) l).longValue());
96+
if (l instanceof Number number && r instanceof IntervalDayTime) {
97+
return ((IntervalDayTime) r).mul(safeToLong(number));
9698
}
97-
if (r instanceof Number && l instanceof IntervalDayTime) {
98-
return ((IntervalDayTime) l).mul(((Number) r).longValue());
99+
if (r instanceof Number number && l instanceof IntervalDayTime) {
100+
return ((IntervalDayTime) l).mul(safeToLong(number));
99101
}
100102

101103
throw new QlIllegalArgumentException(

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/SqlBinaryArithmeticTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import static org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics.mod;
2626
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
27+
import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX;
2728
import static org.elasticsearch.xpack.sql.type.SqlDataTypes.INTERVAL_DAY;
2829
import static org.elasticsearch.xpack.sql.type.SqlDataTypes.INTERVAL_DAY_TO_HOUR;
2930
import static org.elasticsearch.xpack.sql.type.SqlDataTypes.INTERVAL_HOUR;
@@ -243,6 +244,36 @@ public void testMulNullInterval() {
243244
assertEquals(INTERVAL_MONTH, result.dataType());
244245
}
245246

247+
public void testMulIntegerIntervalYearMonthOverflow() {
248+
Literal l = interval(Period.ofYears(1).plusMonths(11), INTERVAL_YEAR);
249+
ArithmeticException expect = expectThrows(ArithmeticException.class, () -> mul(l, L(Integer.MAX_VALUE)));
250+
assertEquals("integer overflow", expect.getMessage());
251+
}
252+
253+
public void testMulLongIntervalYearMonthOverflow() {
254+
Literal l = interval(Period.ofYears(1), INTERVAL_YEAR);
255+
QlIllegalArgumentException expect = expectThrows(QlIllegalArgumentException.class, () -> mul(l, L(Long.MAX_VALUE)));
256+
assertEquals("[9223372036854775807] out of [integer] range", expect.getMessage());
257+
}
258+
259+
public void testMulUnsignedLongIntervalYearMonthOverflow() {
260+
Literal l = interval(Period.ofYears(1), INTERVAL_YEAR);
261+
QlIllegalArgumentException expect = expectThrows(QlIllegalArgumentException.class, () -> mul(l, L(UNSIGNED_LONG_MAX)));
262+
assertEquals("[18446744073709551615] out of [long] range", expect.getMessage());
263+
}
264+
265+
public void testMulLongIntervalDayTimeOverflow() {
266+
Literal l = interval(Duration.ofDays(1), INTERVAL_DAY);
267+
ArithmeticException expect = expectThrows(ArithmeticException.class, () -> mul(l, L(Long.MAX_VALUE)));
268+
assertEquals("Exceeds capacity of Duration: 796899343984252629724800000000000", expect.getMessage());
269+
}
270+
271+
public void testMulUnsignedLongIntervalDayTimeOverflow() {
272+
Literal l = interval(Duration.ofDays(1), INTERVAL_DAY);
273+
QlIllegalArgumentException expect = expectThrows(QlIllegalArgumentException.class, () -> mul(l, L(UNSIGNED_LONG_MAX)));
274+
assertEquals("[18446744073709551615] out of [long] range", expect.getMessage());
275+
}
276+
246277
public void testAddNullInterval() {
247278
Literal literal = interval(Period.ofMonths(1), INTERVAL_MONTH);
248279
Add result = new Add(EMPTY, L(null), literal);

0 commit comments

Comments
 (0)