diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala index 078f1d1941..a0a13e70da 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala @@ -879,8 +879,12 @@ object TypeCoercion { case e if !e.childrenResolved => e // If DecimalType operands are involved, DecimalPrecision will handle it + // If CalendarIntervalType operands are involved, DateTimeOperations will handle it case b @ BinaryOperator(left, right) if !left.dataType.isInstanceOf[DecimalType] && - !right.dataType.isInstanceOf[DecimalType] && left.dataType != right.dataType => + !right.dataType.isInstanceOf[DecimalType] && + !left.dataType.isInstanceOf[CalendarIntervalType] && + !right.dataType.isInstanceOf[CalendarIntervalType] && + left.dataType != right.dataType => findTightestCommonType(left.dataType, right.dataType).map { commonType => if (b.inputType.acceptsType(commonType)) { // If the expression accepts the tightest common type, cast to that. diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala index 1f63f1e14b..b0e288a102 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/IntervalUtils.scala @@ -386,6 +386,7 @@ object IntervalUtils { } def divide(interval: CalendarInterval, num: Double): CalendarInterval = { + if (num == 0) throw new java.lang.ArithmeticException("divide by zero") fromDoubles(interval.months / num, interval.days / num, interval.microseconds / num) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/IntervalExpressionsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/IntervalExpressionsSuite.scala index d0610e7260..f776546e33 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/IntervalExpressionsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/IntervalExpressionsSuite.scala @@ -224,6 +224,6 @@ class IntervalExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper { check("2 years -8 seconds", 0.5, "4 years -16 seconds") check("-1 month 2 microseconds", -0.25, "4 months -8 microseconds") check("1 month 3 microsecond", 1.5, "20 days 2 microseconds") - check("2 months", 0, null) + check("1 second", 0, null) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala index 7015475c4b..2c0e6a9b94 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala @@ -222,7 +222,7 @@ class IntervalUtilsSuite extends SparkFunSuite { fail("Expected to throw an exception on divide by zero") } catch { case e: ArithmeticException => - assert(e.getMessage.contains("overflow")) + assert(e.getMessage.contains("divide by zero")) } } } diff --git a/sql/core/src/test/resources/sql-tests/inputs/datetime.sql b/sql/core/src/test/resources/sql-tests/inputs/datetime.sql index 8aa173d4db..09eb185bd4 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/datetime.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/datetime.sql @@ -41,3 +41,9 @@ select timestamp'2019-10-06 10:11:12.345678' - date'2020-01-01'; select 3 * (timestamp'2019-10-15 10:11:12.001002' - date'2019-10-15'); select interval 4 month 2 weeks 3 microseconds * 1.5; select (timestamp'2019-10-15' - timestamp'2019-10-14') / 1.5; + +-- interval operation with null and zero case +select interval '2 seconds' / 0; +select interval '2 seconds' / null; +select interval '2 seconds' * null; +select null * interval '2 seconds'; diff --git a/sql/core/src/test/resources/sql-tests/results/datetime.sql.out b/sql/core/src/test/resources/sql-tests/results/datetime.sql.out index 781db39b87..d003854570 100644 --- a/sql/core/src/test/resources/sql-tests/results/datetime.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/datetime.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 20 +-- Number of queries: 24 -- !query 0 @@ -169,3 +169,35 @@ select (timestamp'2019-10-15' - timestamp'2019-10-14') / 1.5 struct -- !query 19 output interval 16 hours + + +-- !query 20 +select interval '2 seconds' / 0 +-- !query 20 schema +struct +-- !query 20 output +NULL + + +-- !query 21 +select interval '2 seconds' / null +-- !query 21 schema +struct +-- !query 21 output +NULL + + +-- !query 22 +select interval '2 seconds' * null +-- !query 22 schema +struct +-- !query 22 output +NULL + + +-- !query 23 +select null * interval '2 seconds' +-- !query 23 schema +struct +-- !query 23 output +NULL