diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java index a5228edc33c83..ded5c96525e22 100644 --- a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java +++ b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java @@ -342,4 +342,21 @@ public static UTF8String quote(UTF8String str) { String sp = str.toString().replaceAll(qtChar, qtCharRep); return UTF8String.fromString(qtChar + sp + qtChar); } + + /** + * Returns the single-character string for the {@code chr} expression: the + * ASCII/Latin-1 character for {@code longVal & 0xFF}. A negative argument + * yields the empty string. Shared by the eval and codegen paths so the + * generated Java is a single call rather than an inline if/else chain. + */ + public static UTF8String chr(long longVal) { + if (longVal < 0) { + return UTF8String.EMPTY_UTF8; + } else if ((longVal & 0xFF) == 0) { + return UTF8String.fromString(String.valueOf(Character.MIN_VALUE)); + } else { + char c = (char) (longVal & 0xFF); + return UTF8String.fromString(String.valueOf(c)); + } + } } diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringExpressions.scala index 5b5a63812dcab..5c6e457421bf6 100755 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/stringExpressions.scala @@ -2822,31 +2822,14 @@ case class Chr(child: Expression) override def inputTypes: Seq[DataType] = Seq(LongType) protected override def nullSafeEval(lon: Any): Any = { - val longVal = lon.asInstanceOf[Long] - if (longVal < 0) { - UTF8String.EMPTY_UTF8 - } else if ((longVal & 0xFF) == 0) { - UTF8String.fromString(Character.MIN_VALUE.toString) - } else { - UTF8String.fromString((longVal & 0xFF).toChar.toString) - } + ExpressionImplUtils.chr(lon.asInstanceOf[Long]) } override def contextIndependentFoldable: Boolean = child.contextIndependentFoldable override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { - nullSafeCodeGen(ctx, ev, lon => { - s""" - if ($lon < 0) { - ${ev.value} = UTF8String.EMPTY_UTF8; - } else if (($lon & 0xFF) == 0) { - ${ev.value} = UTF8String.fromString(String.valueOf(Character.MIN_VALUE)); - } else { - char c = (char)($lon & 0xFF); - ${ev.value} = UTF8String.fromString(String.valueOf(c)); - } - """ - }) + val utils = classOf[ExpressionImplUtils].getName + nullSafeCodeGen(ctx, ev, lon => s"${ev.value} = $utils.chr($lon);") } override protected def withNewChildInternal(newChild: Expression): Chr = copy(child = newChild)