diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/functions.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/functions.scala index 252d188ff8fe..fae8de478010 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/functions.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/functions.scala @@ -251,8 +251,8 @@ case class RefreshFunctionCommand( override def run(sparkSession: SparkSession): Seq[Row] = { val catalog = sparkSession.sessionState.catalog - if (FunctionRegistry.builtin.functionExists(FunctionIdentifier(functionName))) { - throw new AnalysisException(s"Cannot refresh builtin function $functionName") + if (FunctionRegistry.builtin.functionExists(FunctionIdentifier(functionName, databaseName))) { + throw new AnalysisException(s"Cannot refresh built-in function $functionName") } if (catalog.isTemporaryFunction(FunctionIdentifier(functionName, databaseName))) { throw new AnalysisException(s"Cannot refresh temporary function $functionName") diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala index faafcb721008..17857a6ce173 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/DDLSuite.scala @@ -3035,7 +3035,12 @@ abstract class DDLSuite extends QueryTest with SQLTestUtils { val msg = intercept[AnalysisException] { sql("REFRESH FUNCTION md5") }.getMessage - assert(msg.contains("Cannot refresh builtin function")) + assert(msg.contains("Cannot refresh built-in function")) + val msg2 = intercept[NoSuchFunctionException] { + sql("REFRESH FUNCTION default.md5") + }.getMessage + assert(msg2.contains(s"Undefined function: 'md5'. This function is neither a registered " + + s"temporary function nor a permanent function registered in the database 'default'.")) withUserDefinedFunction("func1" -> true) { sql("CREATE TEMPORARY FUNCTION func1 AS 'test.org.apache.spark.sql.MyDoubleAvg'") @@ -3046,15 +3051,23 @@ abstract class DDLSuite extends QueryTest with SQLTestUtils { } withUserDefinedFunction("func1" -> false) { + val func = FunctionIdentifier("func1", Some("default")) + assert(!spark.sessionState.catalog.isRegisteredFunction(func)) intercept[NoSuchFunctionException] { sql("REFRESH FUNCTION func1") } + assert(!spark.sessionState.catalog.isRegisteredFunction(func)) - val func = FunctionIdentifier("func1", Some("default")) sql("CREATE FUNCTION func1 AS 'test.org.apache.spark.sql.MyDoubleAvg'") assert(!spark.sessionState.catalog.isRegisteredFunction(func)) sql("REFRESH FUNCTION func1") assert(spark.sessionState.catalog.isRegisteredFunction(func)) + val msg = intercept[NoSuchFunctionException] { + sql("REFRESH FUNCTION func2") + }.getMessage + assert(msg.contains(s"Undefined function: 'func2'. This function is neither a registered " + + s"temporary function nor a permanent function registered in the database 'default'.")) + assert(spark.sessionState.catalog.isRegisteredFunction(func)) spark.sessionState.catalog.externalCatalog.dropFunction("default", "func1") assert(spark.sessionState.catalog.isRegisteredFunction(func)) @@ -3073,6 +3086,21 @@ abstract class DDLSuite extends QueryTest with SQLTestUtils { assert(!spark.sessionState.catalog.isRegisteredFunction(func)) } } + + test("REFRESH FUNCTION persistent function with the same name as the built-in function") { + withUserDefinedFunction("default.rand" -> false) { + val rand = FunctionIdentifier("rand", Some("default")) + sql("CREATE FUNCTION rand AS 'test.org.apache.spark.sql.MyDoubleAvg'") + assert(!spark.sessionState.catalog.isRegisteredFunction(rand)) + val msg = intercept[AnalysisException] { + sql("REFRESH FUNCTION rand") + }.getMessage + assert(msg.contains("Cannot refresh built-in function")) + assert(!spark.sessionState.catalog.isRegisteredFunction(rand)) + sql("REFRESH FUNCTION default.rand") + assert(spark.sessionState.catalog.isRegisteredFunction(rand)) + } + } } object FakeLocalFsFileSystem {