|
5 | 5 | package org.hibernate.exception.internal;
|
6 | 6 |
|
7 | 7 | import java.sql.SQLException;
|
8 |
| -import java.util.Set; |
9 | 8 |
|
10 | 9 | import org.hibernate.JDBCException;
|
11 | 10 | import org.hibernate.PessimisticLockException;
|
12 | 11 | import org.hibernate.QueryTimeoutException;
|
| 12 | +import org.hibernate.exception.AuthException; |
13 | 13 | import org.hibernate.exception.ConstraintViolationException;
|
14 | 14 | import org.hibernate.exception.DataException;
|
15 | 15 | import org.hibernate.exception.JDBCConnectionException;
|
16 | 16 | import org.hibernate.exception.LockAcquisitionException;
|
17 | 17 | import org.hibernate.exception.SQLGrammarException;
|
18 | 18 | import org.hibernate.exception.spi.AbstractSQLExceptionConversionDelegate;
|
19 | 19 | import org.hibernate.exception.spi.ConversionContext;
|
20 |
| -import org.hibernate.internal.util.JdbcExceptionHelper; |
21 | 20 |
|
22 | 21 | import org.checkerframework.checker.nullness.qual.Nullable;
|
23 | 22 |
|
| 23 | +import static org.hibernate.internal.util.JdbcExceptionHelper.determineSqlStateClassCode; |
| 24 | +import static org.hibernate.internal.util.JdbcExceptionHelper.extractErrorCode; |
| 25 | +import static org.hibernate.internal.util.JdbcExceptionHelper.extractSqlState; |
| 26 | + |
24 | 27 | /**
|
25 | 28 | * A {@link org.hibernate.exception.spi.SQLExceptionConverter} implementation which performs conversion based
|
26 | 29 | * on the underlying SQLState. Interpretation of a SQL error based on SQLState is not nearly as accurate as
|
27 | 30 | * using the ErrorCode (which is, however, vendor-specific).
|
28 |
| - * <p> |
29 |
| - * SQLState codes are defined by both ANSI SQL specs and X/Open. Some "classes" are shared, others are |
30 |
| - * specific to one or another, yet others are custom vendor classes. Unfortunately I have not been able to |
31 |
| - * find a "blessed" list of X/Open codes. These codes are cobbled together between ANSI SQL spec and error |
| 31 | + * |
| 32 | + * @implNote |
| 33 | + * SQLState codes are defined by both ANSI SQL specs and X/Open. Some "classes" are shared, others are |
| 34 | + * specific to one or another, yet others are custom vendor classes. Unfortunately I have not been able to |
| 35 | + * find a "blessed" list of X/Open codes. These codes are cobbled together between ANSI SQL spec and error |
32 | 36 | * code tables from few vendor's documentation.
|
33 | 37 | *
|
34 | 38 | * @author Steve Ebersole
|
35 | 39 | */
|
36 | 40 | public class SQLStateConversionDelegate extends AbstractSQLExceptionConversionDelegate {
|
37 | 41 |
|
38 |
| - private static final Set<String> SQL_GRAMMAR_CATEGORIES = buildGrammarCategories(); |
39 |
| - private static Set<String> buildGrammarCategories() { |
40 |
| - return Set.of( |
41 |
| - "07", // "dynamic SQL error" |
42 |
| - "20", |
43 |
| - "2A", // "direct SQL syntax error or access rule violation" |
44 |
| - "37", // "dynamic SQL syntax error or access rule violation" |
45 |
| - "42", // "syntax error or access rule violation" |
46 |
| - "65", // Oracle specific as far as I can tell |
47 |
| - "S0" // MySQL specific as far as I can tell |
48 |
| - ); |
49 |
| - } |
50 |
| - |
51 |
| - private static final Set<String> DATA_CATEGORIES = buildDataCategories(); |
52 |
| - private static Set<String> buildDataCategories() { |
53 |
| - return Set.of( |
54 |
| - "21", // "cardinality violation" |
55 |
| - "22" // "data exception" |
56 |
| - ); |
57 |
| - } |
58 |
| - |
59 |
| - private static final Set<String> INTEGRITY_VIOLATION_CATEGORIES = buildContraintCategories(); |
60 |
| - private static Set<String> buildContraintCategories() { |
61 |
| - return Set.of( |
62 |
| - "23", // "integrity constraint violation" |
63 |
| - "27", // "triggered data change violation" |
64 |
| - "44" // "with check option violation" |
65 |
| - ); |
66 |
| - } |
67 |
| - |
68 |
| - private static final Set<String> CONNECTION_CATEGORIES = buildConnectionCategories(); |
69 |
| - private static Set<String> buildConnectionCategories() { |
70 |
| - return Set.of( |
71 |
| - "08" // "connection exception" |
72 |
| - ); |
73 |
| - } |
74 |
| - |
75 | 42 | public SQLStateConversionDelegate(ConversionContext conversionContext) {
|
76 | 43 | super( conversionContext );
|
77 | 44 | }
|
78 | 45 |
|
79 | 46 | @Override
|
80 | 47 | public @Nullable JDBCException convert(SQLException sqlException, String message, String sql) {
|
81 |
| - final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); |
82 |
| - final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException ); |
83 |
| - |
| 48 | + final String sqlState = extractSqlState( sqlException ); |
84 | 49 | if ( sqlState != null ) {
|
85 |
| - String sqlStateClassCode = JdbcExceptionHelper.determineSqlStateClassCode( sqlState ); |
86 |
| - |
87 |
| - if ( sqlStateClassCode != null ) { |
88 |
| - if ( SQL_GRAMMAR_CATEGORIES.contains( sqlStateClassCode ) ) { |
| 50 | + switch ( sqlState ) { |
| 51 | + case "42501": |
| 52 | + return new AuthException( message, sqlException, sql ); |
| 53 | + case "40001": |
| 54 | + return new LockAcquisitionException( message, sqlException, sql ); |
| 55 | + case "40XL1", "40XL2": |
| 56 | + // Derby "A lock could not be obtained within the time requested." |
| 57 | + return new PessimisticLockException( message, sqlException, sql ); |
| 58 | + case "70100": |
| 59 | + // MySQL Query execution was interrupted |
| 60 | + return new QueryTimeoutException( message, sqlException, sql ); |
| 61 | + case "72000": |
| 62 | + if ( extractErrorCode( sqlException ) == 1013 ) { |
| 63 | + // Oracle user requested cancel of current operation |
| 64 | + return new QueryTimeoutException( message, sqlException, sql ); |
| 65 | + } |
| 66 | + } |
| 67 | + switch ( determineSqlStateClassCode( sqlState ) ) { |
| 68 | + case |
| 69 | + "07", // "dynamic SQL error" |
| 70 | + "20", |
| 71 | + "2A", // "direct SQL syntax error or access rule violation" |
| 72 | + "37", // "dynamic SQL syntax error or access rule violation" |
| 73 | + "42", // "syntax error or access rule violation" |
| 74 | + "65", // Oracle specific as far as I can tell |
| 75 | + "S0": // MySQL specific as far as I can tell |
89 | 76 | return new SQLGrammarException( message, sqlException, sql );
|
90 |
| - } |
91 |
| - else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) { |
| 77 | + case |
| 78 | + "23", // "integrity constraint violation" |
| 79 | + "27", // "triggered data change violation" |
| 80 | + "44": // "with check option violation" |
92 | 81 | final String constraintName = getConversionContext()
|
93 | 82 | .getViolatedConstraintNameExtractor()
|
94 | 83 | .extractConstraintName( sqlException );
|
95 | 84 | return new ConstraintViolationException( message, sqlException, sql, constraintName );
|
96 |
| - } |
97 |
| - else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) { |
| 85 | + case |
| 86 | + "08": // "connection exception" |
98 | 87 | return new JDBCConnectionException( message, sqlException, sql );
|
99 |
| - } |
100 |
| - else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) { |
| 88 | + case |
| 89 | + "21", // "cardinality violation" |
| 90 | + "22": // "data exception" |
101 | 91 | return new DataException( message, sqlException, sql );
|
102 |
| - } |
103 |
| - } |
104 |
| - |
105 |
| - if ( "40001".equals( sqlState ) ) { |
106 |
| - return new LockAcquisitionException( message, sqlException, sql ); |
107 |
| - } |
108 |
| - |
109 |
| - if ( "40XL1".equals( sqlState ) || "40XL2".equals( sqlState )) { |
110 |
| - // Derby "A lock could not be obtained within the time requested." |
111 |
| - return new PessimisticLockException( message, sqlException, sql ); |
112 |
| - } |
113 |
| - |
114 |
| - // MySQL Query execution was interrupted |
115 |
| - if ( "70100".equals( sqlState ) || |
116 |
| - // Oracle user requested cancel of current operation |
117 |
| - ( "72000".equals( sqlState ) && errorCode == 1013 ) ) { |
118 |
| - return new QueryTimeoutException( message, sqlException, sql ); |
| 92 | + case |
| 93 | + "28": // "authentication failure" |
| 94 | + return new AuthException( message, sqlException, sql ); |
119 | 95 | }
|
120 | 96 | }
|
121 |
| - |
122 | 97 | return null;
|
123 | 98 | }
|
124 | 99 | }
|
0 commit comments