DataAccessException was caused by a {@link SQLException} or
* {@link R2dbcException}.
*/
+ @NotNull
public String sqlState() {
SQLException s = getCause(SQLException.class);
if (s != null)
- return s.getSQLState();
+ return defaultIfNull(s.getSQLState(), "00000");
R2dbcException r = getCause(R2dbcException.class);
if (r != null)
- return r.getSqlState();
+ return defaultIfNull(r.getSqlState(), "00000");
return "00000";
}
@@ -96,28 +102,51 @@ public class DataAccessException extends RuntimeException {
* {@link SQLStateClass}, if this DataAccessException was
* caused by a {@link SQLException} or {@link R2dbcException}.
*/
+ @NotNull
public SQLStateClass sqlStateClass() {
SQLException s = getCause(SQLException.class);
if (s != null)
- if (s.getSQLState() != null)
- return SQLStateClass.fromCode(s.getSQLState());
- else if (s.getSQLState() == null && "org.sqlite.SQLiteException".equals(s.getClass().getName()))
- return SQLStateClass.fromSQLiteVendorCode(s.getErrorCode());
+ return sqlStateClass(s);
R2dbcException r = getCause(R2dbcException.class);
if (r != null)
- if (r.getSqlState() != null)
- return SQLStateClass.fromCode(r.getSqlState());
+ return sqlStateClass(r);
return SQLStateClass.NONE;
}
+ /**
+ * Decode the {@link SQLException#getSQLState()} into {@link SQLStateClass}.
+ */
+ @NotNull
+ public static SQLStateClass sqlStateClass(SQLException e) {
+ if (e.getSQLState() != null)
+ return SQLStateClass.fromCode(e.getSQLState());
+ else if (e.getSQLState() == null && "org.sqlite.SQLiteException".equals(e.getClass().getName()))
+ return SQLStateClass.fromSQLiteVendorCode(e.getErrorCode());
+ else
+ return SQLStateClass.NONE;
+ }
+
+ /**
+ * Decode the {@link R2dbcException#getSqlState()} into
+ * {@link SQLStateClass}.
+ */
+ @NotNull
+ public static SQLStateClass sqlStateClass(R2dbcException e) {
+ if (e.getSqlState() != null)
+ return SQLStateClass.fromCode(e.getSqlState());
+ else
+ return SQLStateClass.NONE;
+ }
+
/**
* Decode the {@link SQLException#getSQLState()} or
* {@link R2dbcException#getSqlState()} from {@link #getCause()} into
* {@link SQLStateSubclass}, if this DataAccessException was
* caused by a {@link SQLException} or {@link R2dbcException}.
*/
+ @NotNull
public SQLStateSubclass sqlStateSubclass() {
return SQLStateSubclass.fromCode(sqlState());
}
@@ -131,6 +160,7 @@ public class DataAccessException extends RuntimeException {
* Find a root cause of a given type, or null if no root cause
* of that type was found.
*/
+ @Nullable
public DataException is jOOQ's equivalent of JDBC's
+ * {@link SQLDataException}.
+ *
+ * It is thrown by jOOQ whenever jOOQ detects
+ * {@link SQLStateClass#C22_DATA_EXCEPTION} from the JDBC driver. Whether this
+ * SQL state is available is JDBC driver implementation specific.
+ *
+ * @author Lukas Eder
+ */
+public class DataException extends DataAccessException {
+
+ /**
+ * Constructor for DataException.
+ *
+ * @param message the detail message
+ */
+ public DataException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor for DataException.
+ *
+ * @param message the detail message
+ * @param cause the root cause (usually from using a underlying data access
+ * API such as JDBC)
+ */
+ public DataException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/exception/ExceptionTools.java b/jOOQ/src/main/java/org/jooq/exception/ExceptionTools.java
index be76006294..5358750246 100644
--- a/jOOQ/src/main/java/org/jooq/exception/ExceptionTools.java
+++ b/jOOQ/src/main/java/org/jooq/exception/ExceptionTools.java
@@ -37,6 +37,8 @@
*/
package org.jooq.exception;
+import org.jetbrains.annotations.Nullable;
+
/**
* @author Lukas Eder
*/
@@ -52,6 +54,7 @@ public final class ExceptionTools {
* of that type was found.
*/
@SuppressWarnings("unchecked")
+ @Nullable
public static
+ * It is thrown by jOOQ whenever jOOQ detects
+ * {@link SQLStateClass#C23_INTEGRITY_CONSTRAINT_VIOLATION} from the JDBC
+ * driver. Whether this SQL state is available is JDBC driver implementation
+ * specific.
+ *
+ * @author Lukas Eder
+ */
+public class IntegrityConstraintViolationException extends DataAccessException {
+
+ /**
+ * Constructor for IntegrityConstraintViolationException.
+ *
+ * @param message the detail message
+ */
+ public IntegrityConstraintViolationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor for IntegrityConstraintViolationException.
+ *
+ * @param message the detail message
+ * @param cause the root cause (usually from using a underlying data access
+ * API such as JDBC)
+ */
+ public IntegrityConstraintViolationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/exception/SQLStateClass.java b/jOOQ/src/main/java/org/jooq/exception/SQLStateClass.java
index dd9929ee87..9f73b66d03 100644
--- a/jOOQ/src/main/java/org/jooq/exception/SQLStateClass.java
+++ b/jOOQ/src/main/java/org/jooq/exception/SQLStateClass.java
@@ -40,6 +40,8 @@ package org.jooq.exception;
import java.util.HashMap;
import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+
/**
* The class of the SQL state as specified by the SQL:2011 standard, or by individual
* vendors.
@@ -165,10 +167,12 @@ public enum SQLStateClass {
this.className = className;
}
+ @NotNull
public String className() {
return className;
}
+ @NotNull
public static SQLStateClass fromCode(String code) {
if (code == null || code.length() < 2)
return SQLStateClass.OTHER;
@@ -177,6 +181,7 @@ public enum SQLStateClass {
return result != null ? result : SQLStateClass.OTHER;
}
+ @NotNull
static SQLStateClass fromSQLiteVendorCode(int errorCode) {
// See https://sqlite.org/c3ref/c_abort.html
diff --git a/jOOQ/src/main/java/org/jooq/exception/SQLStateSubclass.java b/jOOQ/src/main/java/org/jooq/exception/SQLStateSubclass.java
index 59e67b8211..b94ae88b96 100644
--- a/jOOQ/src/main/java/org/jooq/exception/SQLStateSubclass.java
+++ b/jOOQ/src/main/java/org/jooq/exception/SQLStateSubclass.java
@@ -88,6 +88,8 @@ import static org.jooq.exception.SQLStateClass.CHZ_REMOTE_DATABASE_ACCESS;
import java.util.HashMap;
import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+
/**
* The subclass of the SQL state class as specified by the SQL standard, or by individual
* vendors.
@@ -460,18 +462,22 @@ public enum SQLStateSubclass {
this.subclass = subclass;
}
+ @NotNull
public String sqlStateSubclassName() {
return subclass;
}
+ @NotNull
public SQLStateClass sqlStateClass() {
return clazz;
}
+ @NotNull
public String sqlStateClassName() {
return sqlStateClass().className();
}
+ @NotNull
public static SQLStateSubclass fromCode(String code) {
if (code == null || code.length() != 5)
return SQLStateSubclass.OTHER;
@@ -488,6 +494,7 @@ public enum SQLStateSubclass {
return SQLStateSubclass.OTHER;
}
+ @NotNull
static SQLStateSubclass fromSQLiteVendorCode(int errorCode) {
// See https://sqlite.org/c3ref/c_abort.html
diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java
index 0bcc013c48..7d10fad725 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Tools.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java
@@ -88,6 +88,7 @@ import static org.jooq.conf.SettingsTools.getBackslashEscaping;
import static org.jooq.conf.SettingsTools.updatablePrimaryKeys;
import static org.jooq.conf.ThrowExceptions.THROW_FIRST;
import static org.jooq.conf.ThrowExceptions.THROW_NONE;
+import static org.jooq.exception.DataAccessException.sqlStateClass;
import static org.jooq.impl.CacheType.REFLECTION_CACHE_GET_ANNOTATED_GETTER;
import static org.jooq.impl.CacheType.REFLECTION_CACHE_GET_ANNOTATED_MEMBERS;
import static org.jooq.impl.CacheType.REFLECTION_CACHE_GET_ANNOTATED_SETTERS;
@@ -339,11 +340,14 @@ import org.jooq.conf.Settings;
import org.jooq.conf.SettingsTools;
import org.jooq.conf.ThrowExceptions;
import org.jooq.exception.DataAccessException;
+import org.jooq.exception.DataException;
import org.jooq.exception.DataTypeException;
import org.jooq.exception.DetachedException;
import org.jooq.exception.ExceptionTools;
+import org.jooq.exception.IntegrityConstraintViolationException;
import org.jooq.exception.MappingException;
import org.jooq.exception.NoDataFoundException;
+import org.jooq.exception.SQLStateClass;
import org.jooq.exception.TemplatingException;
import org.jooq.exception.TooManyRowsException;
import org.jooq.impl.QOM.Quantifier;
@@ -3412,7 +3416,7 @@ final class Tools {
*/
static final DataAccessException translate(String sql, R2dbcException e) {
if (e != null)
- return new DataAccessException("SQL [" + sql + "]; " + e.getMessage(), e);
+ return translate(sql, e, sqlStateClass(e));
else
return new DataAccessException("SQL [" + sql + "]; Unspecified R2dbcException");
}
@@ -3422,11 +3426,22 @@ final class Tools {
*/
static final DataAccessException translate(String sql, SQLException e) {
if (e != null)
- return new DataAccessException("SQL [" + sql + "]; " + e.getMessage(), e);
+ return translate(sql, e, sqlStateClass(e));
else
return new DataAccessException("SQL [" + sql + "]; Unspecified SQLException");
}
+ private static final DataAccessException translate(String sql, Exception e, SQLStateClass sqlState) {
+ switch (sqlState) {
+ case C22_DATA_EXCEPTION:
+ return new DataException("SQL [" + sql + "]; " + e.getMessage(), e);
+ case C23_INTEGRITY_CONSTRAINT_VIOLATION:
+ return new IntegrityConstraintViolationException("SQL [" + sql + "]; " + e.getMessage(), e);
+ default:
+ return new DataAccessException("SQL [" + sql + "]; " + e.getMessage(), e);
+ }
+ }
+
/**
* Translate a {@link RuntimeException} to a {@link DataAccessException}
*/
IntegrityConstraintViolationException is jOOQ's equivalent
+ * of JDBC's {@link SQLIntegrityConstraintViolationException}.
+ *