Skip to content

Commit

Permalink
Add function unhex
Browse files Browse the repository at this point in the history
  • Loading branch information
zhichao-li committed Jun 30, 2015
1 parent 6c5a6db commit c852d46
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ object FunctionRegistry {
expression[Substring]("substr"),
expression[Substring]("substring"),
expression[Upper]("ucase"),
expression[UnHex]("unhex"),
expression[Upper]("upper")
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,44 @@ case class Pow(left: Expression, right: Expression)
}
}

/**
* Performs the inverse operation of HEX.
* Resulting characters are returned as a byte array.
*/
case class UnHex(child: Expression)
extends UnaryExpression with ExpectsInputTypes with Serializable {

override def expectedChildTypes: Seq[DataType] = Seq(StringType)

override def dataType: DataType = BinaryType

override def eval(input: InternalRow): Any = {
val num = child.eval(input)
if (num == null) {
null
} else {
unhex(num.asInstanceOf[UTF8String].toString)
}
}

private def unhex(s: String): Array[Byte] = {
// append a leading 0 if needed
val str = if (s.length % 2 == 1) {"0" + s} else {s}
val result = new Array[Byte](str.length / 2)
var i = 0
while (i < str.length()) {
try {
result(i / 2) = Integer.parseInt(str.substring(i, i + 2), 16).asInstanceOf[Byte]
} catch {
// invalid character present, return null
case _: NumberFormatException => return null
}
i += 2
}
result
}
}

case class Hypot(left: Expression, right: Expression)
extends BinaryMathExpression(math.hypot, "HYPOT")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ class MathFunctionsSuite extends SparkFunSuite with ExpressionEvalHelper {
// scalastyle:on
}

test("unhex") {
checkEvaluation(UnHex(Literal("737472696E67")), "string".getBytes)
// scalastyle:off
// Turn off scala style for non-ascii chars
checkEvaluation(UnHex(Literal("E4B889E9878DE79A84")), "三重的".getBytes)
// scalastyle:on
}

test("hypot") {
testBinary(Hypot, math.hypot)
}
Expand Down
18 changes: 18 additions & 0 deletions sql/core/src/main/scala/org/apache/spark/sql/functions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,24 @@ object functions {
*/
def hex(colName: String): Column = hex(Column(colName))

/**
* Inverse of hex. Interprets each pair of characters as a hexadecimal number
* and converts to the byte representation of number.
*
* @group math_funcs
* @since 1.5.0
*/
def unhex(column: Column): Column = UnHex(column.expr)

/**
* Inverse of hex. Interprets each pair of characters as a hexadecimal number
* and converts to the byte representation of number.
*
* @group math_funcs
* @since 1.5.0
*/
def unhex(colName: String): Column = unhex(Column(colName))

/**
* Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ class MathExpressionsSuite extends QueryTest {
checkAnswer(data.selectExpr("hex(cast(d as binary))"), Seq(Row("68656C6C6F")))
}

test("unhex") {
val data = Seq(("1C", "737472696E67")).toDF("a", "b")
checkAnswer(data.select(unhex('a)), Row(Array[Byte](28.toByte)))
checkAnswer(data.select(unhex('b)), Row("string".getBytes))
checkAnswer(data.selectExpr("unhex(a)"), Row(Array[Byte](28.toByte)))
checkAnswer(data.selectExpr("unhex(b)"), Row("string".getBytes))
checkAnswer(data.selectExpr("""unhex("##")"""), Row(null))

}

test("hypot") {
testTwoToOneMathFunction(hypot, hypot, math.hypot)
}
Expand Down

0 comments on commit c852d46

Please sign in to comment.