Repository: incubator-livy Updated Branches: refs/heads/branch-0.5 4783fbc25 -> 88d66a95f
[LIVY-455][REPL] Fix json4s doesn't support java.math.BigDecimal issue ## What changes were proposed in this pull request? Livy's SQLInterpreter will throw exception when rows contain java.math.BigDecimal data. This is because current version of json4s doesn't treat java.math.BigDecimal type as primitive type. On the contrary, json4s supports Scala BigDecimal as primitive type. So the fix is to convert java BigDecimal to Scala BigDecimal. ## How was this patch tested? Unit test is added. Author: jerryshao <ss...@hortonworks.com> Closes #85 from jerryshao/LIVY-455. (cherry picked from commit 7e4bb3bd6888742e43aed7396ed490d343a063a2) Signed-off-by: jerryshao <ss...@hortonworks.com> Project: http://git-wip-us.apache.org/repos/asf/incubator-livy/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-livy/commit/88d66a95 Tree: http://git-wip-us.apache.org/repos/asf/incubator-livy/tree/88d66a95 Diff: http://git-wip-us.apache.org/repos/asf/incubator-livy/diff/88d66a95 Branch: refs/heads/branch-0.5 Commit: 88d66a95fb6737a1e3bdeed34138e16f64fc23af Parents: 4783fbc Author: jerryshao <ss...@hortonworks.com> Authored: Wed Apr 11 10:24:20 2018 +0800 Committer: jerryshao <ss...@hortonworks.com> Committed: Wed Apr 11 10:24:31 2018 +0800 ---------------------------------------------------------------------- .../org/apache/livy/repl/SQLInterpreter.scala | 10 +++++- .../apache/livy/repl/SQLInterpreterSpec.scala | 36 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/88d66a95/repl/src/main/scala/org/apache/livy/repl/SQLInterpreter.scala ---------------------------------------------------------------------- diff --git a/repl/src/main/scala/org/apache/livy/repl/SQLInterpreter.scala b/repl/src/main/scala/org/apache/livy/repl/SQLInterpreter.scala index a98223e..afef09b 100644 --- a/repl/src/main/scala/org/apache/livy/repl/SQLInterpreter.scala +++ b/repl/src/main/scala/org/apache/livy/repl/SQLInterpreter.scala @@ -97,7 +97,15 @@ class SQLInterpreter( val rows = result.getClass.getMethod("take", classOf[Int]) .invoke(result, maxResult: java.lang.Integer) .asInstanceOf[Array[Row]] - .map(_.toSeq) + .map { + _.toSeq.map { + // Convert java BigDecimal type to Scala BigDecimal, because current version of + // Json4s doesn't support java BigDecimal as a primitive type (LIVY-455). + case i: java.math.BigDecimal => BigDecimal(i) + case e => e + } + } + val jRows = Extraction.decompose(rows) Interpreter.ExecuteSuccess( http://git-wip-us.apache.org/repos/asf/incubator-livy/blob/88d66a95/repl/src/test/scala/org/apache/livy/repl/SQLInterpreterSpec.scala ---------------------------------------------------------------------- diff --git a/repl/src/test/scala/org/apache/livy/repl/SQLInterpreterSpec.scala b/repl/src/test/scala/org/apache/livy/repl/SQLInterpreterSpec.scala index 58e89ee..d2c12eb 100644 --- a/repl/src/test/scala/org/apache/livy/repl/SQLInterpreterSpec.scala +++ b/repl/src/test/scala/org/apache/livy/repl/SQLInterpreterSpec.scala @@ -95,6 +95,42 @@ class SQLInterpreterSpec extends BaseInterpreterSpec { )) } + it should "handle java BigDecimal" in withInterpreter { interpreter => + val rdd = sparkEntries.sc().parallelize(Seq( + ("1", new java.math.BigDecimal(1.0)), + ("2", new java.math.BigDecimal(2.0)))) + val df = sparkEntries.sqlctx().createDataFrame(rdd).selectExpr("_1 as col1", "_2 as col2") + df.registerTempTable("test") + + val resp1 = interpreter.execute( + """ + |SELECT * FROM test + """.stripMargin) + + val expectedResult = (nullable: Boolean) => { + Interpreter.ExecuteSuccess( + APPLICATION_JSON -> (("schema" -> + (("type" -> "struct") ~ + ("fields" -> List( + ("name" -> "col1") ~ ("type" -> "string") ~ ("nullable" -> true) ~ + ("metadata" -> List()), + ("name" -> "col2") ~ ("type" -> "decimal(38,18)") ~ ("nullable" -> nullable) ~ + ("metadata" -> List()) + )))) ~ + ("data" -> List( + List[JValue]("1", 1.0d), + List[JValue]("2", 2.0d) + ))) + ) + } + + val result = Try { resp1 should equal(expectedResult(false))} + .orElse(Try { resp1 should equal(expectedResult(true)) }) + if (result.isFailure) { + fail(s"$resp1 doesn't equal to expected result") + } + } + it should "throw exception for illegal query" in withInterpreter { interpreter => val resp = interpreter.execute( """