Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -543,11 +543,14 @@ object TypeCoercion {
// Decimal and Double remain the same
case d: Divide if d.dataType == DoubleType => d
case d: Divide if d.dataType.isInstanceOf[DecimalType] => d
case Divide(left, right) if isNumeric(left) && isNumeric(right) =>
case Divide(left, right) if isNumericOrNull(left) && isNumericOrNull(right) =>
Divide(Cast(left, DoubleType), Cast(right, DoubleType))
}

private def isNumeric(ex: Expression): Boolean = ex.dataType.isInstanceOf[NumericType]
private def isNumericOrNull(ex: Expression): Boolean = {
// We need to handle null types in case a query contains null literals.
ex.dataType.isInstanceOf[NumericType] || ex.dataType == NullType
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package org.apache.spark.sql.catalyst.analysis

import java.sql.Timestamp

import org.apache.spark.sql.catalyst.analysis.TypeCoercion.{Division, FunctionArgumentConversion}
import org.apache.spark.sql.catalyst.analysis.TypeCoercion._
import org.apache.spark.sql.catalyst.dsl.expressions._
import org.apache.spark.sql.catalyst.expressions._
import org.apache.spark.sql.catalyst.plans.PlanTest
Expand Down Expand Up @@ -730,6 +730,13 @@ class TypeCoercionSuite extends PlanTest {
// the right expression to Decimal.
ruleTest(rules, sum(Divide(Decimal(4.0), 3)), sum(Divide(Decimal(4.0), 3)))
}

test("SPARK-17117 null type coercion in divide") {
val rules = Seq(FunctionArgumentConversion, Division, ImplicitTypeCasts)
val nullLit = Literal.create(null, NullType)
ruleTest(rules, Divide(1L, nullLit), Divide(Cast(1L, DoubleType), Cast(nullLit, DoubleType)))
ruleTest(rules, Divide(nullLit, 1L), Divide(Cast(nullLit, DoubleType), Cast(1L, DoubleType)))
}
}


Expand Down
12 changes: 10 additions & 2 deletions sql/core/src/test/resources/sql-tests/inputs/arithmetic.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ select + + 100;
select - - max(key) from testdata;
select + - key from testdata where key = 33;

-- div
select 5 / 2;
select 5 / 0;
select 5 / null;
select null / 5;
select 5 div 2;
select 5 div 0;
select 5 div null;
select null div 5;

-- other arithmetics
select 1 + 2;
select 1 - 2;
select 2 * 5;
select 5 / 2;
select 5 div 2;
select 5 % 3;
select pmod(-7, 3);
84 changes: 66 additions & 18 deletions sql/core/src/test/resources/sql-tests/results/arithmetic.sql.out
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 22
-- Number of queries: 28


-- !query 0
Expand Down Expand Up @@ -123,35 +123,35 @@ struct<(- key):int>


-- !query 15
select 1 + 2
select 5 / 2
-- !query 15 schema
struct<(1 + 2):int>
struct<(CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)):double>
-- !query 15 output
3
2.5


-- !query 16
select 1 - 2
select 5 / 0
-- !query 16 schema
struct<(1 - 2):int>
struct<(CAST(5 AS DOUBLE) / CAST(0 AS DOUBLE)):double>
-- !query 16 output
-1
NULL


-- !query 17
select 2 * 5
select 5 / null
-- !query 17 schema
struct<(2 * 5):int>
struct<(CAST(5 AS DOUBLE) / CAST(NULL AS DOUBLE)):double>
-- !query 17 output
10
NULL


-- !query 18
select 5 / 2
select null / 5
-- !query 18 schema
struct<(CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)):double>
struct<(CAST(NULL AS DOUBLE) / CAST(5 AS DOUBLE)):double>
-- !query 18 output
2.5
NULL


-- !query 19
Expand All @@ -163,16 +163,64 @@ struct<CAST((CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)) AS BIGINT):bigint>


-- !query 20
select 5 % 3
select 5 div 0
-- !query 20 schema
struct<(5 % 3):int>
struct<CAST((CAST(5 AS DOUBLE) / CAST(0 AS DOUBLE)) AS BIGINT):bigint>
-- !query 20 output
2
NULL


-- !query 21
select pmod(-7, 3)
select 5 div null
-- !query 21 schema
struct<pmod(-7, 3):int>
struct<CAST((CAST(5 AS DOUBLE) / CAST(NULL AS DOUBLE)) AS BIGINT):bigint>
-- !query 21 output
NULL


-- !query 22
select null div 5
-- !query 22 schema
struct<CAST((CAST(NULL AS DOUBLE) / CAST(5 AS DOUBLE)) AS BIGINT):bigint>
-- !query 22 output
NULL


-- !query 23
select 1 + 2
-- !query 23 schema
struct<(1 + 2):int>
-- !query 23 output
3


-- !query 24
select 1 - 2
-- !query 24 schema
struct<(1 - 2):int>
-- !query 24 output
-1


-- !query 25
select 2 * 5
-- !query 25 schema
struct<(2 * 5):int>
-- !query 25 output
10


-- !query 26
select 5 % 3
-- !query 26 schema
struct<(5 % 3):int>
-- !query 26 output
2


-- !query 27
select pmod(-7, 3)
-- !query 27 schema
struct<pmod(-7, 3):int>
-- !query 27 output
2