You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by ma...@apache.org on 2023/06/29 09:26:39 UTC

[spark] branch master updated: [SPARK-44169][SQL] Assign names to the error class _LEGACY_ERROR_TEMP_[2300-2304]

This is an automated email from the ASF dual-hosted git repository.

maxgekk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new ffbd1a3b5b1 [SPARK-44169][SQL] Assign names to the error class _LEGACY_ERROR_TEMP_[2300-2304]
ffbd1a3b5b1 is described below

commit ffbd1a3b5b17386759a378dee5ef5cf6df7f2d09
Author: Jiaan Geng <be...@163.com>
AuthorDate: Thu Jun 29 12:26:24 2023 +0300

    [SPARK-44169][SQL] Assign names to the error class _LEGACY_ERROR_TEMP_[2300-2304]
    
    ### What changes were proposed in this pull request?
    The pr aims to assign names to the error class _LEGACY_ERROR_TEMP_[2300-2304].
    
    ### Why are the changes needed?
    Improve the error framework.
    
    ### Does this PR introduce _any_ user-facing change?
    'No'.
    
    ### How was this patch tested?
    Exists test cases updated and added new test cases.
    
    Closes #41719 from beliefer/SPARK-44169.
    
    Authored-by: Jiaan Geng <be...@163.com>
    Signed-off-by: Max Gekk <ma...@gmail.com>
---
 .../src/main/resources/error/error-classes.json    |  74 ++++---
 .../catalyst/analysis/ResolveInlineTables.scala    |  12 +-
 .../catalyst/analysis/higherOrderFunctions.scala   |  14 +-
 .../analysis/ResolveLambdaVariablesSuite.scala     |  18 +-
 .../spark/sql/execution/datasources/rules.scala    |   4 +-
 .../sql-tests/analyzer-results/cte.sql.out         |   4 +-
 .../analyzer-results/inline-table.sql.out          |  12 +-
 .../analyzer-results/postgreSQL/boolean.sql.out    |   2 +-
 .../postgreSQL/window_part3.sql.out                |   2 +-
 .../postgreSQL/window_part4.sql.out                |   2 +-
 .../analyzer-results/udf/udf-inline-table.sql.out  |  12 +-
 .../test/resources/sql-tests/results/cte.sql.out   |   4 +-
 .../sql-tests/results/inline-table.sql.out         |  12 +-
 .../sql-tests/results/postgreSQL/boolean.sql.out   |   2 +-
 .../results/postgreSQL/window_part3.sql.out        |   2 +-
 .../results/postgreSQL/window_part4.sql.out        |   2 +-
 .../sql-tests/results/udf/udf-inline-table.sql.out |  12 +-
 .../apache/spark/sql/ColumnExpressionSuite.scala   |  33 +++-
 .../apache/spark/sql/DataFrameFunctionsSuite.scala | 219 +++++++++++++++------
 19 files changed, 297 insertions(+), 145 deletions(-)

diff --git a/common/utils/src/main/resources/error/error-classes.json b/common/utils/src/main/resources/error/error-classes.json
index e441686432a..192a0747dfd 100644
--- a/common/utils/src/main/resources/error/error-classes.json
+++ b/common/utils/src/main/resources/error/error-classes.json
@@ -704,11 +704,6 @@
     ],
     "sqlState" : "42K04"
   },
-  "FAILED_SQL_EXPRESSION_EVALUATION" : {
-    "message" : [
-      "Failed to evaluate the SQL expression: <sqlExpr>. Please check your syntax and ensure all required tables and columns are available."
-    ]
-  },
   "FIELD_NOT_FOUND" : {
     "message" : [
       "No such struct field <fieldName> in <fields>."
@@ -1197,6 +1192,28 @@
     ],
     "sqlState" : "22003"
   },
