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 1053650a3709..fa1741cb08f7 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 @@ -346,6 +346,23 @@ public static UTF8String quote(UTF8String str) { 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)); + } + } + /** * Compiles {@code regex} with the given {@code flags} for the regexp expression * family, translating a {@link PatternSyntaxException} into the user-facing 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 5b5a63812dca..5c6e457421bf 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)