diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala index 0041ccf77557..918410807df8 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala @@ -580,14 +580,23 @@ object FunctionRegistry { // Otherwise, find a constructor method that matches the number of arguments, and use that. val params = Seq.fill(expressions.size)(classOf[Expression]) val f = constructors.find(_.getParameterTypes.toSeq == params).getOrElse { - val validParametersCount = constructors - .filter(_.getParameterTypes.forall(_ == classOf[Expression])) - .map(_.getParameterCount).distinct.sorted - val expectedNumberOfParameters = if (validParametersCount.length == 1) { - validParametersCount.head.toString + val (validParameters, invalidParameters) = constructors + .partition(_.getParameterTypes.forall(_ == classOf[Expression])) + val validParametersCount = validParameters.map(_.getParameterCount).distinct.sorted + + def getExpectedNumberOfParameters(parametersCount: Array[Int]): String = { + if (parametersCount.length == 1) { + parametersCount.head.toString + } else { + parametersCount.init.mkString("one of ", ", ", " and ") + parametersCount.last + } + } + val expectedNumberOfParameters = if (validParametersCount.isEmpty) { + val invalidParametersCount = invalidParameters.map(_.getParameterCount).distinct.sorted + getExpectedNumberOfParameters(invalidParametersCount) + + "(But none is valid, please check whether it is properly defined or misused)" } else { - validParametersCount.init.mkString("one of ", ", ", " and ") + - validParametersCount.last + getExpectedNumberOfParameters(validParametersCount) } throw new AnalysisException(s"Invalid number of arguments for function $name. " + s"Expected: $expectedNumberOfParameters; Found: ${params.length}") diff --git a/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala index ba1ac654c1a0..679aa5b5455e 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala @@ -106,6 +106,13 @@ class SQLQuerySuite extends QueryTest with SharedSQLContext { checkKeywordsExist(sql("describe functioN abcadf"), "Function: abcadf not found.") } + test("SPARK-28143: IN expression missing attribute should throw analysis exception") { + // missing attribute, which actually might be `select 1 where a in ()` + val query = "select 1 where in ()" + val e = intercept[AnalysisException](sql(query)) + assert(e.getMessage.startsWith("Invalid number of arguments for function in")) + } + test("SPARK-14415: All functions should have own descriptions") { for (f <- spark.sessionState.functionRegistry.listFunction()) { if (!Seq("cube", "grouping", "grouping_id", "rollup", "window").contains(f.unquotedString)) {