From 230a967b8959609925b74e3013af9b887848f5e0 Mon Sep 17 00:00:00 2001 From: Kousuke Saruta Date: Thu, 23 Jan 2025 22:36:27 +0900 Subject: [PATCH] Move quote function to ExpressionUtils, and use StaticInvoke instead of Invoke --- .../apache/spark/unsafe/types/UTF8String.java | 8 ------- .../expressions/ExpressionImplUtils.java | 8 +++++++ .../expressions/stringExpressions.scala | 22 +++++++++++++------ .../spark/sql/StringFunctionsSuite.scala | 17 -------------- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/common/unsafe/src/main/java/org/apache/spark/unsafe/types/UTF8String.java b/common/unsafe/src/main/java/org/apache/spark/unsafe/types/UTF8String.java index fda0539d1669a..caf8461b0b5d6 100644 --- a/common/unsafe/src/main/java/org/apache/spark/unsafe/types/UTF8String.java +++ b/common/unsafe/src/main/java/org/apache/spark/unsafe/types/UTF8String.java @@ -2160,14 +2160,6 @@ public UTF8String soundex() { return UTF8String.fromBytes(sx); } - public UTF8String quote() { - final String qtChar = "'"; - final String qtCharRep = "\\\\'"; - - String sp = toString().replaceAll(qtChar, qtCharRep); - return fromString(qtChar + sp + qtChar); - } - @Override public void writeExternal(ObjectOutput out) throws IOException { byte[] bytes = getBytes(); 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 2fad36efe8cc1..8c42e5bf112c4 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 @@ -334,4 +334,12 @@ public static UTF8String randStr(XORShiftRandom rng, int length) { } return UTF8String.fromBytes(bytes); } + + public static UTF8String quote(UTF8String str) { + final String qtChar = "'"; + final String qtCharRep = "\\\\'"; + + String sp = str.toString().replaceAll(qtChar, qtCharRep); + return UTF8String.fromString(qtChar + sp + qtChar); + } } 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 20e44d0420ee2..a9a337f741432 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 @@ -3724,11 +3724,9 @@ case class Luhncheck(input: Expression) extends RuntimeReplaceable with Implicit * A function that prepends a backslash to each instance of single quote * in the given string and encloses the result by single quotes. */ +// scalastyle:off line.size.limit @ExpressionDescription( - usage = """ - _FUNC_(str) - Returns `str` enclosed by single quotes and - each instance of single quote in it is preceded by a backslash. - """, + usage = "_FUNC_(str) - Returns `str` enclosed by single quotes and each instance of single quote in it is preceded by a backslash.", examples = """ Examples: > SELECT _FUNC_('Don\'t'); @@ -3736,11 +3734,21 @@ case class Luhncheck(input: Expression) extends RuntimeReplaceable with Implicit """, since = "4.0.0", group = "string_funcs") -case class Quote(input: Expression) extends RuntimeReplaceable with ImplicitCastInputTypes - with UnaryLike[Expression] { +// scalastyle:on line.size.limit +case class Quote(input: Expression) + extends UnaryExpression + with RuntimeReplaceable + with ImplicitCastInputTypes + with DefaultStringProducingExpression { + override def nullIntolerant: Boolean = true - override lazy val replacement: Expression = Invoke(input, "quote", input.dataType) + override lazy val replacement: Expression = StaticInvoke( + classOf[ExpressionImplUtils], + dataType, + "quote", + Seq(input), + inputTypes) override def inputTypes: Seq[AbstractDataType] = { Seq(StringTypeWithCollation(supportsTrimCollation = true)) diff --git a/sql/core/src/test/scala/org/apache/spark/sql/StringFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/StringFunctionsSuite.scala index ebba2e540abd2..2e91d60e4ba04 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/StringFunctionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/StringFunctionsSuite.scala @@ -1452,21 +1452,4 @@ class StringFunctionsSuite extends QueryTest with SharedSparkSession { Seq(Row("abc", "def"))) } } - - test("SPARK-50582: string quote function") { - val df = Seq(("Don't")).toDF("value") - - checkAnswer( - df.select(quote($"value")), - Row("'Don\\'t'")) - - checkAnswer( - df.selectExpr("quote('Spark')"), - Row("'Spark'") - ) - - checkAnswer( - df.selectExpr("quote(NULL)"), - Row(null)) - } }