j1wonpark opened a new pull request, #57009:
URL: https://github.com/apache/spark/pull/57009
### What changes were proposed in this pull request?
Two commits:
1. `GrpcExceptionConverter` now preserves the original
`StatusRuntimeException`
as the cause of fallback errors (errors without `ErrorInfo`), generalizing
what the `DEADLINE_EXCEEDED` branch already did for the same reason.
2. The Connect JDBC driver maps client failures to `SQLException` at the two
points where they cross the JDBC boundary: `SparkConnectStatement.execute`
(`executeQuery`/`executeUpdate` route through it) and
`SparkConnectResultSet.next` (rows are fetched lazily, so errors during
result streaming surface there).
| Error | Mapped to | SQLState |
|---|---|---|
| `INVALID_HANDLE.SESSION_*` (session is gone) |
`SQLNonTransientConnectionException` | `08003` |
| gRPC `UNAVAILABLE` | `SQLTransientConnectionException` | `08006` |
| gRPC `DEADLINE_EXCEEDED` | `SQLTimeoutException` | `HYT00` |
| Anything else | `SQLException` | server-provided |
The gRPC status is read only from the `StatusRuntimeException` preserved in
the cause chain (commit 1), never from message text, so a server-side error
that merely quotes a gRPC exception cannot be mistaken for a transport
failure. The original exception is always kept as the cause.
Notes on the mapping:
- Operation-level `INVALID_HANDLE` subconditions (`OPERATION_*`, `FORMAT`)
are not connection errors: the session is still healthy.
- `DEADLINE_EXCEEDED` is a timeout, not a connection failure: a slow query
fires it on a healthy connection, and the client's own `RetryPolicy`
deliberately excludes it from retryable errors.
Other JDBC entry points (`Connection.setCatalog`, `DatabaseMetaData` query
methods, `Statement.cancel`) will be covered in a follow-up.
### Why are the changes needed?
Currently unchecked exceptions (e.g. `SparkException`) leak across the JDBC
boundary: standard JDBC code catching `SQLException` misses them, and there
is no SQLState to act on. SQLState class 08 is how connection pools (e.g.
HikariCP) and BI tools detect a dead connection and reconnect; without it
they keep handing out a connection whose server-side session is gone.
### Does this PR introduce _any_ user-facing change?
Yes, for the unreleased Connect JDBC driver:
stmt.execute("SELECT * FROM nonexistent")
// before: throws AnalysisException (unchecked)
// after: throws SQLException with getSQLState() == "42P01"
For other Connect clients, the only observable change is that fallback
`SparkException`s now carry the original `StatusRuntimeException` as their
cause (previously often null); messages are unchanged.
### How was this patch tested?
- `SparkConnectClientSuite`: new test that transport errors preserve the
gRPC exception as the cause; existing deadline tests still pass.
- New `JdbcErrorUtilsSuite`: 13 unit tests covering the mapping table,
precedence, cause-chain traversal, and the quoted-gRPC-text negative case.
- Integration tests: a failing query throws `SQLException`/`42P01` from
`execute`; a mid-stream failure (ANSI divide-by-zero) throws
`SQLException`/`22012` from `next`.
Ran `build/sbt "connect-client-jdbc/test"` and scalastyle.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (claude-fable-5)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]