Skip to content

Commit

Permalink
[SPARK-13056][SQL] map column would throw NPE if value is null
Browse files Browse the repository at this point in the history
Jira:
https://issues.apache.org/jira/browse/SPARK-13056

Create a map like
{ "a": "somestring", "b": null}
Query like
SELECT col["b"] FROM t1;
NPE would be thrown.

Author: Daoyuan Wang <daoyuan.wang@intel.com>

Closes #10964 from adrian-wang/npewriter.
  • Loading branch information
adrian-wang authored and marmbrus committed Feb 2, 2016
1 parent cba1d6b commit 358300c
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ case class GetArrayItem(child: Expression, ordinal: Expression)
protected override def nullSafeEval(value: Any, ordinal: Any): Any = {
val baseValue = value.asInstanceOf[ArrayData]
val index = ordinal.asInstanceOf[Number].intValue()
if (index >= baseValue.numElements() || index < 0) {
if (index >= baseValue.numElements() || index < 0 || baseValue.isNullAt(index)) {
null
} else {
baseValue.get(index, dataType)
Expand Down Expand Up @@ -267,6 +267,7 @@ case class GetMapValue(child: Expression, key: Expression)
val map = value.asInstanceOf[MapData]
val length = map.numElements()
val keys = map.keyArray()
val values = map.valueArray()

var i = 0
var found = false
Expand All @@ -278,10 +279,10 @@ case class GetMapValue(child: Expression, key: Expression)
}
}

if (!found) {
if (!found || values.isNullAt(i)) {
null
} else {
map.valueArray().get(i, dataType)
values.get(i, dataType)
}
}

Expand All @@ -291,10 +292,12 @@ case class GetMapValue(child: Expression, key: Expression)
val keys = ctx.freshName("keys")
val found = ctx.freshName("found")
val key = ctx.freshName("key")
val values = ctx.freshName("values")
nullSafeCodeGen(ctx, ev, (eval1, eval2) => {
s"""
final int $length = $eval1.numElements();
final ArrayData $keys = $eval1.keyArray();
final ArrayData $values = $eval1.valueArray();

int $index = 0;
boolean $found = false;
Expand All @@ -307,10 +310,10 @@ case class GetMapValue(child: Expression, key: Expression)
}
}

if ($found) {
${ev.value} = ${ctx.getValue(eval1 + ".valueArray()", dataType, index)};
} else {
if (!$found || $values.isNullAt($index)) {
${ev.isNull} = true;
} else {
${ev.value} = ${ctx.getValue(values, dataType, index)};
}
"""
})
Expand Down
10 changes: 10 additions & 0 deletions sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,16 @@ class SQLQuerySuite extends QueryTest with SharedSQLContext {
)
}

test("SPARK-13056: Null in map value causes NPE") {
val df = Seq(1 -> Map("abc" -> "somestring", "cba" -> null)).toDF("key", "value")
withTempTable("maptest") {
df.registerTempTable("maptest")
// local optimization will by pass codegen code, so we should keep the filter `key=1`
checkAnswer(sql("SELECT value['abc'] FROM maptest where key = 1"), Row("somestring"))
checkAnswer(sql("SELECT value['cba'] FROM maptest where key = 1"), Row(null))
}
}

test("hash function") {
val df = Seq(1 -> "a", 2 -> "b").toDF("i", "j")
withTempTable("tbl") {
Expand Down

0 comments on commit 358300c

Please sign in to comment.