jdbc-protolib/src/main/java/com/streamsets/pipeline/lib/jdbc/JdbcUtil.java
public String formatSqlException(SQLException ex) {
    StringBuilder sb = new StringBuilder();
    Set<String> messages = new HashSet<>();
    for (Throwable e : ex) {
      if (e instanceof SQLException) {
        String message = e.getMessage();
        if (!messages.add(message)) {
          continue;
        }
        sb.append("SQLState: " + ((SQLException) e).getSQLState() + "\n")
            .append("Error Code: " + ((SQLException) e).getErrorCode() + "\n")
            .append("Message: " + message + "\n");
        Throwable t = ex.getCause();
        while (t != null) {
          if (messages.add(t.getMessage())) {
            sb.append("Cause: " + t + "\n");
          }
          t = t.getCause();
        }
      }
    }
    return sb.toString();
  }
public String formatSqlException(SQLException ex) {
    StringBuilder sb = new StringBuilder();
    Set<String> messages = new HashSet<>();
    for (Throwable e : ex) {
      if (e instanceof SQLException) {
        String message = e.getMessage();
        if (!messages.add(message)) {
          continue;
        }
        sb.append("SQLState: " + ((SQLException) e).getSQLState() + "\n")
            .append("Error Code: " + ((SQLException) e).getErrorCode() + "\n")
            .append("Message: " + message + "\n");
        Throwable t = ex.getCause();
        while (t != null) {
          if (messages.add(t.getMessage())) {
            sb.append("Cause: " + t + "\n");
          }
          t = t.getCause();
        }
      }
    }
    return sb.toString();
  }
Formats the error message of a {@link java.sql.SQLException} for human consumption.

@param ex SQLException
@return Formatted string with database-specific error code, error message, and SQLState