diff --git a/common/unsafe/src/main/java/org/apache/spark/unsafe/types/CalendarInterval.java b/common/unsafe/src/main/java/org/apache/spark/unsafe/types/CalendarInterval.java index 908ff1983e6be..911c5c7f646f4 100644 --- a/common/unsafe/src/main/java/org/apache/spark/unsafe/types/CalendarInterval.java +++ b/common/unsafe/src/main/java/org/apache/spark/unsafe/types/CalendarInterval.java @@ -49,7 +49,8 @@ private static String unitRegex(String unit) { private static Pattern p = Pattern.compile("interval" + unitRegex("year") + unitRegex("month") + unitRegex("week") + unitRegex("day") + unitRegex("hour") + unitRegex("minute") + - unitRegex("second") + unitRegex("millisecond") + unitRegex("microsecond")); + unitRegex("second") + unitRegex("millisecond") + unitRegex("microsecond"), + Pattern.CASE_INSENSITIVE); private static Pattern yearMonthPattern = Pattern.compile("^(?:['|\"])?([+|-])?(\\d+)-(\\d+)(?:['|\"])?$"); @@ -69,7 +70,7 @@ private static long toLong(String s) { /** * Convert a string to CalendarInterval. Return null if the input string is not a valid interval. - * This method is case-sensitive and all characters in the input string should be in lower case. + * This method is case-insensitive. */ public static CalendarInterval fromString(String s) { if (s == null) { @@ -77,7 +78,7 @@ public static CalendarInterval fromString(String s) { } s = s.trim(); Matcher m = p.matcher(s); - if (!m.matches() || s.equals("interval")) { + if (!m.matches() || s.compareToIgnoreCase("interval") == 0) { return null; } else { long months = toLong(m.group(1)) * 12 + toLong(m.group(2)); @@ -93,8 +94,9 @@ public static CalendarInterval fromString(String s) { } /** - * Convert a string to CalendarInterval. Unlike fromString, this method is case-insensitive and - * will throw IllegalArgumentException when the input string is not a valid interval. + * Convert a string to CalendarInterval. Unlike fromString, this method can handle + * strings without the `interval` prefix and throws IllegalArgumentException + * when the input string is not a valid interval. * * @throws IllegalArgumentException if the string is not a valid internal. */ diff --git a/common/unsafe/src/test/java/org/apache/spark/unsafe/types/CalendarIntervalSuite.java b/common/unsafe/src/test/java/org/apache/spark/unsafe/types/CalendarIntervalSuite.java index c307d74e0ba07..6ccc65f7d1740 100644 --- a/common/unsafe/src/test/java/org/apache/spark/unsafe/types/CalendarIntervalSuite.java +++ b/common/unsafe/src/test/java/org/apache/spark/unsafe/types/CalendarIntervalSuite.java @@ -274,4 +274,26 @@ private static void testSingleUnit(String unit, int number, int months, long mic assertEquals(fromString(input1), result); assertEquals(fromString(input2), result); } + + @Test + public void fromStringCaseSensitivityTest() { + testSingleUnit("YEAR", 3, 36, 0); + testSingleUnit("Month", 3, 3, 0); + testSingleUnit("Week", 3, 0, 3 * MICROS_PER_WEEK); + testSingleUnit("DAY", 3, 0, 3 * MICROS_PER_DAY); + testSingleUnit("HouR", 3, 0, 3 * MICROS_PER_HOUR); + testSingleUnit("MiNuTe", 3, 0, 3 * MICROS_PER_MINUTE); + testSingleUnit("Second", 3, 0, 3 * MICROS_PER_SECOND); + testSingleUnit("MilliSecond", 3, 0, 3 * MICROS_PER_MILLI); + testSingleUnit("MicroSecond", 3, 0, 3); + + String input; + + input = "INTERVAL -5 YEARS 23 MONTHS"; + CalendarInterval result = new CalendarInterval(-5 * 12 + 23, 0); + assertEquals(fromString(input), result); + + assertNull(fromString("INTERVAL")); + assertNull(fromString(" Interval ")); + } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuite.scala index d717647abe665..96ef3a558b85b 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuite.scala @@ -670,6 +670,8 @@ abstract class CastSuiteBase extends SparkFunSuite with ExpressionEvalHelper { new CalendarInterval(15, -3 * CalendarInterval.MICROS_PER_DAY), CalendarIntervalType), StringType), "interval 1 years 3 months -3 days") + checkEvaluation(Cast(Literal("INTERVAL 1 Second 1 microsecond"), CalendarIntervalType), + new CalendarInterval(0, 1000001)) } test("cast string to boolean") {