[jOOQ/jOOQ#14675] Add a DataException for SQLState 22 and a IntegrityConstraintViolationException for SQLState 23
This commit is contained in:
parent
8c2cebaee9
commit
e35dfdbe04
@ -37,8 +37,13 @@
|
||||
*/
|
||||
package org.jooq.exception;
|
||||
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import io.r2dbc.spi.R2dbcException;
|
||||
|
||||
/**
|
||||
@ -78,14 +83,15 @@ public class DataAccessException extends RuntimeException {
|
||||
* <code>DataAccessException</code> 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 <code>DataAccessException</code> 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 <code>DataAccessException</code> 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 <code>null</code> if no root cause
|
||||
* of that type was found.
|
||||
*/
|
||||
@Nullable
|
||||
public <T extends Throwable> T getCause(Class<? extends T> type) {
|
||||
return ExceptionTools.getCause(this, type);
|
||||
}
|
||||
|
||||
76
jOOQ/src/main/java/org/jooq/exception/DataException.java
Normal file
76
jOOQ/src/main/java/org/jooq/exception/DataException.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.exception;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import io.r2dbc.spi.R2dbcException;
|
||||
|
||||
/**
|
||||
* The <code>DataException</code> is jOOQ's equivalent of JDBC's
|
||||
* {@link SQLDataException}.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -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 <T extends Throwable> T getCause(Throwable t, Class<? extends T> type) {
|
||||
Throwable next = t.getCause();
|
||||
Throwable prev;
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.exception;
|
||||
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
|
||||
/**
|
||||
* The <code>IntegrityConstraintViolationException</code> is jOOQ's equivalent
|
||||
* of JDBC's {@link SQLIntegrityConstraintViolationException}.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user