1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.exception;
26
27 import org.hibernate.JDBCException;
28
29 import java.sql.SQLException;
30 import java.util.HashSet;
31 import java.util.Set;
32
33 /**
34 * A SQLExceptionConverter implementation which performs converion based on
35 * the underlying SQLState. Interpretation of a SQL error based on SQLState
36 * is not nearly as accurate as using the ErrorCode (which is, however, vendor-
37 * specific). Use of a ErrorCode-based converter should be preferred approach
38 * for converting/interpreting SQLExceptions.
39 *
40 * @author Steve Ebersole
41 */
42 public class SQLStateConverter implements SQLExceptionConverter {
43
44 private ViolatedConstraintNameExtracter extracter;
45
46 private static final Set SQL_GRAMMAR_CATEGORIES = new HashSet();
47 private static final Set DATA_CATEGORIES = new HashSet();
48 private static final Set INTEGRITY_VIOLATION_CATEGORIES = new HashSet();
49 private static final Set CONNECTION_CATEGORIES = new HashSet();
50
51 static {
52 SQL_GRAMMAR_CATEGORIES.add( "07" );
53 SQL_GRAMMAR_CATEGORIES.add( "37" );
54 SQL_GRAMMAR_CATEGORIES.add( "42" );
55 SQL_GRAMMAR_CATEGORIES.add( "65" );
56 SQL_GRAMMAR_CATEGORIES.add( "S0" );
57 SQL_GRAMMAR_CATEGORIES.add( "20" );
58
59 DATA_CATEGORIES.add("22");
60 DATA_CATEGORIES.add("21");
61 DATA_CATEGORIES.add("02");
62
63 INTEGRITY_VIOLATION_CATEGORIES.add( "23" );
64 INTEGRITY_VIOLATION_CATEGORIES.add( "27" );
65 INTEGRITY_VIOLATION_CATEGORIES.add( "44" );
66
67 CONNECTION_CATEGORIES.add( "08" );
68 }
69
70 public SQLStateConverter(ViolatedConstraintNameExtracter extracter) {
71 this.extracter = extracter;
72 }
73
74 /**
75 * Convert the given SQLException into Hibernate's JDBCException hierarchy.
76 *
77 * @param sqlException The SQLException to be converted.
78 * @param message An optional error message.
79 * @param sql Optionally, the sql being performed when the exception occurred.
80 * @return The resulting JDBCException.
81 */
82 public JDBCException convert(SQLException sqlException, String message, String sql) {
83 String sqlState = JDBCExceptionHelper.extractSqlState( sqlException );
84
85 if ( sqlState != null ) {
86 String sqlStateClassCode = JDBCExceptionHelper.determineSqlStateClassCode( sqlState );
87
88 if ( sqlStateClassCode != null ) {
89 if ( SQL_GRAMMAR_CATEGORIES.contains( sqlStateClassCode ) ) {
90 return new SQLGrammarException( message, sqlException, sql );
91 }
92 else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) {
93 String constraintName = extracter.extractConstraintName( sqlException );
94 return new ConstraintViolationException( message, sqlException, sql, constraintName );
95 }
96 else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) {
97 return new JDBCConnectionException( message, sqlException, sql );
98 }
99 else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) {
100 return new DataException( message, sqlException, sql );
101 }
102 }
103
104 if ( "40001".equals( sqlState ) ) {
105 return new LockAcquisitionException( message, sqlException, sql );
106 }
107
108 if ( "61000".equals( sqlState ) ) {
109 // oracle sql-state code for deadlock
110 return new LockAcquisitionException( message, sqlException, sql );
111 }
112 }
113
114 return handledNonSpecificException( sqlException, message, sql );
115 }
116
117 /**
118 * Handle an exception not converted to a specific type based on the SQLState.
119 *
120 * @param sqlException The exception to be handled.
121 * @param message An optional message
122 * @param sql Optionally, the sql being performed when the exception occurred.
123 * @return The converted exception; should <b>never</b> be null.
124 */
125 protected JDBCException handledNonSpecificException(SQLException sqlException, String message, String sql) {
126 return new GenericJDBCException( message, sqlException, sql );
127 }
128 }