|
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