+  "INVALID_INLINE_TABLE" : {
+    "message" : [
+      "Invalid inline table."
+    ],
+    "subClass" : {
+      "CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE" : {
+        "message" : [
+          "Cannot evaluate the expression <expr> in inline table definition."
+        ]
+      },
+      "FAILED_SQL_EXPRESSION_EVALUATION" : {
+        "message" : [
+          "Failed to evaluate the SQL expression <sqlExpr>. Please check your syntax and ensure all required tables and columns are available."
+        ]
+      },
+      "INCOMPATIBLE_TYPES_IN_INLINE_TABLE" : {
+        "message" : [
+          "Found incompatible types in the column <colName> for inline table."
+        ]
+      }
+    }
+  },
   "INVALID_JSON_ROOT_FIELD" : {
     "message" : [
       "Cannot convert JSON root field to target Spark type."
@@ -1209,6 +1226,23 @@
     ],
     "sqlState" : "22032"
   },
+  "INVALID_LAMBDA_FUNCTION_CALL" : {
+    "message" : [
+      "Invalid lambda function call."
+    ],
+    "subClass" : {
+      "DUPLICATE_ARG_NAMES" : {
+        "message" : [
+          "The lambda function has duplicate arguments <args>. Please, consider to rename the argument names or set <caseSensitiveConfig> to \"true\"."
+        ]
+      },
+      "NUM_ARGS_MISMATCH" : {
+        "message" : [
+          "A higher order function expects <expectedNumArgs> arguments, but got <actualNumArgs>."
+        ]
+      }
+    }
+  },
   "INVALID_LATERAL_JOIN_TYPE" : {
     "message" : [
       "The <joinType> JOIN with LATERAL correlation is not allowed because an OUTER subquery cannot correlate to its join partner. Remove the LATERAL correlation or use an INNER JOIN, or LEFT OUTER JOIN instead."
@@ -1654,6 +1688,11 @@
     ],
     "sqlState" : "42803"
   },
+  "MULTI_SOURCES_UNSUPPORTED_FOR_EXPRESSION" : {
+    "message" : [
+      "The expression <expr> does not support more than one source."
+    ]
+  },
   "MULTI_UDF_INTERFACE_ERROR" : {
     "message" : [
       "Not allowed to implement multiple UDF interfaces, UDF class <className>."
@@ -5492,31 +5531,6 @@
       "The input <valueType> '<input>' does not match the given number format: '<format>'."
     ]
   },
