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

gurwls223 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 4aeddb8  [SPARK-36870][SQL] Introduce INTERNAL_ERROR error class
4aeddb8 is described below

commit 4aeddb81d1cc9c464d5dddbd4d54dda4836a6078
Author: Karen Feng <[email protected]>
AuthorDate: Fri Oct 1 13:46:45 2021 +0900

    [SPARK-36870][SQL] Introduce INTERNAL_ERROR error class
    
    ### What changes were proposed in this pull request?
    
    Adds the `INTERNAL_ERROR` error class and the `isInternalError` API to 
`SparkThrowable`.
    Removes existing error classes that are internal-only and replaces them 
with `INTERNAL_ERROR`.
    
    ### Why are the changes needed?
    
    Makes it easy for end-users to diagnose whether an error is an internal 
error. If an end-user encounters an internal error, it should be reported 
immediately. This also limits the number of error classes, making it easy to 
audit. We do not need high-quality error messages for internal errors, as they 
should not be exposed to the end-user.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes; this changes the error class in master.
    
    ### How was this patch tested?
    
    Unit tests
    
    Closes #34123 from karenfeng/internal-error-class.
    
    Authored-by: Karen Feng <[email protected]>
    Signed-off-by: Hyukjin Kwon <[email protected]>
---
 .../main/java/org/apache/spark/SparkThrowable.java |  9 +++++++-
 .../apache/spark/memory/SparkOutOfMemoryError.java |  4 ----
 core/src/main/resources/error/README.md            | 19 ++++++++--------
 core/src/main/resources/error/error-classes.json   | 19 +++-------------
 .../main/scala/org/apache/spark/ErrorInfo.scala    |  4 ++++
 .../scala/org/apache/spark/SparkException.scala    | 20 -----------------
 .../org/apache/spark/SparkThrowableSuite.scala     | 17 +++++++++++++++
 .../org/apache/spark/sql/AnalysisException.scala   |  1 -
 .../spark/sql/errors/QueryExecutionErrors.scala    | 25 ++++++++++++----------
 9 files changed, 56 insertions(+), 62 deletions(-)

diff --git a/core/src/main/java/org/apache/spark/SparkThrowable.java 
b/core/src/main/java/org/apache/spark/SparkThrowable.java
index 31a9ab0..2be0c3c 100644
--- a/core/src/main/java/org/apache/spark/SparkThrowable.java
+++ b/core/src/main/java/org/apache/spark/SparkThrowable.java
@@ -38,5 +38,12 @@ public interface SparkThrowable {
 
   // Portable error identifier across SQL engines
   // If null, error class or SQLSTATE is not set
-  String getSqlState();
+  default String getSqlState() {
+    return SparkThrowableHelper.getSqlState(this.getErrorClass());
+  }
+
+  // True if this error is an internal error.
+  default boolean isInternalError() {
+    return SparkThrowableHelper.isInternalError(this.getErrorClass());
+  }
 }
diff --git 
a/core/src/main/java/org/apache/spark/memory/SparkOutOfMemoryError.java 
b/core/src/main/java/org/apache/spark/memory/SparkOutOfMemoryError.java
index bf7984b..88eada3 100644
--- a/core/src/main/java/org/apache/spark/memory/SparkOutOfMemoryError.java
+++ b/core/src/main/java/org/apache/spark/memory/SparkOutOfMemoryError.java
@@ -47,8 +47,4 @@ public final class SparkOutOfMemoryError extends 
OutOfMemoryError implements Spa
     public String getErrorClass() {
         return errorClass;
     }
-
-    public String getSqlState() {
-        return SparkThrowableHelper.getSqlState(errorClass);
-    }
 }
diff --git a/core/src/main/resources/error/README.md 
b/core/src/main/resources/error/README.md
index c4ab6bb..f58eb6d 100644
--- a/core/src/main/resources/error/README.md
+++ b/core/src/main/resources/error/README.md
@@ -5,13 +5,16 @@ and message parameters rather than an arbitrary error message.
 
 ## Usage
 
-1. Check if an appropriate error class already exists in `error-class.json`.
-   If true, skip to step 3. Otherwise, continue to step 2.
-2. Add a new class to `error-class.json`; keep in mind the invariants below.
-3. Check if the exception type already extends `SparkThrowable`.
-   If true, skip to step 5. Otherwise, continue to step 4.
-4. Mix `SparkThrowable` into the exception.
-5. Throw the exception with the error class and message parameters.
+1. Check if the error is an internal error.
+   Internal errors are bugs in the code that we do not expect users to 
encounter; this does not include unsupported operations.
+   If true, use the error class `INTERNAL_ERROR` and skip to step 4.
+2. Check if an appropriate error class already exists in `error-class.json`.
+   If true, use the error class and skip to step 4.
+3. Add a new class to `error-class.json`; keep in mind the invariants below.
+4. Check if the exception type already extends `SparkThrowable`.
+   If true, skip to step 6.
+5. Mix `SparkThrowable` into the exception.
+6. Throw the exception with the error class and message parameters.
 
 ### Before
 
@@ -37,8 +40,6 @@ Throw with arbitrary error message:
         with SparkThrowable {
         
       def getErrorClass: String = errorClass
-      def getMessageParameters: Array[String] = messageParameters
-      def getSqlState: String = SparkThrowableHelper.getSqlState(errorClass)
     }
 
 Throw with error class and message parameters:
diff --git a/core/src/main/resources/error/error-classes.json 
b/core/src/main/resources/error/error-classes.json
index 31b2144..d270f0e 100644
--- a/core/src/main/resources/error/error-classes.json
+++ b/core/src/main/resources/error/error-classes.json
@@ -11,19 +11,10 @@
     "message" : [ "%s cannot be represented as Decimal(%s, %s)." ],
     "sqlState" : "22005"
   },
-  "CANNOT_EVALUATE_EXPRESSION" : {
-    "message" : [ "Cannot evaluate expression: %s" ]
-  },
-  "CANNOT_GENERATE_CODE_FOR_EXPRESSION" : {
-    "message" : [ "Cannot generate code for expression: %s" ]
-  },
   "CANNOT_PARSE_DECIMAL" : {
     "message" : [ "Cannot parse decimal" ],
     "sqlState" : "42000"
   },
-  "CANNOT_TERMINATE_GENERATOR" : {
-    "message" : [ "Cannot terminate expression: %s" ]
-  },
   "CAST_CAUSES_OVERFLOW" : {
     "message" : [ "Casting %s to %s causes overflow" ],
     "sqlState" : "22005"
@@ -74,6 +65,9 @@
     "message" : [ "Index %s must be between 0 and the length of the 
ArrayData." ],
     "sqlState" : "22023"
   },
+  "INTERNAL_ERROR" : {
+    "message" : [ "%s" ]
+  },
   "INVALID_ARRAY_INDEX" : {
     "message" : [ "Invalid index: %s, numElements: %s" ]
   },
@@ -92,9 +86,6 @@
   "INVALID_JSON_SCHEMA_MAPTYPE" : {
     "message" : [ "Input schema %s can only contain StringType as a key type 
for a MapType." ]
   },
-  "LOGICAL_HINT_OPERATOR_NOT_REMOVED_DURING_ANALYSIS" : {
-    "message" : [ "Internal error: logical hint operator should have been 
removed during analysis" ]
-  },
   "MAP_KEY_DOES_NOT_EXIST" : {
     "message" : [ "Key %s does not exist." ]
   },
@@ -102,10 +93,6 @@
     "message" : [ "cannot resolve '%s' given input columns: [%s]" ],
     "sqlState" : "42000"
   },
-  "MISSING_METHOD" : {
-    "message" : [ "A method named \"%s\" is not declared in any enclosing 
class nor any supertype" ],
-    "sqlState" : "42000"
-  },
   "MISSING_STATIC_PARTITION_COLUMN" : {
     "message" : [ "Unknown static partition column: %s" ],
     "sqlState" : "42000"
diff --git a/core/src/main/scala/org/apache/spark/ErrorInfo.scala 
b/core/src/main/scala/org/apache/spark/ErrorInfo.scala
index 67a363c..0917085 100644
--- a/core/src/main/scala/org/apache/spark/ErrorInfo.scala
+++ b/core/src/main/scala/org/apache/spark/ErrorInfo.scala
@@ -64,4 +64,8 @@ private[spark] object SparkThrowableHelper {
   def getSqlState(errorClass: String): String = {
     
Option(errorClass).flatMap(errorClassToInfoMap.get).flatMap(_.sqlState).orNull
   }
+
+  def isInternalError(errorClass: String): Boolean = {
+    errorClass == "INTERNAL_ERROR"
+  }
 }
diff --git a/core/src/main/scala/org/apache/spark/SparkException.scala 
b/core/src/main/scala/org/apache/spark/SparkException.scala
index c508864..aea09e3 100644
--- a/core/src/main/scala/org/apache/spark/SparkException.scala
+++ b/core/src/main/scala/org/apache/spark/SparkException.scala
@@ -45,7 +45,6 @@ class SparkException(
       messageParameters = messageParameters)
 
   override def getErrorClass: String = errorClass.orNull
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass.orNull)
 }
 
 /**
@@ -84,7 +83,6 @@ private[spark] class SparkArithmeticException(errorClass: 
String, messageParamet
     with SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -97,7 +95,6 @@ private[spark] class SparkUnsupportedOperationException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -111,7 +108,6 @@ private[spark] class SparkClassNotFoundException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters), cause) 
with SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -125,7 +121,6 @@ private[spark] class SparkConcurrentModificationException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters), cause) 
with SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -136,7 +131,6 @@ private[spark] class SparkDateTimeException(errorClass: 
String, messageParameter
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -149,7 +143,6 @@ private[spark] class SparkFileAlreadyExistsException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -162,7 +155,6 @@ private[spark] class SparkIllegalStateException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -175,7 +167,6 @@ private[spark] class SparkFileNotFoundException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -188,7 +179,6 @@ private[spark] class SparkNumberFormatException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -201,7 +191,6 @@ private[spark] class SparkNoSuchMethodException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -214,7 +203,6 @@ private[spark] class SparkIllegalArgumentException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -227,7 +215,6 @@ private[spark] class SparkIndexOutOfBoundsException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -240,7 +227,6 @@ private[spark] class SparkIOException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 private[spark] class SparkRuntimeException(
@@ -251,7 +237,6 @@ private[spark] class SparkRuntimeException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters), cause) 
with SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -264,7 +249,6 @@ private[spark] class SparkSecurityException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -277,7 +261,6 @@ private[spark] class SparkArrayIndexOutOfBoundsException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -290,7 +273,6 @@ private[spark] class SparkSQLException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -303,7 +285,6 @@ private[spark] class SparkNoSuchElementException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
 
 /**
@@ -316,5 +297,4 @@ private[spark] class SparkSQLFeatureNotSupportedException(
     SparkThrowableHelper.getMessage(errorClass, messageParameters)) with 
SparkThrowable {
 
   override def getErrorClass: String = errorClass
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass)
 }
diff --git a/core/src/test/scala/org/apache/spark/SparkThrowableSuite.scala 
b/core/src/test/scala/org/apache/spark/SparkThrowableSuite.scala
index 750b2ee..5af55af 100644
--- a/core/src/test/scala/org/apache/spark/SparkThrowableSuite.scala
+++ b/core/src/test/scala/org/apache/spark/SparkThrowableSuite.scala
@@ -160,4 +160,21 @@ class SparkThrowableSuite extends SparkFunSuite {
         assert(false)
     }
   }
+
+  test("Try catching internal SparkError") {
+    try {
+      throw new SparkException(
+        errorClass = "INTERNAL_ERROR",
+        messageParameters = Array("this is an internal error"),
+        cause = null
+      )
+    } catch {
+      case e: SparkThrowable =>
+        assert(e.isInternalError)
+        assert(e.getSqlState == null)
+      case _: Throwable =>
+        // Should not end up here
+        assert(false)
+    }
+  }
 }
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/AnalysisException.scala 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/AnalysisException.scala
index 35eb040..397300d 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/AnalysisException.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/AnalysisException.scala
@@ -92,5 +92,4 @@ class AnalysisException protected[sql] (
   }
 
   override def getErrorClass: String = errorClass.orNull
-  override def getSqlState: String = 
SparkThrowableHelper.getSqlState(errorClass.orNull)
 }
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
index 8e43f48..3fe367b 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
@@ -72,23 +72,24 @@ object QueryExecutionErrors {
   }
 
   def logicalHintOperatorNotRemovedDuringAnalysisError(): Throwable = {
-    new SparkIllegalStateException(errorClass = 
"LOGICAL_HINT_OPERATOR_NOT_REMOVED_DURING_ANALYSIS",
-      messageParameters = Array.empty)
+    new SparkIllegalStateException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(
+        "Internal error: logical hint operator should have been removed during 
analysis"))
   }
 
   def cannotEvaluateExpressionError(expression: Expression): Throwable = {
-    new SparkUnsupportedOperationException(errorClass = 
"CANNOT_EVALUATE_EXPRESSION",
-      messageParameters = Array("", expression.toString))
+    new SparkUnsupportedOperationException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(s"Cannot evaluate expression: $expression"))
   }
 
   def cannotGenerateCodeForExpressionError(expression: Expression): Throwable 
= {
-    new SparkUnsupportedOperationException(errorClass = 
"CANNOT_GENERATE_CODE_FOR_EXPRESSION",
-      messageParameters = Array(expression.toString))
+    new SparkUnsupportedOperationException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(s"Cannot generate code for expression: 
$expression"))
   }
 
   def cannotTerminateGeneratorError(generator: UnresolvedGenerator): Throwable 
= {
-    new SparkUnsupportedOperationException(errorClass = 
"CANNOT_TERMINATE_GENERATOR",
-      messageParameters = Array(generator.toString))
+    new SparkUnsupportedOperationException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(s"Cannot terminate expression: $generator"))
   }
 
   def castingCauseOverflowError(t: Any, targetType: String): 
ArithmeticException = {
@@ -130,8 +131,8 @@ object QueryExecutionErrors {
 
   def evaluateUnevaluableAggregateUnsupportedError(
       methodName: String, unEvaluable: UnevaluableAggregate): Throwable = {
-    new SparkUnsupportedOperationException(errorClass = 
"CANNOT_EVALUATE_EXPRESSION",
-      messageParameters = Array(methodName + ": " + unEvaluable.toString))
+    new SparkUnsupportedOperationException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(s"Cannot evaluate expression: $methodName: 
$unEvaluable"))
   }
 
   def dataTypeUnsupportedError(dt: DataType): Throwable = {
@@ -279,7 +280,9 @@ object QueryExecutionErrors {
   }
 
   def methodNotDeclaredError(name: String): Throwable = {
-    new SparkNoSuchMethodException(errorClass = "MISSING_METHOD", Array(name))
+    new SparkNoSuchMethodException(errorClass = "INTERNAL_ERROR",
+      messageParameters = Array(
+        s"""A method named "$name" is not declared in any enclosing class nor 
any supertype"""))
   }
 
   def constructorNotFoundError(cls: String): Throwable = {

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to