From 3c9eef35a85fd841efb4491b299345a2edf30e87 Mon Sep 17 00:00:00 2001
From: caoxuewen <cao.xuewen@zte.com.cn>
Date: Sun, 21 May 2017 22:39:07 -0700
Subject: [PATCH] [SPARK-20786][SQL] Improve ceil and floor handle the value
 which is not expected

## What changes were proposed in this pull request?

spark-sql>SELECT ceil(1234567890123456);
1234567890123456

spark-sql>SELECT ceil(12345678901234567);
12345678901234568

spark-sql>SELECT ceil(123456789012345678);
123456789012345680

when the length of the getText is greater than 16. long to double will be precision loss.

but mysql handle the value is ok.

mysql> SELECT ceil(1234567890123456);
+------------------------+
| ceil(1234567890123456) |
+------------------------+
|       1234567890123456 |
+------------------------+
1 row in set (0.00 sec)

mysql> SELECT ceil(12345678901234567);
+-------------------------+
| ceil(12345678901234567) |
+-------------------------+
|       12345678901234567 |
+-------------------------+
1 row in set (0.00 sec)

mysql> SELECT ceil(123456789012345678);
+--------------------------+
| ceil(123456789012345678) |
+--------------------------+
|       123456789012345678 |
+--------------------------+
1 row in set (0.00 sec)

## How was this patch tested?

Supplement the unit test.

Author: caoxuewen <cao.xuewen@zte.com.cn>

Closes #18016 from heary-cao/ceil_long.
---
 .../expressions/mathExpressions.scala         |  6 +-
 .../sql/catalyst/analysis/AnalysisSuite.scala |  2 +-
 .../resources/sql-tests/inputs/operators.sql  | 14 ++++
 .../sql-tests/results/operators.sql.out       | 80 +++++++++++++++++++
 4 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
index a7bf81e98b..bf46a39862 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
@@ -232,9 +232,10 @@ case class Ceil(child: Expression) extends UnaryMathExpression(math.ceil, "CEIL"
   }
 
   override def inputTypes: Seq[AbstractDataType] =
-    Seq(TypeCollection(DoubleType, DecimalType))
+    Seq(TypeCollection(LongType, DoubleType, DecimalType))
 
   protected override def nullSafeEval(input: Any): Any = child.dataType match {
+    case LongType => input.asInstanceOf[Long]
     case DoubleType => f(input.asInstanceOf[Double]).toLong
     case DecimalType.Fixed(precision, scale) => input.asInstanceOf[Decimal].ceil
   }
@@ -347,9 +348,10 @@ case class Floor(child: Expression) extends UnaryMathExpression(math.floor, "FLO
   }
 
   override def inputTypes: Seq[AbstractDataType] =
-    Seq(TypeCollection(DoubleType, DecimalType))
+    Seq(TypeCollection(LongType, DoubleType, DecimalType))
 
   protected override def nullSafeEval(input: Any): Any = child.dataType match {
+    case LongType => input.asInstanceOf[Long]
     case DoubleType => f(input.asInstanceOf[Double]).toLong
     case DecimalType.Fixed(precision, scale) => input.asInstanceOf[Decimal].floor
   }
diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala
index 31047f6886..0896caeab8 100644
--- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala
+++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisSuite.scala
@@ -262,7 +262,7 @@ class AnalysisSuite extends AnalysisTest with ShouldMatchers {
 
     val plan = testRelation2.select('c).orderBy(Floor('a).asc)
     val expected = testRelation2.select(c, a)
-      .orderBy(Floor(Cast(a, DoubleType, Option(TimeZone.getDefault().getID))).asc).select(c)
+      .orderBy(Floor(Cast(a, LongType, Option(TimeZone.getDefault().getID))).asc).select(c)
 
     checkAnalysis(plan, expected)
   }
diff --git a/sql/core/src/test/resources/sql-tests/inputs/operators.sql b/sql/core/src/test/resources/sql-tests/inputs/operators.sql
index 1920a108c6..f7167472b0 100644
--- a/sql/core/src/test/resources/sql-tests/inputs/operators.sql
+++ b/sql/core/src/test/resources/sql-tests/inputs/operators.sql
@@ -59,3 +59,17 @@ select cot(1);
 select cot(null);
 select cot(0);
 select cot(-1);
+
+-- ceil and ceiling
+select ceiling(0);
+select ceiling(1);
+select ceil(1234567890123456);
+select ceil(12345678901234567);
+select ceiling(1234567890123456);
+select ceiling(12345678901234567);
+
+-- floor
+select floor(0);
+select floor(1);
+select floor(1234567890123456);
+select floor(12345678901234567);
diff --git a/sql/core/src/test/resources/sql-tests/results/operators.sql.out b/sql/core/src/test/resources/sql-tests/results/operators.sql.out
index abd18211c7..fe52005aa9 100644
--- a/sql/core/src/test/resources/sql-tests/results/operators.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/operators.sql.out
@@ -316,3 +316,83 @@ select cot(-1)
 struct<COT(CAST(-1 AS DOUBLE)):double>
 -- !query 37 output
 -0.6420926159343306
+
+
+-- !query 38
+select ceiling(0)
+-- !query 38 schema
+struct<CEIL(CAST(0 AS BIGINT)):bigint>
+-- !query 38 output
+0
+
+
+-- !query 39
+select ceiling(1)
+-- !query 39 schema
+struct<CEIL(CAST(1 AS BIGINT)):bigint>
+-- !query 39 output
+1
+
+
+-- !query 40
+select ceil(1234567890123456)
+-- !query 40 schema
+struct<CEIL(1234567890123456):bigint>
+-- !query 40 output
+1234567890123456
+
+
+-- !query 41
+select ceil(12345678901234567)
+-- !query 41 schema
+struct<CEIL(12345678901234567):bigint>
+-- !query 41 output
+12345678901234567
+
+
+-- !query 42
+select ceiling(1234567890123456)
+-- !query 42 schema
+struct<CEIL(1234567890123456):bigint>
+-- !query 42 output
+1234567890123456
+
+
+-- !query 43
+select ceiling(12345678901234567)
+-- !query 43 schema
+struct<CEIL(12345678901234567):bigint>
+-- !query 43 output
+12345678901234567
+
+
+-- !query 44
+select floor(0)
+-- !query 44 schema
+struct<FLOOR(CAST(0 AS BIGINT)):bigint>
+-- !query 44 output
+0
+
+
+-- !query 45
+select floor(1)
+-- !query 45 schema
+struct<FLOOR(CAST(1 AS BIGINT)):bigint>
+-- !query 45 output
+1
+
+
+-- !query 46
+select floor(1234567890123456)
+-- !query 46 schema
+struct<FLOOR(1234567890123456):bigint>
+-- !query 46 output
+1234567890123456
+
+
+-- !query 47
+select floor(12345678901234567)
+-- !query 47 schema
+struct<FLOOR(12345678901234567):bigint>
+-- !query 47 output
+12345678901234567
-- 
GitLab