HHH-18772 introduce AuthException and simplify SQLStateConversionDelegate
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
55255e9d4a
commit
b44833b7c9
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.exception;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* A {@link JDBCException} indicating an authentication or authorization failure.
|
||||
*
|
||||
* @since 7.0
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class AuthException extends JDBCException {
|
||||
/**
|
||||
* Constructor for AuthException.
|
||||
*
|
||||
* @param root The underlying exception.
|
||||
*/
|
||||
public AuthException(String message, SQLException root) {
|
||||
super( message, root );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for AuthException.
|
||||
*
|
||||
* @param message Optional message.
|
||||
* @param root The underlying exception.
|
||||
*/
|
||||
public AuthException(String message, SQLException root, String sql) {
|
||||
super( message, root, sql );
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import java.sql.SQLException;
|
|||
import org.hibernate.JDBCException;
|
||||
|
||||
/**
|
||||
* Extends {@link JDBCException} indicating that evaluation of the
|
||||
* A {@link JDBCException} indicating that evaluation of the
|
||||
* valid SQL statement against the given data resulted in some
|
||||
* illegal operation, mismatched types or incorrect cardinality.
|
||||
*
|
||||
|
@ -17,7 +17,7 @@ import org.hibernate.JDBCException;
|
|||
*/
|
||||
public class DataException extends JDBCException {
|
||||
/**
|
||||
* Constructor for JDBCException.
|
||||
* Constructor for DataException.
|
||||
*
|
||||
* @param root The underlying exception.
|
||||
*/
|
||||
|
@ -26,7 +26,7 @@ public class DataException extends JDBCException {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructor for JDBCException.
|
||||
* Constructor for DataException.
|
||||
*
|
||||
* @param message Optional message.
|
||||
* @param root The underlying exception.
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
package org.hibernate.exception.internal;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.QueryTimeoutException;
|
||||
import org.hibernate.exception.AuthException;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.DataException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
|
@ -17,15 +17,19 @@ import org.hibernate.exception.LockAcquisitionException;
|
|||
import org.hibernate.exception.SQLGrammarException;
|
||||
import org.hibernate.exception.spi.AbstractSQLExceptionConversionDelegate;
|
||||
import org.hibernate.exception.spi.ConversionContext;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.internal.util.JdbcExceptionHelper.determineSqlStateClassCode;
|
||||
import static org.hibernate.internal.util.JdbcExceptionHelper.extractErrorCode;
|
||||
import static org.hibernate.internal.util.JdbcExceptionHelper.extractSqlState;
|
||||
|
||||
/**
|
||||
* A {@link org.hibernate.exception.spi.SQLExceptionConverter} implementation which performs conversion based
|
||||
* on the underlying SQLState. Interpretation of a SQL error based on SQLState is not nearly as accurate as
|
||||
* using the ErrorCode (which is, however, vendor-specific).
|
||||
* <p>
|
||||
*
|
||||
* @implNote
|
||||
* SQLState codes are defined by both ANSI SQL specs and X/Open. Some "classes" are shared, others are
|
||||
* specific to one or another, yet others are custom vendor classes. Unfortunately I have not been able to
|
||||
* find a "blessed" list of X/Open codes. These codes are cobbled together between ANSI SQL spec and error
|
||||
|
@ -35,90 +39,61 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
*/
|
||||
public class SQLStateConversionDelegate extends AbstractSQLExceptionConversionDelegate {
|
||||
|
||||
private static final Set<String> SQL_GRAMMAR_CATEGORIES = buildGrammarCategories();
|
||||
private static Set<String> buildGrammarCategories() {
|
||||
return Set.of(
|
||||
"07", // "dynamic SQL error"
|
||||
"20",
|
||||
"2A", // "direct SQL syntax error or access rule violation"
|
||||
"37", // "dynamic SQL syntax error or access rule violation"
|
||||
"42", // "syntax error or access rule violation"
|
||||
"65", // Oracle specific as far as I can tell
|
||||
"S0" // MySQL specific as far as I can tell
|
||||
);
|
||||
}
|
||||
|
||||
private static final Set<String> DATA_CATEGORIES = buildDataCategories();
|
||||
private static Set<String> buildDataCategories() {
|
||||
return Set.of(
|
||||
"21", // "cardinality violation"
|
||||
"22" // "data exception"
|
||||
);
|
||||
}
|
||||
|
||||
private static final Set<String> INTEGRITY_VIOLATION_CATEGORIES = buildContraintCategories();
|
||||
private static Set<String> buildContraintCategories() {
|
||||
return Set.of(
|
||||
"23", // "integrity constraint violation"
|
||||
"27", // "triggered data change violation"
|
||||
"44" // "with check option violation"
|
||||
);
|
||||
}
|
||||
|
||||
private static final Set<String> CONNECTION_CATEGORIES = buildConnectionCategories();
|
||||
private static Set<String> buildConnectionCategories() {
|
||||
return Set.of(
|
||||
"08" // "connection exception"
|
||||
);
|
||||
}
|
||||
|
||||
public SQLStateConversionDelegate(ConversionContext conversionContext) {
|
||||
super( conversionContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable JDBCException convert(SQLException sqlException, String message, String sql) {
|
||||
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
|
||||
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
|
||||
|
||||
final String sqlState = extractSqlState( sqlException );
|
||||
if ( sqlState != null ) {
|
||||
String sqlStateClassCode = JdbcExceptionHelper.determineSqlStateClassCode( sqlState );
|
||||
|
||||
if ( sqlStateClassCode != null ) {
|
||||
if ( SQL_GRAMMAR_CATEGORIES.contains( sqlStateClassCode ) ) {
|
||||
return new SQLGrammarException( message, sqlException, sql );
|
||||
switch ( sqlState ) {
|
||||
case "42501":
|
||||
return new AuthException( message, sqlException, sql );
|
||||
case "40001":
|
||||
return new LockAcquisitionException( message, sqlException, sql );
|
||||
case "40XL1", "40XL2":
|
||||
// Derby "A lock could not be obtained within the time requested."
|
||||
return new PessimisticLockException( message, sqlException, sql );
|
||||
case "70100":
|
||||
// MySQL Query execution was interrupted
|
||||
return new QueryTimeoutException( message, sqlException, sql );
|
||||
case "72000":
|
||||
if ( extractErrorCode( sqlException ) == 1013 ) {
|
||||
// Oracle user requested cancel of current operation
|
||||
return new QueryTimeoutException( message, sqlException, sql );
|
||||
}
|
||||
else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) {
|
||||
}
|
||||
switch ( determineSqlStateClassCode( sqlState ) ) {
|
||||
case
|
||||
"07", // "dynamic SQL error"
|
||||
"20",
|
||||
"2A", // "direct SQL syntax error or access rule violation"
|
||||
"37", // "dynamic SQL syntax error or access rule violation"
|
||||
"42", // "syntax error or access rule violation"
|
||||
"65", // Oracle specific as far as I can tell
|
||||
"S0": // MySQL specific as far as I can tell
|
||||
return new SQLGrammarException( message, sqlException, sql );
|
||||
case
|
||||
"23", // "integrity constraint violation"
|
||||
"27", // "triggered data change violation"
|
||||
"44": // "with check option violation"
|
||||
final String constraintName = getConversionContext()
|
||||
.getViolatedConstraintNameExtractor()
|
||||
.extractConstraintName( sqlException );
|
||||
return new ConstraintViolationException( message, sqlException, sql, constraintName );
|
||||
}
|
||||
else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) {
|
||||
case
|
||||
"08": // "connection exception"
|
||||
return new JDBCConnectionException( message, sqlException, sql );
|
||||
}
|
||||
else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) {
|
||||
case
|
||||
"21", // "cardinality violation"
|
||||
"22": // "data exception"
|
||||
return new DataException( message, sqlException, sql );
|
||||
case
|
||||
"28": // "authentication failure"
|
||||
return new AuthException( message, sqlException, sql );
|
||||
}
|
||||
}
|
||||
|
||||
if ( "40001".equals( sqlState ) ) {
|
||||
return new LockAcquisitionException( message, sqlException, sql );
|
||||
}
|
||||
|
||||
if ( "40XL1".equals( sqlState ) || "40XL2".equals( sqlState )) {
|
||||
// Derby "A lock could not be obtained within the time requested."
|
||||
return new PessimisticLockException( message, sqlException, sql );
|
||||
}
|
||||
|
||||
// MySQL Query execution was interrupted
|
||||
if ( "70100".equals( sqlState ) ||
|
||||
// Oracle user requested cancel of current operation
|
||||
( "72000".equals( sqlState ) && errorCode == 1013 ) ) {
|
||||
return new QueryTimeoutException( message, sqlException, sql );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,9 +56,6 @@ public final class JdbcExceptionHelper {
|
|||
}
|
||||
|
||||
public static String determineSqlStateClassCode(String sqlState) {
|
||||
if ( sqlState == null || sqlState.length() < 2 ) {
|
||||
return sqlState;
|
||||
}
|
||||
return sqlState.substring( 0, 2 );
|
||||
return sqlState == null || sqlState.length() < 2 ? sqlState : sqlState.substring( 0, 2 );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue