This is an automated email from the ASF dual-hosted git repository.

mgaido pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-livy.git


The following commit(s) were added to refs/heads/master by this push:
     new 7847c3f  [LIVY-699][THRIFT] Fix resultSet.getBigDecimal throw 
java.sql.SQLException: Illegal conversion
7847c3f is described below

commit 7847c3fe8309dfd2d2089dac68044603745a3499
Author: runzhiwang <runzhiw...@tencent.com>
AuthorDate: Tue Nov 12 11:26:48 2019 +0100

    [LIVY-699][THRIFT] Fix resultSet.getBigDecimal throw java.sql.SQLException: 
Illegal conversion
    
    ## What changes were proposed in this pull request?
    
    [LIVY-699][THRIFT] Fix resultSet.getBigDecimal throw java.sql.SQLException: 
Illegal conversion.
    
    Follows are steps to reproduce the problem:
    1. `create table test(id decimal)`.
    2. Then `resultSet.getBigDecimal(1)` will throw:` java.sql.SQLException: 
Illegal conversion`. The reason is 
`getSchema().getColumnDescriptorAt(columnIndex - 1).getType();` at 
https://github.com/apache/hive/blob/master/jdbc/src/java/org/apache/hive/jdbc/HiveBaseResultSet.java#L415
 return string, so cannot pass the check `val instanceof BigDecimal `at 
https://github.com/apache/hive/blob/master/jdbc/src/java/org/apache/hive/jdbc/HiveBaseResultSet.java#L133,
 so throw `java.sql.SQLExceptio [...]
    3. So the root cause is the error return of `getType()`, which should 
return decimal other than string.
    4. Regarding to date and timestamp, though the return type is string, 
hive-jdbc has done the transformation from string to date and timestamp in the 
following links. But I think it is necessary to return the right type.
    
https://github.com/apache/hive/blob/master/jdbc/src/java/org/apache/hive/jdbc/HiveBaseResultSet.java#L255
    
https://github.com/apache/hive/blob/master/jdbc/src/java/org/apache/hive/jdbc/HiveBaseResultSet.java#L571
    
    Additionally, SparkThrift return decimal type instead of string in the same 
case, if user use `getBigDecimal` and migrate from SparkThrift to Livy, it will 
throw exception. So it is necessary to return decimal instead of string in livy.
    
    ## How was this patch tested?
    
    Add `SchemaIT.scala` to test the return of column type.
    
    Author: runzhiwang <runzhiw...@tencent.com>
    
    Closes #247 from runzhiwang/support-type.
---
 .../apache/livy/thriftserver/types/Schema.scala    |   6 +
 .../livy/thriftserver/ThriftServerSuites.scala     | 134 ++++++++++++++++++---
 .../apache/livy/thriftserver/session/DataType.java |   3 +
 3 files changed, 126 insertions(+), 17 deletions(-)

diff --git 
a/thriftserver/server/src/main/scala/org/apache/livy/thriftserver/types/Schema.scala
 
b/thriftserver/server/src/main/scala/org/apache/livy/thriftserver/types/Schema.scala
index 6e06474..0f4c642 100644
--- 
a/thriftserver/server/src/main/scala/org/apache/livy/thriftserver/types/Schema.scala
+++ 
b/thriftserver/server/src/main/scala/org/apache/livy/thriftserver/types/Schema.scala
@@ -41,6 +41,9 @@ case class BasicDataType(name: String) extends FieldType {
     case "float" => DataType.FLOAT
     case "double" => DataType.DOUBLE
     case "binary" => DataType.BINARY
+    case _ if name.contains("decimal") => DataType.DECIMAL
+    case "timestamp" => DataType.TIMESTAMP
+    case "date" => DataType.DATE
     case _ => DataType.STRING
   }
 }
@@ -100,6 +103,9 @@ object Schema {
       case DataType.FLOAT => TTypeId.FLOAT_TYPE
       case DataType.DOUBLE => TTypeId.DOUBLE_TYPE
       case DataType.BINARY => TTypeId.BINARY_TYPE
+      case DataType.DECIMAL => TTypeId.DECIMAL_TYPE
+      case DataType.TIMESTAMP => TTypeId.TIMESTAMP_TYPE
+      case DataType.DATE => TTypeId.DATE_TYPE
       case _ => TTypeId.STRING_TYPE
     }
     val primitiveEntry = new TPrimitiveTypeEntry(typeId)
diff --git 
a/thriftserver/server/src/test/scala/org/apache/livy/thriftserver/ThriftServerSuites.scala
 
b/thriftserver/server/src/test/scala/org/apache/livy/thriftserver/ThriftServerSuites.scala
index 1939a56..19abb0d 100644
--- 
a/thriftserver/server/src/test/scala/org/apache/livy/thriftserver/ThriftServerSuites.scala
+++ 
b/thriftserver/server/src/test/scala/org/apache/livy/thriftserver/ThriftServerSuites.scala
@@ -17,7 +17,7 @@
 
 package org.apache.livy.thriftserver
 
-import java.sql.{Connection, Date, SQLException, Statement, Types}
+import java.sql.{Connection, Date, SQLException, Statement, Timestamp, Types}
 
 import scala.collection.mutable.ArrayBuffer
 import scala.io.Source
@@ -34,33 +34,133 @@ trait CommonThriftTests {
 
   def dataTypesTest(statement: Statement, mapSupported: Boolean): Unit = {
     val resultSet = statement.executeQuery(
-      "select 1, 'a', cast(null as int), 1.2345, CAST('2018-08-06' as date), " 
+
-        "CAST('123' as BINARY)")
+      "select cast(1 as tinyint)," +
+        "cast(2 as smallint)," +
+        "cast(3 as int)," +
+        "cast(4 as bigint)," +
+        "cast(5.5 as float)," +
+        "cast(6.6 as double)," +
+        "cast(7.7 as decimal(10, 1))," +
+        "cast(true as boolean)," +
+        "cast('123' as binary)," +
+        "cast('string_val' as string)," +
+        "cast('varchar_val' as varchar(20))," +
+        "cast('char_val' as char(20))," +
+        "cast('2018-08-06 09:11:15' as timestamp)," +
+        "cast('2018-08-06' as date)")
+
+    val rsMetaData = resultSet.getMetaData()
+
     resultSet.next()
-    assert(resultSet.getInt(1) == 1)
-    assert(resultSet.getString(2) == "a")
-    assert(resultSet.getInt(3) == 0)
-    assert(resultSet.wasNull())
-    assert(resultSet.getDouble(4) == 1.2345)
-    assert(resultSet.getDate(5) == Date.valueOf("2018-08-06"))
-    val resultBytes = Source.fromInputStream(resultSet.getBinaryStream(6))
+
+    assert(resultSet.getByte(1) == 1)
+    assert(rsMetaData.getColumnTypeName(1) == "tinyint")
+
+    assert(resultSet.getShort(2) == 2)
+    assert(rsMetaData.getColumnTypeName(2) == "smallint")
+
+    assert(resultSet.getInt(3) == 3)
+    assert(rsMetaData.getColumnTypeName(3) == "int")
+
+    assert(resultSet.getLong(4) == 4)
+    assert(rsMetaData.getColumnTypeName(4) == "bigint")
+
+    assert(resultSet.getFloat(5) == 5.5)
+    assert(rsMetaData.getColumnTypeName(5) == "float")
+
+    assert(resultSet.getDouble(6) == 6.6)
+    assert(rsMetaData.getColumnTypeName(6) == "double")
+
+    assert(resultSet.getBigDecimal(7).doubleValue() == 7.7)
+    assert(rsMetaData.getColumnTypeName(7) == "decimal")
+
+    assert(resultSet.getBoolean(8) == true)
+    assert(rsMetaData.getColumnTypeName(8) == "boolean")
+
+    val resultBytes = Source.fromInputStream(resultSet.getBinaryStream(9))
       .map(_.toByte).toArray
     assert("123".getBytes.sameElements(resultBytes))
+    assert(rsMetaData.getColumnTypeName(9) == "binary")
+
+    assert(resultSet.getString(10) == "string_val")
+    assert(rsMetaData.getColumnTypeName(10) == "string")
+
+    assert(resultSet.getString(11) == "varchar_val")
+    assert(rsMetaData.getColumnTypeName(11) == "string")
+
+    assert(resultSet.getString(12) == "char_val")
+    assert(rsMetaData.getColumnTypeName(12) == "string")
+
+    assert(resultSet.getTimestamp(13).
+      compareTo(Timestamp.valueOf("2018-08-06 09:11:15")) == 0)
+    assert(rsMetaData.getColumnTypeName(13) == "timestamp")
+
+    assert(resultSet.getDate(14).
+      compareTo(Date.valueOf("2018-08-06")) == 0)
+    assert(rsMetaData.getColumnTypeName(14) == "date")
+
     assert(!resultSet.next())
 
-    val resultSetWithNulls = statement.executeQuery("select cast(null as 
string), " +
-      "cast(null as decimal), cast(null as double), cast(null as date), null")
+    val resultSetWithNulls = statement.executeQuery(
+      "select cast(null as tinyint), " +
+        "cast(null as smallint)," +
+        "cast(null as int)," +
+        "cast(null as bigint)," +
+        "cast(null as float)," +
+        "cast(null as double)," +
+        "cast(null as decimal)," +
+        "cast(null as boolean)," +
+        "cast(null as binary)," +
+        "cast(null as string)," +
+        "cast(null as varchar(20))," +
+        "cast(null as char(20))," +
+        "cast(null as timestamp)," +
+        "cast(null as date)")
+
     resultSetWithNulls.next()
-    assert(resultSetWithNulls.getString(1) == null)
+
+    assert(resultSetWithNulls.getByte(1) == 0)
     assert(resultSetWithNulls.wasNull())
-    assert(resultSetWithNulls.getBigDecimal(2) == null)
+
+    assert(resultSetWithNulls.getShort(2) == 0)
     assert(resultSetWithNulls.wasNull())
-    assert(resultSetWithNulls.getDouble(3) == 0.0)
+
+    assert(resultSetWithNulls.getInt(3) == 0)
     assert(resultSetWithNulls.wasNull())
-    assert(resultSetWithNulls.getDate(4) == null)
+
+    assert(resultSetWithNulls.getLong(4) == 0)
     assert(resultSetWithNulls.wasNull())
-    assert(resultSetWithNulls.getString(5) == null)
+
+    assert(resultSetWithNulls.getFloat(5) == 0.0)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getDouble(6) == 0.0)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getBigDecimal(7) == null)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getBoolean(8) == false)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getBinaryStream(9) == null)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getString(10) == null)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getString(11) == null)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getString(12) == null)
     assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getTimestamp(13) == null)
+    assert(resultSetWithNulls.wasNull())
+
+    assert(resultSetWithNulls.getDate(14) == null)
+    assert(resultSetWithNulls.wasNull())
+
     assert(!resultSetWithNulls.next())
 
     val complexTypesQuery = if (mapSupported) {
diff --git 
a/thriftserver/session/src/main/java/org/apache/livy/thriftserver/session/DataType.java
 
b/thriftserver/session/src/main/java/org/apache/livy/thriftserver/session/DataType.java
index ab8f665..1812eaf 100644
--- 
a/thriftserver/session/src/main/java/org/apache/livy/thriftserver/session/DataType.java
+++ 
b/thriftserver/session/src/main/java/org/apache/livy/thriftserver/session/DataType.java
@@ -30,6 +30,9 @@ public enum DataType {
   FLOAT,
   DOUBLE,
   BINARY,
+  DECIMAL,
+  TIMESTAMP,
+  DATE,
   STRING;
 
 }

Reply via email to