-  "_LEGACY_ERROR_TEMP_2300" : {
-    "message" : [
-      "The number of lambda function arguments '<namesSize>' does not match the number of arguments expected by the higher order function '<argInfoSize>'."
-    ]
-  },
-  "_LEGACY_ERROR_TEMP_2301" : {
-    "message" : [
-      "Lambda function arguments should not have names that are semantically the same."
-    ]
-  },
-  "_LEGACY_ERROR_TEMP_2302" : {
-    "message" : [
-      "'<name>' does not support more than one sources."
-    ]
-  },
-  "_LEGACY_ERROR_TEMP_2303" : {
-    "message" : [
-      "incompatible types found in column <name> for inline table."
-    ]
-  },
-  "_LEGACY_ERROR_TEMP_2304" : {
-    "message" : [
-      "cannot evaluate expression <sqlExpr> in inline table definition."
-    ]
-  },
   "_LEGACY_ERROR_TEMP_2305" : {
     "message" : [
       "expected <numCols> columns but found <rowSize> columns in row <ri>."
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTables.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTables.scala
index 4447b96c332..934b3bde6b5 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTables.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTables.scala
@@ -25,7 +25,7 @@ import org.apache.spark.sql.catalyst.plans.logical.{LocalRelation, LogicalPlan}
 import org.apache.spark.sql.catalyst.rules.Rule
 import org.apache.spark.sql.catalyst.trees.AlwaysProcess
 import org.apache.spark.sql.catalyst.types.DataTypeUtils
-import org.apache.spark.sql.catalyst.util.TypeUtils.toSQLExpr
+import org.apache.spark.sql.catalyst.util.TypeUtils.{toSQLExpr, toSQLId}
 import org.apache.spark.sql.types.{StructField, StructType}
 
 /**
@@ -75,8 +75,8 @@ object ResolveInlineTables extends Rule[LogicalPlan] with CastSupport with Alias
         // Note that nondeterministic expressions are not supported since they are not foldable.
         if (!e.resolved || !trimAliases(e).foldable) {
           e.failAnalysis(
-            errorClass = "_LEGACY_ERROR_TEMP_2304",
-            messageParameters = Map("sqlExpr" -> e.sql))
+            errorClass = "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
+            messageParameters = Map("expr" -> toSQLExpr(e)))
         }
       }
     }
@@ -96,8 +96,8 @@ object ResolveInlineTables extends Rule[LogicalPlan] with CastSupport with Alias
       val inputTypes = column.map(_.dataType)
       val tpe = TypeCoercion.findWiderTypeWithoutStringPromotion(inputTypes).getOrElse {
         table.failAnalysis(
-          errorClass = "_LEGACY_ERROR_TEMP_2303",
-          messageParameters = Map("name" -> name))
+          errorClass = "INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE",
+          messageParameters = Map("colName" -> toSQLId(name)))
       }
       StructField(name, tpe, nullable = column.exists(_.nullable))
     }
@@ -117,7 +117,7 @@ object ResolveInlineTables extends Rule[LogicalPlan] with CastSupport with Alias
         } catch {
           case NonFatal(ex) =>
             table.failAnalysis(
-              errorClass = "FAILED_SQL_EXPRESSION_EVALUATION",
+              errorClass = "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
               messageParameters = Map("sqlExpr" -> toSQLExpr(e)),
               cause = ex)
         }
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/higherOrderFunctions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/higherOrderFunctions.scala
index 1c841675d9a..492adf62c78 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/higherOrderFunctions.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/higherOrderFunctions.scala
@@ -21,6 +21,8 @@ import org.apache.spark.sql.catalyst.expressions._
 import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
 import org.apache.spark.sql.catalyst.rules.Rule
 import org.apache.spark.sql.catalyst.trees.TreePattern._
+import org.apache.spark.sql.catalyst.util.TypeUtils.{toSQLConf, toSQLId}
+import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types.DataType
 
 /**
@@ -72,16 +74,18 @@ object ResolveLambdaVariables extends Rule[LogicalPlan] {
     case LambdaFunction(function, names, _) =>
       if (names.size != argInfo.size) {
         e.failAnalysis(
-          errorClass = "_LEGACY_ERROR_TEMP_2300",
+          errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
           messageParameters = Map(
-            "namesSize" -> names.size.toString,
-            "argInfoSize" -> argInfo.size.toString))
+            "expectedNumArgs" -> names.size.toString,
+            "actualNumArgs" -> argInfo.size.toString))
       }
 
       if (names.map(a => canonicalizer(a.name)).distinct.size < names.size) {
         e.failAnalysis(
-          errorClass = "_LEGACY_ERROR_TEMP_2301",
-          messageParameters = Map.empty)
+          errorClass = "INVALID_LAMBDA_FUNCTION_CALL.DUPLICATE_ARG_NAMES",
+          messageParameters = Map(
+            "args" -> names.map(a => canonicalizer(a.name)).map(toSQLId(_)).mkString(", "),
+            "caseSensitiveConfig" -> toSQLConf(SQLConf.CASE_SENSITIVE.key)))
       }
 
       val arguments = argInfo.zip(names).map {
diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveLambdaVariablesSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveLambdaVariablesSuite.scala
index 1848e8bce4e..5809d1e04b9 100644
--- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveLambdaVariablesSuite.scala
+++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveLambdaVariablesSuite.scala
@@ -79,15 +79,25 @@ class ResolveLambdaVariablesSuite extends PlanTest {
   test("fail - name collisions") {
     val p = plan(ArrayTransform(values1,
       LambdaFunction(lv(Symbol("x")) + lv(Symbol("X")), lv(Symbol("x")) :: lv(Symbol("X")) :: Nil)))
-    val msg = intercept[AnalysisException](Analyzer.execute(p)).getMessage
-    assert(msg.contains("arguments should not have names that are semantically the same"))
+
+    checkError(
+      exception = intercept[AnalysisException](Analyzer.execute(p)),
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.DUPLICATE_ARG_NAMES",
+      parameters = Map(
+        "args" -> "`x`, `x`",
+        "caseSensitiveConfig" -> "\"spark.sql.caseSensitive\"")
+    )
   }
 
   test("fail - lambda arguments") {
     val p = plan(ArrayTransform(values1,
       LambdaFunction(lv(Symbol("x")) + lv(Symbol("y")) + lv(Symbol("z")),
         lv(Symbol("x")) :: lv(Symbol("y")) :: lv(Symbol("z")) :: Nil)))
-    val msg = intercept[AnalysisException](Analyzer.execute(p)).getMessage
-    assert(msg.contains("does not match the number of arguments expected"))
+
+    checkError(
+      exception = intercept[AnalysisException](Analyzer.execute(p)),
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "1")
+    )
   }
 }
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/rules.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/rules.scala
index 750f39a252f..10197709438 100644
--- a/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/rules.scala
+++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/rules.scala
@@ -489,8 +489,8 @@ object PreReadCheck extends (LogicalPlan => Unit) {
         val numInputFileBlockSources = o.children.map(checkNumInputFileBlockSources(e, _)).sum
         if (numInputFileBlockSources > 1) {
           e.failAnalysis(
-            errorClass = "_LEGACY_ERROR_TEMP_2302",
-            messageParameters = Map("name" -> e.prettyName))
+            errorClass = "MULTI_SOURCES_UNSUPPORTED_FOR_EXPRESSION",
+            messageParameters = Map("expr" -> toSQLExpr(e)))
         } else {
           numInputFileBlockSources
         }
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/cte.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/cte.sql.out
index ac998540532..1c6e6718fc5 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/cte.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/cte.sql.out
@@ -358,9 +358,9 @@ FROM t
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "outer(t.id)"
+    "expr" : "\"outer(t.id)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/inline-table.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/inline-table.sql.out
index 9ff237d4324..c473c392f07 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/inline-table.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/inline-table.sql.out
@@ -99,9 +99,9 @@ select * from values ("one", rand(5)), ("two", 3.0D) as data(a, b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "rand(5)"
+    "expr" : "\"rand(5)\""
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -139,9 +139,9 @@ select * from values ("one", array(0, 1)), ("two", struct(1, 2)) as data(a, b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2303",
+  "errorClass" : "INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE",
   "messageParameters" : {
-    "name" : "b"
+    "colName" : "`b`"
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -200,9 +200,9 @@ select * from values ("one", count(1)), ("two", 2) as data(a, b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "count(1)"
+    "expr" : "\"count(1)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/boolean.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/boolean.sql.out
index adf7bcda741..f0313cb62d5 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/boolean.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/boolean.sql.out
@@ -414,7 +414,7 @@ INSERT INTO BOOLTBL2
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"XXX\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part3.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part3.sql.out
index 27fafeb38dc..020cdbf375c 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part3.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part3.sql.out
@@ -65,7 +65,7 @@ insert into datetimes values
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"CAST(11:00 BST AS TIMESTAMP)\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part4.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part4.sql.out
index 12f754620de..83e984cc678 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part4.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/postgreSQL/window_part4.sql.out
@@ -500,7 +500,7 @@ FROM (VALUES(1,1),(2,2),(3,(cast('nan' as int))),(4,3),(5,4)) t(a,b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"CAST(nan AS INT)\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/udf/udf-inline-table.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/udf/udf-inline-table.sql.out
index 7c9ace74676..7a6685fc9fe 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/udf/udf-inline-table.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/udf/udf-inline-table.sql.out
@@ -83,9 +83,9 @@ select udf(a), b from values ("one", rand(5)), ("two", 3.0D) as data(a, b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "rand(5)"
+    "expr" : "\"rand(5)\""
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -123,9 +123,9 @@ select udf(a), udf(b) from values ("one", array(0, 1)), ("two", struct(1, 2)) as
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2303",
+  "errorClass" : "INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE",
   "messageParameters" : {
-    "name" : "b"
+    "colName" : "`b`"
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -184,9 +184,9 @@ select udf(a), udf(b) from values ("one", count(1)), ("two", 2) as data(a, b)
 -- !query analysis
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "count(1)"
+    "expr" : "\"count(1)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/resources/sql-tests/results/cte.sql.out b/sql/core/src/test/resources/sql-tests/results/cte.sql.out
index b40b062c876..cf585b8d884 100644
--- a/sql/core/src/test/resources/sql-tests/results/cte.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/cte.sql.out
@@ -271,9 +271,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "outer(t.id)"
+    "expr" : "\"outer(t.id)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/resources/sql-tests/results/inline-table.sql.out b/sql/core/src/test/resources/sql-tests/results/inline-table.sql.out
index 1d265061c5d..2d2e6b28360 100644
--- a/sql/core/src/test/resources/sql-tests/results/inline-table.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/inline-table.sql.out
@@ -111,9 +111,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "rand(5)"
+    "expr" : "\"rand(5)\""
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -155,9 +155,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2303",
+  "errorClass" : "INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE",
   "messageParameters" : {
-    "name" : "b"
+    "colName" : "`b`"
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -222,9 +222,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "count(1)"
+    "expr" : "\"count(1)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out b/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out
index 44efe4614e9..c61a7aa82d2 100644
--- a/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/postgreSQL/boolean.sql.out
@@ -717,7 +717,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"XXX\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part3.sql.out b/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part3.sql.out
index 7b738505be1..53f9f6cee8c 100644
--- a/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part3.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part3.sql.out
@@ -70,7 +70,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"CAST(11:00 BST AS TIMESTAMP)\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part4.sql.out b/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part4.sql.out
index 8ba267f6618..1c3e7ec0f59 100644
--- a/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part4.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/postgreSQL/window_part4.sql.out
@@ -499,7 +499,7 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "FAILED_SQL_EXPRESSION_EVALUATION",
+  "errorClass" : "INVALID_INLINE_TABLE.FAILED_SQL_EXPRESSION_EVALUATION",
   "messageParameters" : {
     "sqlExpr" : "\"CAST(nan AS INT)\""
   },
diff --git a/sql/core/src/test/resources/sql-tests/results/udf/udf-inline-table.sql.out b/sql/core/src/test/resources/sql-tests/results/udf/udf-inline-table.sql.out
index 3fbabf9a9d9..77de4beb79d 100644
--- a/sql/core/src/test/resources/sql-tests/results/udf/udf-inline-table.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/udf/udf-inline-table.sql.out
@@ -95,9 +95,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "rand(5)"
+    "expr" : "\"rand(5)\""
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -139,9 +139,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2303",
+  "errorClass" : "INVALID_INLINE_TABLE.INCOMPATIBLE_TYPES_IN_INLINE_TABLE",
   "messageParameters" : {
-    "name" : "b"
+    "colName" : "`b`"
   },
   "queryContext" : [ {
     "objectType" : "",
@@ -206,9 +206,9 @@ struct<>
 -- !query output
 org.apache.spark.sql.AnalysisException
 {
-  "errorClass" : "_LEGACY_ERROR_TEMP_2304",
+  "errorClass" : "INVALID_INLINE_TABLE.CANNOT_EVALUATE_EXPRESSION_IN_INLINE_TABLE",
   "messageParameters" : {
-    "sqlExpr" : "count(1)"
+    "expr" : "\"count(1)\""
   },
   "queryContext" : [ {
     "objectType" : "",
diff --git a/sql/core/src/test/scala/org/apache/spark/sql/ColumnExpressionSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/ColumnExpressionSuite.scala
index b93b643cbb8..9e8d77c53f3 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/ColumnExpressionSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/ColumnExpressionSuite.scala
@@ -721,11 +721,21 @@ class ColumnExpressionSuite extends QueryTest with SharedSparkSession {
         data.write.saveAsTable("tab1")
         data.write.saveAsTable("tab2")
         data.createOrReplaceTempView("tempView1")
-        Seq("input_file_name", "input_file_block_start", "input_file_block_length").foreach { f =>
-          val e = intercept[AnalysisException] {
-            sql(s"SELECT *, $f() FROM tab1 JOIN tab2 ON tab1.id = tab2.id")
-          }.getMessage
-          assert(e.contains(s"'$f' does not support more than one source"))
+        Seq(
+          ("input_file_name", 26),
+          ("input_file_block_start", 33),
+          ("input_file_block_length", 34)).foreach { case (f, e) =>
+          checkError(
+            exception = intercept[AnalysisException] {
+              sql(s"SELECT *, $f() FROM tab1 JOIN tab2 ON tab1.id = tab2.id")
+            },
+            errorClass = "MULTI_SOURCES_UNSUPPORTED_FOR_EXPRESSION",
+            parameters = Map("expr" -> s""""$f()""""),
+            context = ExpectedContext(
+              fragment = s"$f()",
+              start = 10,
+              stop = e)
+          )
         }
 
         def checkResult(
@@ -734,8 +744,17 @@ class ColumnExpressionSuite extends QueryTest with SharedSparkSession {
             numExpectedRows: Int = 0): Unit = {
           val stmt = s"SELECT *, input_file_name() FROM ($fromClause)"
           if (exceptionExpected) {
-            val e = intercept[AnalysisException](sql(stmt)).getMessage
-            assert(e.contains("'input_file_name' does not support more than one source"))
+            checkError(
+              exception = intercept[AnalysisException] {
+                sql(stmt)
+              },
+              errorClass = "MULTI_SOURCES_UNSUPPORTED_FOR_EXPRESSION",
+              parameters = Map("expr" -> """"input_file_name()""""),
+              context = ExpectedContext(
+                fragment = s"input_file_name()",
+                start = 10,
+                stop = 26)
+            )
           } else {
             assert(sql(stmt).count() == numExpectedRows)
           }
diff --git a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala
index f1f6480cc08..419e00659ea 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala
@@ -3574,10 +3574,17 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 4)
     ).toDF("s", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("transform(s, (x, y, z) -> x + y + z)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '3' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("transform(s, (x, y, z) -> x + y + z)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "1"),
+      context = ExpectedContext(
+        fragment = "(x, y, z) -> x + y + z",
+        start = 13,
+        stop = 34)
+    )
 
     checkError(
       exception = intercept[AnalysisException](df.selectExpr("transform(i, x -> x)")),
@@ -3651,15 +3658,29 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 3)
     ).toDF("s", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("map_filter(s, (x, y, z) -> x + y + z)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '3' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("map_filter(s, (x, y, z) -> x + y + z)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "2"),
+      context = ExpectedContext(
+        fragment = "(x, y, z) -> x + y + z",
+        start = 14,
+        stop = 35)
+    )
 
-    val ex2 = intercept[AnalysisException] {
-      df.selectExpr("map_filter(s, x -> x)")
-    }
-    assert(ex2.getMessage.contains("The number of lambda function arguments '1' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("map_filter(s, x -> x)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "1", "actualNumArgs" -> "2"),
+      context = ExpectedContext(
+        fragment = "x -> x",
+        start = 14,
+        stop = 19)
+    )
 
     checkError(
       exception = intercept[AnalysisException] {
@@ -3832,10 +3853,17 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 4)
     ).toDF("s", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("filter(s, (x, y, z) -> x + y)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '3' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("filter(s, (x, y, z) -> x + y)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "1"),
+      context = ExpectedContext(
+        fragment = "(x, y, z) -> x + y",
+        start = 10,
+        stop = 27)
+    )
 
     checkError(
       exception = intercept[AnalysisException] {
@@ -4004,10 +4032,17 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 4)
     ).toDF("s", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("exists(s, (x, y) -> x + y)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '2' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("exists(s, (x, y) -> x + y)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "2", "actualNumArgs" -> "1"),
+      context = ExpectedContext(
+        fragment = "(x, y) -> x + y",
+        start = 10,
+        stop = 24)
+    )
 
     checkError(
       exception = intercept[AnalysisException] {
@@ -4189,10 +4224,17 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 4)
     ).toDF("s", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("forall(s, (x, y) -> x + y)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '2' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("forall(s, (x, y) -> x + y)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "2", "actualNumArgs" -> "1"),
+      context = ExpectedContext(
+        fragment = "(x, y) -> x + y",
+        start = 10,
+        stop = 24)
+    )
 
     checkError(
       exception = intercept[AnalysisException] {
@@ -4441,16 +4483,31 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (null, 4)
     ).toDF("s", "i")
 
-    Seq("aggregate", "reduce").foreach { agg =>
-      val ex1 = intercept[AnalysisException] {
-        df.selectExpr(s"$agg(s, '', x -> x)")
-      }
-      assert(ex1.getMessage.contains("The number of lambda function arguments '1' does not match"))
+    Seq(("aggregate", 17, 32), ("reduce", 14, 29)).foreach {
+      case (agg, startIndex1, startIndex2) =>
+        checkError(
+          exception = intercept[AnalysisException] {
+            df.selectExpr(s"$agg(s, '', x -> x)")
+          },
+          errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+          parameters = Map("expectedNumArgs" -> "1", "actualNumArgs" -> "2"),
+          context = ExpectedContext(
+            fragment = "x -> x",
+            start = startIndex1,
+            stop = startIndex1 + 5)
+        )
 
-      val ex2 = intercept[AnalysisException] {
-        df.selectExpr(s"$agg(s, '', (acc, x) -> x, (acc, x) -> x)")
-      }
-      assert(ex2.getMessage.contains("The number of lambda function arguments '2' does not match"))
+        checkError(
+          exception = intercept[AnalysisException] {
+            df.selectExpr(s"$agg(s, '', (acc, x) -> x, (acc, x) -> x)")
+          },
+          errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+          parameters = Map("expectedNumArgs" -> "2", "actualNumArgs" -> "1"),
+          context = ExpectedContext(
+            fragment = "(acc, x) -> x",
+            start = startIndex2,
+            stop = startIndex2 + 12)
+        )
     }
 
     Seq("aggregate", "reduce").foreach { agg =>
@@ -4584,10 +4641,17 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       (Map(1 -> 2), Map(1 -> "a"), Map("a" -> "b"), Map(Map(1 -> 2) -> 2), 1)
     ).toDF("mii", "mis", "mss", "mmi", "i")
 
-    val ex1 = intercept[AnalysisException] {
-      df.selectExpr("map_zip_with(mii, mis, (x, y) -> x + y)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '2' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("map_zip_with(mii, mis, (x, y) -> x + y)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "2", "actualNumArgs" -> "3"),
+      context = ExpectedContext(
+        fragment = "(x, y) -> x + y",
+        start = 23,
+        stop = 37)
+    )
 
     checkError(
       exception = intercept[AnalysisException] {
@@ -4798,16 +4862,29 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       Seq(1, 2, 3, 4)
     ).toDF("j")
 
-    val ex1 = intercept[AnalysisException] {
-      dfExample1.selectExpr("transform_keys(i, k -> k)")
-    }
-    assert(ex1.getMessage.contains("The number of lambda function arguments '1' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        dfExample1.selectExpr("transform_keys(i, k -> k)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "1", "actualNumArgs" -> "2"),
+      context = ExpectedContext(
+        fragment = "k -> k",
+        start = 18,
+        stop = 23)
+    )
 
-    val ex2 = intercept[AnalysisException] {
-      dfExample1.selectExpr("transform_keys(i, (k, v, x) -> k + 1)")
-    }
-    assert(ex2.getMessage.contains(
-      "The number of lambda function arguments '3' does not match"))
+    checkError(
+      exception = intercept[AnalysisException] {
+        dfExample1.selectExpr("transform_keys(i, (k, v, x) -> k + 1)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+      parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "2"),
+      context = ExpectedContext(
+        fragment = "(k, v, x) -> k + 1",
+        start = 18,
+        stop = 35)
+    )
 
     val ex3 = intercept[SparkException] {
       dfExample1.selectExpr("transform_keys(i, (k, v) -> v)").show()
@@ -5065,15 +5142,29 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
 
     def testInvalidLambdaFunctions(): Unit = {
 
-      val ex1 = intercept[AnalysisException] {
-        dfExample1.selectExpr("transform_values(i, k -> k)")
-      }
-      assert(ex1.getMessage.contains("The number of lambda function arguments '1' does not match"))
+      checkError(
+        exception = intercept[AnalysisException] {
+          dfExample1.selectExpr("transform_values(i, k -> k)")
+        },
+        errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+        parameters = Map("expectedNumArgs" -> "1", "actualNumArgs" -> "2"),
+        context = ExpectedContext(
+          fragment = "k -> k",
+          start = 20,
+          stop = 25)
+      )
 
-      val ex2 = intercept[AnalysisException] {
-        dfExample2.selectExpr("transform_values(j, (k, v, x) -> k + 1)")
-      }
-      assert(ex2.getMessage.contains("The number of lambda function arguments '3' does not match"))
+      checkError(
+        exception = intercept[AnalysisException] {
+          dfExample2.selectExpr("transform_values(j, (k, v, x) -> k + 1)")
+        },
+        errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
+        parameters = Map("expectedNumArgs" -> "3", "actualNumArgs" -> "2"),
+        context = ExpectedContext(
+          fragment = "(k, v, x) -> k + 1",
+          start = 20,
+          stop = 37)
+      )
 
       checkError(
         exception = intercept[AnalysisException] {
@@ -5175,16 +5266,30 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession {
       exception = intercept[AnalysisException] {
         df.selectExpr("zip_with(a1, a2, x -> x)")
       },
-      errorClass = "_LEGACY_ERROR_TEMP_2300",
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.NUM_ARGS_MISMATCH",
       parameters = Map(
-        "namesSize" -> "1",
-        "argInfoSize" -> "2"),
+        "expectedNumArgs" -> "1",
+        "actualNumArgs" -> "2"),
       context = ExpectedContext(
         fragment = "x -> x",
         start = 17,
         stop = 22)
     )
 
+    checkError(
+      exception = intercept[AnalysisException] {
+        df.selectExpr("zip_with(a1, a2, (x, x) -> x)")
+      },
+      errorClass = "INVALID_LAMBDA_FUNCTION_CALL.DUPLICATE_ARG_NAMES",
+      parameters = Map(
+        "args" -> "`x`, `x`",
+        "caseSensitiveConfig" -> "\"spark.sql.caseSensitive\""),
+      context = ExpectedContext(
+        fragment = "(x, x) -> x",
+        start = 17,
+        stop = 27)
+    )
+
     checkError(
       exception = intercept[AnalysisException] {
         df.selectExpr("zip_with(a1, a2, (acc, x) -> x, (acc, x) -> x)")


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org