[jOOQ/jOOQ#15732] Reverse engineer error message to detect SQLStateClass
This commit is contained in:
parent
2de610aecc
commit
0de1d5563c
@ -76,6 +76,8 @@ import io.r2dbc.spi.R2dbcException;
|
||||
*/
|
||||
public class DataAccessException extends RuntimeException {
|
||||
|
||||
SQLStateClass sqlStateClass;
|
||||
|
||||
/**
|
||||
* Constructor for DataAccessException.
|
||||
*
|
||||
@ -123,6 +125,9 @@ public class DataAccessException extends RuntimeException {
|
||||
*/
|
||||
@NotNull
|
||||
public SQLStateClass sqlStateClass() {
|
||||
if (sqlStateClass != null)
|
||||
return sqlStateClass;
|
||||
|
||||
SQLException s = getCause(SQLException.class);
|
||||
if (s != null)
|
||||
return sqlStateClass(s);
|
||||
@ -134,6 +139,14 @@ public class DataAccessException extends RuntimeException {
|
||||
return SQLStateClass.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SQLStateClass}.
|
||||
*/
|
||||
public DataAccessException sqlStateClass(SQLStateClass c) {
|
||||
this.sqlStateClass = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the {@link SQLException#getSQLState()} into {@link SQLStateClass}.
|
||||
*/
|
||||
@ -155,11 +168,12 @@ public class DataAccessException extends RuntimeException {
|
||||
|
||||
|
||||
|
||||
|
||||
if (e.getSQLState() != null)
|
||||
return SQLStateClass.fromCode(e.getSQLState());
|
||||
else if (e.getSQLState() == null && causePrefix(e, "org.sqlite"))
|
||||
else if (causePrefix(e, "org.sqlite"))
|
||||
return SQLStateClass.fromSQLiteVendorCode(e.getErrorCode());
|
||||
else if (e.getSQLState() == null && causePrefix(e, "io.trino"))
|
||||
else if (causePrefix(e, "io.trino"))
|
||||
return SQLStateClass.fromTrinoVendorCode(e.getErrorCode());
|
||||
else
|
||||
return SQLStateClass.NONE;
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.exception;
|
||||
|
||||
import static org.jooq.exception.SQLStateClass.C22_DATA_EXCEPTION;
|
||||
|
||||
import java.sql.SQLDataException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@ -61,6 +63,8 @@ public class DataException extends DataAccessException {
|
||||
*/
|
||||
public DataException(String message) {
|
||||
super(message);
|
||||
|
||||
sqlStateClass(C22_DATA_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,5 +76,7 @@ public class DataException extends DataAccessException {
|
||||
*/
|
||||
public DataException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
|
||||
sqlStateClass(C22_DATA_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.exception;
|
||||
|
||||
import static org.jooq.exception.SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION;
|
||||
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
|
||||
/**
|
||||
@ -59,6 +61,8 @@ public class IntegrityConstraintViolationException extends DataAccessException {
|
||||
*/
|
||||
public IntegrityConstraintViolationException(String message) {
|
||||
super(message);
|
||||
|
||||
sqlStateClass(C23_INTEGRITY_CONSTRAINT_VIOLATION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,5 +74,7 @@ public class IntegrityConstraintViolationException extends DataAccessException {
|
||||
*/
|
||||
public IntegrityConstraintViolationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
|
||||
sqlStateClass(C23_INTEGRITY_CONSTRAINT_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ abstract class AbstractBindContext extends AbstractContext<BindContext> implemen
|
||||
return bindValue0(value, field);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate(null, e);
|
||||
throw Tools.translate(this, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -246,7 +246,7 @@ abstract class AbstractQuery<R extends Record> extends AbstractAttachableQueryPa
|
||||
statement = null;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate(rendered.sql, e);
|
||||
throw Tools.translate(create(), rendered.sql, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,7 +258,7 @@ abstract class AbstractQuery<R extends Record> extends AbstractAttachableQueryPa
|
||||
statement.cancel();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate(rendered.sql, e);
|
||||
throw Tools.translate(create(), rendered.sql, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ abstract class AbstractQueryPart implements QueryPartInternal {
|
||||
* Internal convenience method
|
||||
*/
|
||||
protected final DataAccessException translate(String sql, SQLException e) {
|
||||
return Tools.translate(sql, e);
|
||||
return Tools.translate(create(), sql, e);
|
||||
}
|
||||
|
||||
private static final JooqLogger log = JooqLogger.getLogger(AbstractQueryPart.class, "serialization", 100);
|
||||
|
||||
@ -626,7 +626,7 @@ implements
|
||||
listener.executeEnd(ctx);
|
||||
|
||||
if (e != null)
|
||||
results.resultsOrRows().add(new ResultOrRowsImpl(Tools.translate(ctx.sql(), e)));
|
||||
results.resultsOrRows().add(new ResultOrRowsImpl(Tools.translate(ctx, ctx.sql(), e)));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -126,6 +126,7 @@ import static org.jooq.impl.SQLDataType.JSON;
|
||||
import static org.jooq.impl.SQLDataType.JSONB;
|
||||
import static org.jooq.impl.SQLDataType.TIME;
|
||||
import static org.jooq.impl.SQLDataType.TIMESTAMP;
|
||||
import static org.jooq.impl.Tools.CTX;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.combine;
|
||||
import static org.jooq.impl.Tools.configuration;
|
||||
@ -578,7 +579,7 @@ public class DSL {
|
||||
return new DefaultCloseableDSLContext(new DefaultCloseableConnectionProvider(connection), JDBCUtils.dialect(connection));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate("Error when initialising Connection", e);
|
||||
throw Tools.translate(CTX.get(), "Error when initialising Connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -620,7 +621,7 @@ public class DSL {
|
||||
return new DefaultCloseableDSLContext(new DefaultCloseableConnectionProvider(connection), JDBCUtils.dialect(connection));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate("Error when initialising Connection", e);
|
||||
throw Tools.translate(CTX.get(), "Error when initialising Connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -661,7 +662,7 @@ public class DSL {
|
||||
return new DefaultCloseableDSLContext(new DefaultCloseableConnectionProvider(connection), JDBCUtils.dialect(connection));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate("Error when initialising Connection", e);
|
||||
throw Tools.translate(CTX.get(), "Error when initialising Connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -797,7 +797,7 @@ class DefaultExecuteContext implements ExecuteContext {
|
||||
|
||||
@Override
|
||||
public final void exception(RuntimeException e) {
|
||||
this.exception = Tools.translate(sql(), e);
|
||||
this.exception = Tools.translate(this, sql(), e);
|
||||
|
||||
if (Boolean.TRUE.equals(settings().isDebugInfoOnStackTrace())) {
|
||||
|
||||
@ -824,7 +824,7 @@ class DefaultExecuteContext implements ExecuteContext {
|
||||
@Override
|
||||
public final void sqlException(SQLException e) {
|
||||
this.sqlException = e;
|
||||
exception(Tools.translate(sql(), e));
|
||||
exception(Tools.translate(this, sql(), e));
|
||||
|
||||
if (family() == SQLDialect.DEFAULT && logDefaultDialect.isWarnEnabled())
|
||||
logDefaultDialect.warn("Unsupported dialect",
|
||||
|
||||
@ -160,7 +160,7 @@ final class MetaDataFieldProvider implements Serializable {
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Tools.translate(null, e);
|
||||
throw Tools.translate(configuration.dsl(), null, e);
|
||||
}
|
||||
|
||||
return new FieldsImpl<>(fields);
|
||||
|
||||
@ -246,7 +246,7 @@ final class R2DBC {
|
||||
|
||||
@Override
|
||||
public final void onError(Throwable t) {
|
||||
complete(true, () -> resultSubscriber.downstream.subscriber.onError(translate(resultSubscriber.downstream.sql(), t)));
|
||||
complete(true, () -> resultSubscriber.downstream.subscriber.onError(translate(resultSubscriber.downstream.configuration.dsl(), resultSubscriber.downstream.sql(), t)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -282,7 +282,7 @@ final class R2DBC {
|
||||
|
||||
@Override
|
||||
public final void onError(Throwable t) {
|
||||
complete(true, () -> downstream.subscriber.onError(translate(downstream.sql(), t)));
|
||||
complete(true, () -> downstream.subscriber.onError(translate(downstream.configuration.dsl(), downstream.sql(), t)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -397,7 +397,7 @@ final class R2DBC {
|
||||
|
||||
@Override
|
||||
public final void onError(Throwable t) {
|
||||
downstream.subscriber.onError(translate(downstream.sql(), t));
|
||||
downstream.subscriber.onError(translate(downstream.configuration.dsl(), downstream.sql(), t));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -96,6 +96,7 @@ 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.exception.SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION;
|
||||
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;
|
||||
@ -3552,13 +3553,13 @@ final class Tools {
|
||||
/**
|
||||
* Translate a {@link R2dbcException} to a {@link DataAccessException}
|
||||
*/
|
||||
static final RuntimeException translate(String sql, Throwable t) {
|
||||
static final RuntimeException translate(Scope scope, String sql, Throwable t) {
|
||||
if (t instanceof R2dbcException e)
|
||||
return translate(sql, e);
|
||||
return translate(scope, sql, e);
|
||||
else if (t instanceof SQLException e)
|
||||
return translate(sql, e);
|
||||
return translate(scope, sql, e);
|
||||
else if (t instanceof RuntimeException e)
|
||||
return translate(sql, e);
|
||||
return translate(scope, sql, e);
|
||||
else if (t != null)
|
||||
return new DataAccessException("SQL [" + sql + "]; Unspecified Throwable", t);
|
||||
else
|
||||
@ -3568,9 +3569,9 @@ final class Tools {
|
||||
/**
|
||||
* Translate a {@link R2dbcException} to a {@link DataAccessException}
|
||||
*/
|
||||
static final DataAccessException translate(String sql, R2dbcException e) {
|
||||
static final DataAccessException translate(Scope scope, String sql, R2dbcException e) {
|
||||
if (e != null)
|
||||
return translate(sql, e, sqlStateClass(e));
|
||||
return translate(scope, sql, e, sqlStateClass(e));
|
||||
else
|
||||
return new DataAccessException("SQL [" + sql + "]; Unspecified R2dbcException");
|
||||
}
|
||||
@ -3578,28 +3579,39 @@ final class Tools {
|
||||
/**
|
||||
* Translate a {@link SQLException} to a {@link DataAccessException}
|
||||
*/
|
||||
static final DataAccessException translate(String sql, SQLException e) {
|
||||
static final DataAccessException translate(Scope scope, String sql, SQLException e) {
|
||||
if (e != null)
|
||||
return translate(sql, e, sqlStateClass(e));
|
||||
return translate(scope, sql, e, sqlStateClass(e));
|
||||
else
|
||||
return new DataAccessException("SQL [" + sql + "]; Unspecified SQLException");
|
||||
}
|
||||
|
||||
private static final DataAccessException translate(String sql, Exception e, SQLStateClass sqlState) {
|
||||
private static final DataAccessException translate(Scope scope, 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);
|
||||
case NONE:
|
||||
switch (scope.family()) {
|
||||
case DUCKDB: {
|
||||
String m = e.getMessage().toLowerCase();
|
||||
|
||||
if (m.contains("constraint violated: duplicate key"))
|
||||
return new IntegrityConstraintViolationException("SQL [" + sql + "]; " + e.getMessage(), e);
|
||||
else if (m.contains("constraint Error: not nullL constraint failed"));
|
||||
return new IntegrityConstraintViolationException("SQL [" + sql + "]; " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DataAccessException("SQL [" + sql + "]; " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a {@link RuntimeException} to a {@link DataAccessException}
|
||||
*/
|
||||
static final RuntimeException translate(String sql, RuntimeException e) {
|
||||
static final RuntimeException translate(Scope scope, String sql, RuntimeException e) {
|
||||
if (e != null)
|
||||
return e;
|
||||
else
|
||||
@ -5045,7 +5057,7 @@ final class Tools {
|
||||
|
||||
if (ctx.settings().getThrowExceptions() == THROW_NONE) {
|
||||
ctx.sqlException(e);
|
||||
results.resultsOrRows().add(new ResultOrRowsImpl(Tools.translate(ctx.sql(), e)));
|
||||
results.resultsOrRows().add(new ResultOrRowsImpl(Tools.translate(ctx, ctx.sql(), e)));
|
||||
}
|
||||
else {
|
||||
consumeExceptions(ctx.configuration(), ctx.statement(), e);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user