diff --git a/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java b/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java index d202a5bc4708..45a53a3f8607 100644 --- a/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java +++ b/paimon-common/src/main/java/org/apache/paimon/utils/DateTimeUtils.java @@ -349,15 +349,22 @@ public static Integer parseTime(String v) { + milli; } + /** + * Whether the string is a non-negative decimal integer that fits in an {@code int}. Callers + * hand the string straight to {@link Integer#parseInt}, so the range matters as much as the + * characters. + */ private static boolean isInteger(String s) { - boolean isInt = s.length() > 0; + if (s.isEmpty() || s.length() > 10) { + return false; + } for (int i = 0; i < s.length(); i++) { if (s.charAt(i) < '0' || s.charAt(i) > '9') { - isInt = false; - break; + return false; } } - return isInt; + // ten digits still reach past Integer.MAX_VALUE + return s.length() < 10 || Long.parseLong(s) <= Integer.MAX_VALUE; } private static boolean isIllegalDate(int y, int m, int d) { diff --git a/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java b/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java index 6a0f88a367ff..9d459c7236fc 100644 --- a/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java +++ b/paimon-common/src/test/java/org/apache/paimon/utils/DateTimeUtilsTest.java @@ -33,6 +33,24 @@ /** Test for {@link DateTimeUtils}. */ public class DateTimeUtilsTest { + @Test + public void testParseDateAndTimeOverflowReturnsNull() { + // A component too large for an int is an invalid date or time, not a crash: the + // contract of parseDate/parseTime is null for unparseable input. 2147483648 is + // Integer.MAX_VALUE + 1, the smallest ten-digit value that does not fit. + assertThat(DateTimeUtils.parseDate("2147483648-01-01")).isNull(); + assertThat(DateTimeUtils.parseDate("2147483647-01-01")) + .isNull(); // in range, but not a year + assertThat(DateTimeUtils.parseDate("99999999999-01-01")).isNull(); + assertThat(DateTimeUtils.parseDate("2024-99999999999-01")).isNull(); + assertThat(DateTimeUtils.parseDate("2024-01-99999999999")).isNull(); + assertThat(DateTimeUtils.parseTime("99999999999:00:00")).isNull(); + + // Sanity: valid values still parse. + assertThat(DateTimeUtils.parseDate("2024-01-15")).isNotNull(); + assertThat(DateTimeUtils.parseTime("12:30:00")).isNotNull(); + } + @Test public void testFormatLocalDateTime() { LocalDateTime time = LocalDateTime.of(2023, 8, 30, 12, 30, 59, 999_999_999);