From b44833b7c933de1b3a063a3cb8c805e841f921b8 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sat, 26 Oct 2024 12:51:06 +0200 Subject: [PATCH] HHH-18772 introduce AuthException and simplify SQLStateConversionDelegate Signed-off-by: Gavin King --- .../hibernate/exception/AuthException.java | 37 ++++++ .../hibernate/exception/DataException.java | 6 +- .../internal/SQLStateConversionDelegate.java | 123 +++++++----------- .../internal/util/JdbcExceptionHelper.java | 5 +- 4 files changed, 90 insertions(+), 81 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/exception/AuthException.java diff --git a/hibernate-core/src/main/java/org/hibernate/exception/AuthException.java b/hibernate-core/src/main/java/org/hibernate/exception/AuthException.java new file mode 100644 index 000000000000..64637bb7eea6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/exception/AuthException.java @@ -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 ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/exception/DataException.java b/hibernate-core/src/main/java/org/hibernate/exception/DataException.java index c77a9e8b2320..4b7a101798e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/DataException.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/DataException.java @@ -9,7 +9,7 @@ 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 @@ */ public class DataException extends JDBCException { /** - * Constructor for JDBCException. + * Constructor for DataException. * * @param root The underlying exception. */ @@ -26,7 +26,7 @@ public DataException(String message, SQLException root) { } /** - * Constructor for JDBCException. + * Constructor for DataException. * * @param message Optional message. * @param root The underlying exception. diff --git a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java index ee52df5fbea1..97afadfcab03 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java @@ -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,108 +17,83 @@ 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). - *

- * 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 + * + * @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 * code tables from few vendor's documentation. * * @author Steve Ebersole */ public class SQLStateConversionDelegate extends AbstractSQLExceptionConversionDelegate { - private static final Set SQL_GRAMMAR_CATEGORIES = buildGrammarCategories(); - private static Set 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 DATA_CATEGORIES = buildDataCategories(); - private static Set buildDataCategories() { - return Set.of( - "21", // "cardinality violation" - "22" // "data exception" - ); - } - - private static final Set INTEGRITY_VIOLATION_CATEGORIES = buildContraintCategories(); - private static Set buildContraintCategories() { - return Set.of( - "23", // "integrity constraint violation" - "27", // "triggered data change violation" - "44" // "with check option violation" - ); - } - - private static final Set CONNECTION_CATEGORIES = buildConnectionCategories(); - private static Set 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 ) ) { + 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 ); + } + } + 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 ); - } - else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) { + 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 ); - } - } - - 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 ); + case + "28": // "authentication failure" + return new AuthException( message, sqlException, sql ); } } - return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/JdbcExceptionHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/JdbcExceptionHelper.java index f02744f6013a..fba9a3d0872d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/JdbcExceptionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/JdbcExceptionHelper.java @@ -56,9 +56,6 @@ public static String extractSqlStateClassCode(SQLException sqlException) { } 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 ); } }