You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by ur...@apache.org on 2026/09/21 09:54:37 UTC

(spark) branch master updated: [SPARK-59582][SQL] Include original JDBC engine SQLSTATE in external engine syntax errors

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

uros-b 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 707d9814ba93 [SPARK-59582][SQL] Include original JDBC engine SQLSTATE in external engine syntax errors
707d9814ba93 is described below

commit 707d9814ba93652d3fa938e8aa48978b46a7ee69
Author: Alek Jarmov <al...@databricks.com>
AuthorDate: Mon Sep 21 09:54:20 2026 +0000

    [SPARK-59582][SQL] Include original JDBC engine SQLSTATE in external engine syntax errors
    
    ### What changes were proposed in this pull request?
    
    Surface the remote JDBC engine SQLSTATE on `JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR` as a structured message parameter, labeled separately from Spark's own SQLSTATE.
    
    ### Why are the changes needed?
    
    Improves observability by improving error grouping.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. The `JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR` message now includes the remote SQLSTATE.
    
    Previously:
    
    ```
    JDBC external engine syntax error. The error was caused by the query <jdbcQuery>. <externalEngineError>.
    ```
    
    Now:
    
    ```
    JDBC external engine syntax error. The error was caused by the query <jdbcQuery>. External engine SQLSTATE: <externalEngineSqlState>. <externalEngineError>.
    ```
    
    Spark's own SQLSTATE for this condition remains `42000`.
    
    ### How was this patch tested?
    
    Updated `SharedJDBCIntegrationSuite` so the SPARK-52184 wrapping test asserts Spark SQLSTATE `42000` and that `externalEngineSqlState` matches the cause `SQLException` (or `unknown` if the driver SQLSTATE is null or blank).
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Cursor Grok 4.6
    
    Closes #58862 from alekjarmov/alekjarmov/add-external-engine-sql-state.
    
    Authored-by: Alek Jarmov <al...@databricks.com>
    Signed-off-by: Uros Bojanic <22...@users.noreply.github.com>
---
 .../src/main/resources/error/error-conditions.json |  2 +-
 .../sql/jdbc/SharedJDBCIntegrationSuite.scala      | 23 +++++++++++++++++-----
 .../sql/execution/datasources/jdbc/JDBCRDD.scala   | 13 ++++++++++--
 3 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/common/utils/src/main/resources/error/error-conditions.json b/common/utils/src/main/resources/error/error-conditions.json
index f355f13b8f2e..07f85c7b0fc5 100644
--- a/common/utils/src/main/resources/error/error-conditions.json
+++ b/common/utils/src/main/resources/error/error-conditions.json
@@ -5741,7 +5741,7 @@
   },
   "JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR" : {
     "message" : [
-      "JDBC external engine syntax error. The error was caused by the query <jdbcQuery>. <externalEngineError>."
+      "JDBC external engine syntax error. The error was caused by the query <jdbcQuery>. External engine SQLSTATE: <externalEngineSqlState>. <externalEngineError>."
     ],
     "subClass" : {
       "DURING_OUTPUT_SCHEMA_RESOLUTION" : {
diff --git a/connector/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/SharedJDBCIntegrationSuite.scala b/connector/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/SharedJDBCIntegrationSuite.scala
index 05338e79998c..1850fef15cf1 100644
--- a/connector/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/SharedJDBCIntegrationSuite.scala
+++ b/connector/docker-integration-tests/src/test/scala/org/apache/spark/sql/jdbc/SharedJDBCIntegrationSuite.scala
@@ -17,7 +17,7 @@
 
 package org.apache.spark.sql.jdbc
 
-import java.sql.Connection
+import java.sql.{Connection, SQLException}
 
 import org.scalatest.time.SpanSugar._
 
@@ -63,14 +63,27 @@ abstract class SharedJDBCIntegrationSuite extends DockerJDBCIntegrationSuite {
 
     // Exception should be detected in analysis phase first when we resolve a schema from
     // through JDBC by sending SELECT * FROM (<subquery>) [LIMIT 1][WHERE 1=0] query.
-    checkErrorMatchPVals(
-      ex,
+    checkError(
+      exception = ex,
       condition = "JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR.DURING_OUTPUT_SCHEMA_RESOLUTION",
+      sqlState = Some("42000"),
       parameters = Map(
         "jdbcQuery" -> "SELECT \\* FROM \\(.*",
-        "externalEngineError" -> "[\\s\\S]*"
-      )
+        "externalEngineError" -> "[\\s\\S]+",
+        "externalEngineSqlState" -> ".+"
+      ),
+      matchPVals = true
     )
+    ex.getCause match {
+      case cause: SQLException =>
+        val expectedSqlState =
+          Option(cause.getSQLState).filter(_.nonEmpty).getOrElse("unknown")
+        assertResult(expectedSqlState) {
+          ex.getMessageParameters.get("externalEngineSqlState")
+        }
+      case other =>
+        fail(s"Expected SQLException cause, but got: $other")
+    }
   }
 
   test("SPARK-53386: Parameter `query` should work when ending with semicolons") {
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JDBCRDD.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JDBCRDD.scala
index 6636db6e70bb..a681517ccfc0 100644
--- a/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JDBCRDD.scala
+++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JDBCRDD.scala
@@ -87,7 +87,8 @@ object JDBCRDD extends Logging {
           errorClass = "JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR.DURING_OUTPUT_SCHEMA_RESOLUTION",
           messageParameters = Map(
             "jdbcQuery" -> fullQuery,
-            "externalEngineError" -> e.getMessage.replaceAll("\\.+$", "")
+            "externalEngineError" -> e.getMessage.replaceAll("\\.+$", ""),
+            "externalEngineSqlState" -> getSQLState(e)
           ),
           cause = e)
     }
@@ -119,6 +120,13 @@ object JDBCRDD extends Logging {
     }
   }
 
+  /**
+   * Gets the SQLSTATE of the provided SQL exception or "unknown" if it is not defined.
+   */
+  private def getSQLState(e: SQLException): String = {
+    Option(e.getSQLState).filter(_.nonEmpty).getOrElse("unknown")
+  }
+
   /**
    * Prune all but the specified columns from the specified Catalyst schema.
    *
@@ -379,7 +387,8 @@ class JDBCRDD(
             errorClass = "JDBC_EXTERNAL_ENGINE_SYNTAX_ERROR.DURING_QUERY_EXECUTION",
             messageParameters = Map(
               "jdbcQuery" -> sqlText,
-              "externalEngineError" -> e.getMessage.replaceAll("\\.+$", "")
+              "externalEngineError" -> e.getMessage.replaceAll("\\.+$", ""),
+              "externalEngineSqlState" -> JDBCRDD.getSQLState(e)
             ),
             cause = e)
       }


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